Страницы

Поиск по вопросам

Показаны сообщения с ярлыком аннотации. Показать все сообщения
Показаны сообщения с ярлыком аннотации. Показать все сообщения

понедельник, 30 марта 2020 г.

Что значит аннотация @HotSpotIntrinsicCandidate?

#java #jvm #аннотации


Смотрел JVM, наткнулся на аннотацию @HotSpotIntrinsicCandidate, довольно часто ее
стал встречать. Что она значит? Раньше ее не было.
    


Ответы

Ответ 1



Начал искать дальше, вот что нашел в комментариях к аннотации(оказывается, и такие есть). The {@code @HotSpotIntrinsicCandidate} annotation is specific to the HotSpot Virtual Machine. It indicates that an annotated method may be (but is not guaranteed to be) intrinsified by the HotSpot VM. A method is intrinsified if the HotSpot VM replaces the annotated method with hand-written assembly and/or hand-written compiler IR -- a compiler intrinsic -- to improve performance. The {@code @HotSpotIntrinsicCandidate} annotation is internal to the Java libraries and is therefore not supposed to have any relevance for application code. Persons not directly involved with maintaining the Java libraries or the HotSpot VM can safely ignore the fact that a method is annotated with {@code @HotSpotIntrinsicCandidate}. Примерный перевод: Аннотация {@code @HotSpotIntrinsicCandidate} предназначена для HotSpot Virtual Machine. Это означает, что аннотированный метод может быть (но не гарантированно), встроен в HotSpot VM. Метод встроен, если HotSpot VM заменяет аннотированный рукописной сборкой и/или рукописным компилятором IR - встроенным компилятором - для повышения производительности. {@Code @HotSpotIntrinsicCandidate}аннотация является внутренней для Java библиотеки и поэтому не должна иметь никакого отношения к коду приложения. Лица, не имеющие непосредственного отношения к поддержке библиотек Java или HotSpot VM могут смело игнорировать тот факт, что метод аннотирован {@code @HotSpotIntrinsicCandidate}.

воскресенье, 8 марта 2020 г.

Правила удержания аннотаций. SOURCE, CLASS, RUNTIME

#java #аннотации


Что обозначают правила SOURCE, CLASS и RUNTIME, инкапсулированные в перечисление
java.lang.annotation.RetentionPolicy?
    


Ответы

Ответ 1



Рассмотрим вопрос на примере аннотации @Override, которая указывает на переопределение метода. Так выглядит @Override в своей реализации @Retention(RetentionPolicy.SOURCE) public @interface Override { } SOURCE в данном случае указывает на то, что аннотация @Override (как и другая, к которой это правило будет применимо) будет "отброшена" во время компиляции. CLASS - как другое правило, указывает, что аннотация, к которой оно будет применимо, сохранится в файле с расширением .class во время компиляции, но не будет доступна для виртуальной машины JVM во время выполнения. RUNTIME - как другое правило, указывает, что аннотация, к которой оно будет применимо, сохранится в файле с расширением .class во время компиляции, и будет доступна для виртуальной машины JVM во время выполнения.

понедельник, 24 февраля 2020 г.

Как запретить сериализовать некоторые поля в JSON?

#java #json #spring #jackson #аннотации


Обращаюсь к контроллеру, который должен вернуть список объектов. Объекты преобразуются
в JSON строку. При преобразовании объектов в JSON строку вызываются все геттеры объектов.
И в результате возвращаются все данные объекта. Как запретить возврат некоторых полей
объекта, может есть специальная аннотация?

@Controller
@MessageMapping("/v1.0")
public class MyController {

    @MessageMapping("/getList")
    @SendTo("/topic/List")
    public Collection getList() throws Exception {
        return this.MyObjService.getList();
    }

}


Собственно класс будущих объектов:

public class MyObj {
    private String name;
    private String login;

    public String getName() {
       return name;
    }

    public String getLogin() {
       return login;
    }

}


Хотелось бы запретить возврат поля login.
    


Ответы

Ответ 1



Как заметил @ArtemKonovalov по-умолчанию Spring использует в качестве JSON Mapper-а библиотеку Jackson. Она предлагает использовать аннотацию @JsonIgnore. Но рано или поздно вы захотите с одного объекта получить два разных JSON, отличающихся набором полей. Поэтому, по-хорошему нужно сделать отдельные DTO без логики, которые вы будете целиком сериализовать в JSON. PS. Кроме того, рекомендую взять за правило всегда явно вешать на поля аннотацию @JsonProperty и явно указывать в ней имя поля. Иначе случайный рефакторинг с переименованием поля поломает ваш API.

среда, 5 февраля 2020 г.

Java аннотации - реализация бизнес логики

#java #аннотации


Хочу написать свои аннотации, так как возникло несколько идей, но не могу понять
как это сделать. Вроде легко, но вопрос: как к аннотации прикрепить бизнес логику?
Что я могу сделать с теми  данными которые мне пришли в аннотации. пример: @Annotation(SomeValue.VALUE).
И как мне взять это велью с сделать с ним какую-то бизнес логику? Например засунуть
в какой-то метод из другой библиотеки прокрутить его и вернуть значения.. 
    


Ответы

Ответ 1



Для использования своей аннотации нужно: Реализовать аннотацию (public @interface MyAnnotationExample c типом аннотации ElementType - например: класс/метод/конструктор/поле и т.п.). Использовать эту аннотацию MyAnnotationExample в вашем коде (в соответствии с типом ElementType аннотации MyAnnotationExample), т.е. добавить аннотацию к классу/методу/полю/и т.п. Реализовать обработчик этой аннотации через рефлексию. Пример #1. Аннотация на класс и чтение аннотации класса через рефлексию. Создадим аннотацию MyAnnotationExampleForClass: import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(value = ElementType.TYPE) //указание что данная аннотация вешается на класс @Retention(value = RetentionPolicy.RUNTIME) //аннотация доступна в процессе работы модуля public @interface MyAnnotationExampleForClass { String name() default "default name"; //в name() мы будем хранить значения аннотации } Создадим класс MyClassExample с использованием аннотации MyAnnotationExampleForClass: @MyAnnotationExampleForClass(name = "this is my annotation value!!!") public class MyClassExample { ... } Создадим класс MyAnnotationProcessorExample для получения значений аннотаций: class MyAnnotationProcessorExample { MyClassExample myClass = new MyClassExample(); //получаем нашу аннотацию из нашего объекта MyAnnotationExampleForClass a = myClass.getClass().getAnnotation(MyAnnotationExampleForClass.class); System.out.println("выводим значение аннотации = " + a.name()); System.out.println("печатаем тип аннотации со значением = " + a.toString()); } Пример #2. Аннотация на метод класса и чтение аннотации метода через рефлексию. Добавим еще аннотацию MyAnnotationExampleForMethod для метода: @Target(value = ElementType.METHOD) @Retention(value = RetentionPolicy.RUNTIME) public @interface MyAnnotationExampleForMethod { String name() default "default name 2"; } Добавим в наш класс MyClassExample (из примера #1) новый метод runForest(): @MyAnnotationExampleForClass(name = "this is my annotation value!!!") public class MyClassExample { @MyAnnotationExampleForMethod(name = "this is my method-annotation value") public void runForest() { System.out.println("Our Forest run very good!"); } } Создадим класс MyAnnotationProcessorExample2 для получения значений аннотаций: class MyAnnotationProcessorExample2 { MyClassExample myClass = new MyClassExample(); //получаем наш метод из нашего объекта Method m = tm.getClass().getMethod("runForest"); //получаем аннотацию из нашего метода MyAnnotationExampleForMethod a = m.getAnnotation(TimeAnnotationMethod.class); System.out.println("выводим значение аннотации = " + a.name()); System.out.println("печатаем тип аннотации со значением = " + a.toString()); } Теперь можно эти классы-обработчики MyAnnotationProcessorExample и MyAnnotationProcessorExample2 использовать в нужных местах для обработки бизнес-логики. Примеры привел самые примитивные, только для общего понимания. Для более полноценных реализаций нужно разбираться с понятием java reflection. Также рекомендую посмотреть темы: В каких случаях на практике применять рефлексию, аннотации? Зачем создавать собственные аннотации? Аннотация в Java EE

воскресенье, 2 февраля 2020 г.

Аннотация в Java EE

#java #java_ee #аннотации


Всем привет. Хотел узнать у знающих, что такое аннотации, и зачем они нужны. 
До того как начал изучать Java EE у меня было представление, что я знаю, что это
такое. Но как дошел до Java EE, увидел, что они применяются везде особенно в JAX-RS
и при написании веб сервисов. 

Зашел в документацию прочитать про @Context и посмотреть что там внутри. Вот то,
что увидел, если кто сможет объяснить синтаксис и саму логику данного кода буду признателен.
Если есть ссылки на объяснение буду рад почитать.   

 @Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 public @interface Context {
 }

    


Ответы

Ответ 1



Это просто объявление аннотации без какой-либо логики. Как объявить аннотацию, рассказывается в любом учебнике по Java. По-порядку: @Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD}) Аннотация @Target, объявляет элементы исходного кода, к которым можно применить создаваемую аннотацию. В данном случае это: параметры методов (ElementType.PARAMETER), сами методы (ElementType.METHOD) и поля классов (ElementType.FIELD). @Retention(RetentionPolicy.RUNTIME) Аннотация @Retention, говорит компилятору, как долго нужно хранить аннотацию в коде. Политика RetentionPolicy.RUNTIME заставляет компилятор сохранить аннотации в .class-файлах и делает их доступными во время выполнения программы через рефлексию. @Documented Аннотация @Documented включает создаваемую аннотацию в список элементов исходного кода, для которых генерируется документация (при использовании инструментов генерации документации). public @interface Context { } Это, собственно, непосредственно объявление новой аннотации @Context. Сами по себе аннотации - просто маркеры, никакой работы они не выполняют. Что касается логики ("магии") аннотаций то обычно это работает так: есть какой-то класс, отвечающий за инициализацию, он пробегает при помощи рефлексии по классам в определенном пакете и ищет какую-то аннотацию. Если находит - экземпляры этого класса подвергаются какой-либо обработке, например полям классов задаются некоторые значения. В случае с JAX-RS "магией" занимается поставщик реализации (напр. CXF, Jersey, RESTEasy). Где-то в его недрах есть класс, который анализирует аннотации, которыми вы украсили ваши ресурсы и выполняет действия в соответствии со спецификацией JAX-RS. Например, составляет карту соответствий URL-ов конкретным методам, на основе аннотаций @Path и @GET/@PUT/@POST/@DELETE.

Ответ 2



Пример на основе этой статьи: 1) Создаем новый класс-аннотацию: @Target(value= ElementType.TYPE) @Retention(value= RetentionPolicy.RUNTIME) public @interface ControlledObject { String name(); } 2) Используем эту аннотацию, т.е. аннотируем класс: @ControlledObject(name="biscuits") public class Cookies { ... } 3) Как работает аннотация: где-то в коде мы проверяем, аннотирован ли наш класс Cookies этой аннотацией, ControlledObject. Если да, то выполняются одни действия, если нет - другие: Class cl = Class.forName("Cookies"); if(!cl.isAnnotationPresent(ControlledObject.class)){ ... } else { ... }

понедельник, 6 января 2020 г.

Переопределяются ли аннотации в предках классов?

#java #аннотации


Добрый день.

Если используем аннотации, к примеру, для класса.
У нас есть некий абстрактный класс А. У него есть предок, класс B. 
И там и там есть аннотация @MyAnnotation. В аннотации есть поле

String[] value() default {};


В итоге получили примерно такое:

@MyAnnotation({"str1","str2"})
abstract class A {}

@MyAnnotation({"str3","str4"})
class B extends A {}


Вопрос: Будут ли суммироваться все значения из класса и суперкласса, или просто возьмется
значение из текущего объекта B. Либо, может, еще какие хитрости есть в аннотациях?
    


Ответы

Ответ 1



Наследование аннотаций возможно при использовании аннотации @Inherited. В вашем случае произойдет просто перекрытие. Аннотации @Inherited @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface InheritedAnnotation { String name(); } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface UninheritedAnnotation { String name(); } Тестовые классы @InheritedAnnotation(name = "A1") public class A1 {} @InheritedAnnotation(name = "B1") public class B1 extends A1 {} public class C1 extends A1 {} @UninheritedAnnotation(name = "A2") public class A2 {} @UninheritedAnnotation(name = "B2") public class B2 extends A2 {} public class C2 extends A2 {} Тест @Test public void test() throws Exception { System.out.println(new A1().getClass().getAnnotation(InheritedAnnotation.class)); System.out.println(new B1().getClass().getAnnotation(InheritedAnnotation.class)); System.out.println(new C1().getClass().getAnnotation(InheritedAnnotation.class)); System.out.println(new A2().getClass().getAnnotation(UninheritedAnnotation.class)); System.out.println(new B2().getClass().getAnnotation(UninheritedAnnotation.class)); System.out.println(new C2().getClass().getAnnotation(UninheritedAnnotation.class)); } Вывод //@org.example.InheritedAnnotation(name=A1) //@org.example.InheritedAnnotation(name=B1) //@org.example.InheritedAnnotation(name=A1) //@org.example.UninheritedAnnotation(name=A2) //@org.example.UninheritedAnnotation(name=B2) //null

пятница, 27 декабря 2019 г.

Как корректно использование дженерики в данном примере?

#java #generics #рефлексия #аннотации #okhttp


Есть задача А, B и С. И по сути дела возможно я не корректным методом решаю задачи
A и B, но задача C следующая.
Есть интерфейс содержащий методы и аннотации: 

public interface ApiService {

    @POST("/api/v1/smart/status")
    Call postWorkChangeStatus(@Body WorkChangeStatusRequestData
sessionStatusData);

    @POST("/api/v1/smart/sensor")
    Call postWorkSensorData(@Body SensorRequestData sensorData);

    @GET("/api/v1/smart/sensor")
    @FormUrlEncoded
    Call getWorkSensorData(@Field("number") String id);
}


Я хочу получить Map> в которой в качестве ключа будет выступать
путь (значение аннотации, например "/api/v1/smart/sensor") и в качестве значения имя
аннотации (если вы знакомы с okhttp то вы их встречали). То есть должны получить в
данном случае {"/api/v1/smart/sensor":["POST", "GET"], ...}

Получаю эти данные с помощью рефлексии следующим способом: 

    void parse() {
       methods = clazz.getMethods();
        for (int i = 0; i < methods.length; i++) {
                if (methods[i].isAnnotationPresent(POST.class))
                    annotationValues.put(methods[i].getAnnotation(POST.class).value(),
new ArrayList());
                else if (methods[i].isAnnotationPresent(GET.class))
                    annotationValues.put(methods[i].getAnnotation(GET.class).value(),
new ArrayList());
                else if (methods[i].isAnnotationPresent(DELETE.class))
                    annotationValues.put(methods[i].getAnnotation(DELETE.class).value(),
new ArrayList());
                else if (methods[i].isAnnotationPresent(PUT.class))
                    annotationValues.put(methods[i].getAnnotation(PUT.class).value(),
new ArrayList());
                else if (methods[i].isAnnotationPresent(HEAD.class))
                    annotationValues.put(methods[i].getAnnotation(HEAD.class).value(),
new ArrayList());
                else if (methods[i].isAnnotationPresent(OPTIONS.class))
                    annotationValues.put(methods[i].getAnnotation(OPTIONS.class).value(),
new ArrayList());
            }
    for (int i = 0; i < methods.length; i++) {
            if (methods[i].isAnnotationPresent(POST.class)) {
//                parse(methods[i], POST.class);
                String path = methods[i].getAnnotation(POST.class).value();
                annotationValues.get(path).add(POST.class.getSimpleName());
            } else if (methods[i].isAnnotationPresent(GET.class)) {
                String path = methods[i].getAnnotation(GET.class).value();
                annotationValues.get(path).add(GET.class.getSimpleName());
            } else if (methods[i].isAnnotationPresent(DELETE.class)) {
                String path = methods[i].getAnnotation(DELETE.class).value();
                annotationValues.get(path).add(DELETE.class.getSimpleName());
            } else if (methods[i].isAnnotationPresent(PUT.class)) {
                String path = methods[i].getAnnotation(PUT.class).value();
                annotationValues.get(path).add(PUT.class.getSimpleName());
            } else if (methods[i].isAnnotationPresent(HEAD.class)) {
                String path = methods[i].getAnnotation(HEAD.class).value();
                annotationValues.get(path).add(HEAD.class.getSimpleName());
            } else if (methods[i].isAnnotationPresent(OPTIONS.class)) {
                String path = methods[i].getAnnotation(OPTIONS.class).value();
                annotationValues.get(path).add(OPTIONS.class.getSimpleName());
            }
        }
    }


Выглядит не очень красиво. Решил написать следующий метод, который принимает метод
и класс подозреваемой аннотации:

private  void parse(Method method, Class postClass) {
        String test = ((T)method.getAnnotation(postClass)).value(); //ошибка!
        Log.d(logTag, "========TESTVALUE: " + test);
    }


Но возникает ошибка компиляции, которая вполне оправдана, так как заранее не известно,
будет ли у класса Т, наследника Annotation метод value().
У аннотаций okhttp общего предка не нашел. 

Возможно ли каким либо образом написать подобный метод или решить данную задачу элегантнее?
    


Ответы

Ответ 1



Первое что бросается в глаза это methods[i].isAnnotationPresent. Самое оптимальное из метода получать array задекларированных аннотаций method.getDeclaredAnnotations(). А так как array содержит объекты, то мы можем получить их SimpleName: annotation.annotationType().getSimpleName() и далее благополучно заворачиваем в switch Второе - дублированный код наполнения мапки. На мой взгляд это проще вынести в отдельный метод со всеми сопутствующими проверками. Третье - использовать паттерн dependency injection. parse принимает на вход любое количество объектов и далее они анализируются. Так же можно сделать еще один метод который будет принимать на вход array методов и валидировать/фильтровать их. Грубо говоря разделить код на логические части (методы) и передавать уже в них объекты. Результат выполнения ниже приведенного кода Result: {/api/v1/smart/status=[GET, POST]} public class Main { private static Map> map = new HashMap<>(); public static void main(String[] asd) throws InstantiationException, IllegalAccessException { parse(new Main(), new Integer("1")); System.out.println("Result: " + map); } private static void parse(Object... objects) { for (Object o : objects) { for (Method method : o.getClass().getDeclaredMethods()) { for (Annotation annotation : method.getDeclaredAnnotations()) { switch (annotation.annotationType().getSimpleName()) { case "POST": addToMap(((POST) annotation).value(), "POST"); break; case "GET": addToMap(((GET) annotation).value(), "GET"); break; case "DELETE": case "PUT": case "HEAD": case "OPTIONS": } } } } } private static void addToMap(String path, String httpMethod) { if (path != null) { List list = map.get(path); if (list == null) { list = new ArrayList<>(); } list.add(httpMethod); map.put(path, list); } } @GET("/api/v1/smart/status") private void fooMeethod() {} @POST(value = "/api/v1/smart/status") private void barMeethod() {} @Retention(RUNTIME) @Target({METHOD}) private @interface GET { String value(); } @Retention(RUNTIME) @Target({METHOD}) private @interface POST { String value(); } } Надеюсь помог.

вторник, 24 декабря 2019 г.

Примеры записи аннотаций @OneToMany @OneToOne @ManyToMany @ManyToOne [Hibernate]

#hibernate #jpa #аннотации


Интересуют как создавать сущности с аннотациями:  


@OneToOne  
@OneToMany   
@ManyToOne  
@ManyToMany


Так же вариации с bidirectional и unidirectional

Так же было бы неплохо добавить объяснений типо Cascade.**
    


Ответы

Ответ 1



Данный ответ будет модифицироваться по мере получения нужных знаний Update 11.09.2019: Вместо List<> используйте где возможно Set<> ...иначе при работе с join fetch (кастомном hql-запросе) у вас будет выпадать ошибка: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple Bags: Более подробно об ошибке написано тут Не используйте CascadeType.ALL Если кратко - лучше использовать только с @OneToOne, т.к. при использовании со множественными связями могут удалиться ненужные записи из бд. Данный момент подробно описан в данном источнике Все ниже приведенные примеры я подробно показываю в своем мини-проекте, который можно скачать с GitHub О каскадировании можно почитать тут Project Lombok В моих ответах я использую аннотации Project Lombok: - @Data - Аннотация, которая добавляет в ваш проект Getters/Setters, Equals, ToString, HashCode - @AllArgsConstructor - Конструктор, содержащий все глобальные переменные, записанные в данном классе - @NoArgsConstructor - Пустой конструктор. Если мы не хотим в самом конструкторе прописывать данные, а использовать Setter - @ToString(exclude - "НазваниеПеременной") - При работе с bidirectional у нас будет зацикливаться объекты. Чтобы этого не допустить - надо от них избавиться Другие аннотации Project Lombok Установка плагина Project Lombok в IntelliJ и Eclipse @OneToOne Вариант unidirectional: От Пользователя к Покупателю, но не от Покупателя к Пользователю User.java: @Data @AllArgsConstructor @NoArgsConstructor @Entity @Table(name = "users") public class User { @Id @GeneratedValue private long id; @Column private String username; //Some code @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) @JoinColumn(name = "customer_id", unique = true) private Customer customer; } Customer.java @Data @Builder @AllArgsConstructor @NoArgsConstructor @Entity @Table(name = "customer") public class Customer { @Id @GeneratedValue @Column(name = "country_id") private long id; //Some code @Column(name = "customer_name") private String customerName; } Вариант bidirectional: От Пользователя к Покупателю и от Покупателя к Пользователю @OneToMany Вариант unidirectional: У Поста есть несколько Комментариев, но нам не нужно от Комментария искать Пост Post.java: @Data @AllArgsConstructor @NoArgsConstructor @Entity @Table(name = "post") public class Post { @Id @GeneratedValue @Column(name = "post_id") private Long id; @Column private String postHeader; @OneToMany( cascade = CascadeType.ALL, orphanRemoval = true ) private List comments = new ArrayList<>(); public void addComment(Comment comment) { comments.add(comment); } public void removeComment(Comment comment) { comments.remove(comment); } } Comment.java: @Data @AllArgsConstructor @NoArgsConstructor @Entity @Table(name = "comment") public class Comment { @Id @GeneratedValue @Column(name = "postcom_id") private Long id; @Column private String text; } Вариант bidirectional: *Профессор на курсе может узнавать информацию о студентах, в тоже самое время студенты могут узнавать информацию о Профессоре * Professor.java: @Data @NoArgsConstructor @AllArgsConstructor @Entity @ToString(exclude = "students") @Table(name = "professor") public class Professor { @Id @GeneratedValue @Column(name = "professor_id") private Long id; @Column private String name; @OneToMany( mappedBy = "professor", cascade = CascadeType.ALL, orphanRemoval = true ) List students = new ArrayList<>(); /* As you see we need to do something like "recursion" below */ public void addStudent(Student student) { students.add(student); student.setProfessor(this); } public void removeStudent(Student student) { students.remove(student); student.setProfessor(null); } } Student.java @Data @NoArgsConstructor @AllArgsConstructor @Entity @ToString(exclude = "professor") @Table(name = "student") public class Student { @Id @GeneratedValue @Column(name = "student_id") private Long id; @Column private String name; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name="professor_id") private Professor professor; } @ManyToOne @ManyToMany Вариант unidirectional: Пользователь может иметь несколько Ролей, Роль могут быть присвоина нескольким Пользователям User.java @Entity public class User { @Id @GeneratedValue @Column(name = "user_id") private long id; ... @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL) @JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id")) private List roles = new ArrayList<>(); public void addRoles(Role role) { roles.add(role); } public void removeRoles(Role role) { roles.remove(role); } } Role.java @Entity public class Role { @Id @GeneratedValue @Column(name = "role_id") private int id; @Column(name = "role") private String role; } Вариант bidirectional: Трейдер может торговать на нескольких Биржах, Биржы могут посещаться несколькими Трейдерами Trader.java: @Data @AllArgsConstructor @NoArgsConstructor @Entity @ToString(exclude = "stockmarkets") @Table(name = "trader") public class Trader { @Id @GeneratedValue @Column(name = "trader_id") private Long id; @Column(name = "trader_name") private String traderName; @ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE }) @JoinTable(name = "TRADER_STOCKMARKET", joinColumns = { @JoinColumn(name = "trader_id") }, inverseJoinColumns = { @JoinColumn(name = "stockmarket_id") }) private List stockmarkets = new ArrayList<>(); /* We need to add methods below to make everything work correctly */ public void addStockmarket(Stockmarket stockmarket) { stockmarkets.add(stockmarket); stockmarket.getTraders().add(this); } public void removeStockmarket(Stockmarket stockmarket) { stockmarkets.remove(stockmarket); stockmarket.getTraders().remove(this); } } Stockmarket.java @Data @AllArgsConstructor @NoArgsConstructor @Entity @ToString(exclude = "traders") @Table(name = "stockmarket") public class Stockmarket{ @Id @GeneratedValue @Column(name = "stockmarket_id") private Long id; @Column(name = "stockmarket_name") private String stockmarketName; @ManyToMany(mappedBy="stockmarkets") private List traders = new ArrayList<>(); /* We need to add methods below to make everything work correctly */ public void addTrader(Trader trader) { traders.add(trader); trader.getStockmarkets().add(this); } public void removeTrader(Trader trader) { traders.remove(trader); trader.getStockmarkets().remove(this); } }

воскресенье, 22 декабря 2019 г.

Зачем создавать собственные аннотации?

#java #аннотации


Для чего в java возможно использовать собственную аннотацию?
Какое практическое применение возможно для класса, который зааннотирован созданной
аннотацией?

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Question {
    String data();
    int data2();
}

@Question(data = "What Next?", data2 = 1)
public class MyObj {

    private String name;
    private Integer id;

    public MyObj(String name, Integer id) {
        this.name = name;
        this.id = id;
    }

    public String getName() {
        return name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof MyObj)) return false;

        MyObj myObj = (MyObj) o;

        return id.equals(myObj.id);

    }

    @Override
    public int hashCode() {
        return id.hashCode();
    }
}


Получается, что через рефлексию возможно получение значений, занесенных в аннотацию
для конкретного класса.

И какое практическое применение этой информации возможно?
    


Ответы

Ответ 1



На самом деле, применение ограничено только вашей фантазией: в аннотациях можно писать тесты, описывать правила кеширования, валидации или другие параметры объектов, управлять их поведением... Только нужно понимать, что поскольку вы сами придумываете эти аннотации, инструменты для их обработки тоже нужно будет писать вам.

среда, 4 декабря 2019 г.

Использование ButterKnife

#java #android #аннотации #butterknife


Прочитал об аннотациях в Андроиде и наткнулся на такую либу - ButterKnife.

Какая польза от ее использования? Что она дает, кроме того, что заменяет метод findViewById?
    


Ответы

Ответ 1



Там не только Button button = (Button) findViewById(R.id.button); можно заменить на @InjectView(R.id.button) Button mButton; Но и колбеки инжектить. Скажем: button.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { // ... } }); превратится в: @OnClick(R.id.button) public void onButtonClick() { // ... } В адаптерах упрощается код. Если вы писали свой адаптер для ListView, то должны были писать и ViewHolder для него. Когда въюх много, то очень не красиво и не удобно в holder закидывать элементы. С помощью ButterKnife это просто: static class ViewHolder{ @InjectView(R.id.image_in_item) ImageView image; @InjectView(R.id.textview_in_item) TextView text; public ViewHolder(View view){ ButterKnife.inject(this, view); } } Если вопрос именно в том, почему именно ButterKnife, а не, скажем, RoboGuice, то он компактнее. RoboGuice тянет много зависимостей и медленнее, ибо он в рантайме, а ButterKnife во время компиляции это делает. Да и либу написал Jake Wharton. Это тот же, кто писал ActionBarSherlock и другие классные штуки. UPD: как товарищ pavlofff верно заметил, в новых версиях библиотеки @InjectView был заменен на @Bind, плюс другие изменения были. Лучше смотреть сразу в репозитории библиотеки.

воскресенье, 1 декабря 2019 г.

В каких случаях на практике применять рефлексию, аннотации?

#java #аннотации #рефлексия


Помогите уяснить.

К примеру, одно из частных определений рефлексии говорит: "Рефлексия - это инструмент
с помощью которого можно узнать всю информацию о классе: имена методов, параметры,
поля, аннотации....". 

У меня, как у новичка, возникает резонный вопрос, зачем мне эту информацию узнавать,
если классы, методы, поля и т.д. я пишу сам и всё про них знаю?

Понимаю, что используется рефлексия не для своих классов и т.д., но не могу найти
реальный пример, который был бы понятен новичку: в какой ситуации я столкнусь с тем,
что не буду знать имя класса, метода и т.д.?

То же самое с аннотациями: "...средство, позволяющее встраивать справочную информацию
в исходные файлы......". Ну встрою я её, ну а профит какой, что я в итоге с помощью
этого получу? Какие плюшки для разработчика появятся при наличии аннотаций? Как они
способны облегчить жизнь?
    


Ответы

Ответ 1



Рефлексия и аннотации позволяют решать задачи, который в иных случаях можно было бы решить либо ручным монотонным кодированием, либо кодогенерацией. И, конечно, когда они используются, то применяются не к конкретным классам, а с запасом, даже к тем классам, которые вы напишете в будущем. Часто их используют в библиотечном коде, который будет бродить между проектами и, соответственно, о классах тех проектов вообще не знать ничего. Несколько конкретных примеров: Аннотации Hibernate Hibernate — это ORM, то есть библиотека для удобного отображения баз данных на объектный код. Часто в базе и в Java-коде применяются разные соглашения об именовании. Для того, чтобы Hibernate понимал, какое поле куда копировать, применяют аннотации. Для таблицы: create table EMPLOYEE ( id INT NOT NULL auto_increment, first_name VARCHAR(20) default NULL, last_name VARCHAR(20) default NULL, salary INT default NULL, PRIMARY KEY (id) ); Можно применить аннотации: @Entity @Table(name = "EMPLOYEE") public class Employee { @Id @GeneratedValue @Column(name = "id") private int id; @Column(name = "first_name") private String firstName; @Column(name = "last_name") private String lastName; @Column(name = "salary") private int salary; public Employee() {} public int getId() { return id; } public void setId( int id ) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName( String first_name ) { this.firstName = first_name; } public String getLastName() { return lastName; } public void setLastName( String last_name ) { this.lastName = last_name; } public int getSalary() { return salary; } public void setSalary( int salary ) { this.salary = salary; } } Пример взят отсюда. Кратко, что здесь происходит: в базе данных поле называется, например, first_name, а в Java-коде — firstName. Благодаря аннотациям при загрузке записей из базы в объект Employee библиотека самостоятельно раскидает все поля как надо. Компилятор Java Компилятор также использует аннотации для дополнительных проверок или для изменения своих настроек внутри отдельных методов. Смотрите аннотации @Override и @SuppressWarnings. AndroidAnnotations Проект http://androidannotations.org/ позволяет значительно упростить разработку кода для Android, реализовав частые задачи, и обернув их в аннотации. Это как раз хороший пример библиотечного кода, который будет работать в незнакомых проектах. Естественно, для реализации этого кода активно применяется рефлексия. Пример «до аннотаций» и «после аннотаций» приведён прямо на главной странице по ссылке выше. Аспектно-ориентированное программирование Про него много писать не буду, поскольку тема очень большая и новичку может быть не сильно нужная. Но в целом АОП как раз об этом. Например, вы можете написать свои классы, а потом озаботится проверкой прав доступа, навроде администратор может удалять записи, а обычный пользователь — нет. При классическом подходе вам придётся вносить однотипные изменения в большое количество существующих классов, а потом не забывать делать это для новых. В АОП вы можете просто придумать аннотации @Administrator, @User, @Moderator и расставить их у нужных классов и методов. Это тоже монотонно, но всё равно гораздо проще. Рефлексия без аннотаций Рефлексия применяется ещё чаще, например, в разного рода шаблонизаторах и мапперах. Шаблонизаторы позволяют вам использовать шаблоны писем, например, как этот: Здравствуйте, %username%! Напоминаем Вам, что вы задолжали нам крупную сумму денег в размере %amount% рублей. Мы помним! С уважением, Коллекторское агентство «Солнышко» Затем вы передаете шаблонизатору класс с полями username и amount и он самостоятельно сформирует текст письма. Такую задачу без рефлексии не сделать. Заключение В целом, рефлексия и аннотации позволяют избавиться от так называемого monkey coding, то есть от монотонного низкоуровнего кодирования.

Ответ 2



1) Dependency injection framework'и на рефлексии зачастую основаны 2) Вызывать методы по имени. Скажем, есть у вас на входе имя метода, вы можете его вызвать так: Method method = foo.getClass().getMethod("myMethod", null); method.invoke(foo, null); 3) Тоже самое и для инстанциации классов. Мы делаем игру на Unity3d, тут, правда, C#, но суть не меняется. У нас есть куча заклинаний. Список доступных заклинаний в виде массива. Нам надо инстанциировать нужные классы по названию. Либо делать большой switch блок с кучей case, либо вызвать всего 1 метод. 4) С помощью рефлексии можно достучаться до final и protected полей класса, если необходимо. У меня была частая необходимость в этом, когда, к примеру, работал с Android. Многие поля классов из SDK были скрыты, можно было достать и изменить их только с помощью рефлексии. P.S. но надо избегать использование рефлексии, где это возможно, так как она очень медленная по природе

вторник, 9 июля 2019 г.

Null Pointer Exception Аннотация @Autowired Spring

Никак не могу разобраться с тем, как работает аннотация @Autowired в Spring. Итак, допустим, у меня есть вот такой интерфейс Interface1:
public interface Interface1 { String getString(); }
У него есть всего один метод. Следующий класс, являющийся @Service, реализует этот простой интерфейс:
@Service public class Interface1Impl implements Interface1 { public String getString() { return "Hello!"; } }
Теперь я хочу использовать где-то экземпляр этого класса вместе с аннотацией @Autowired. Создаю вот такой вот класс Instance1:
@Service public class Instance1 {
@Autowired Interface1 field;
public void doSomething() { System.out.println(field.getString()); } }
Далее в методе main своего главного класса я делаю следующее:
public class MainClass { public static void main(String[] args) { Instance1 instance = new Instance1(); instance.doSomething(); } }
Однако появляется NullPointerException из-за того, что field с аннотацией @Autowired остался без присвоенного значения. Я не понимаю, почему так, и в целом плохо понимаю, как в данной ситуации работает Spring. Пожалуйста, объясните мне, как можно исправить код, чтобы в методе main я смог вызывать методы instance.


Ответ

"Магия" аннотаций Spring работает только внутри контекста Spring. Который вам нужно создать. Вот некоторое приближение того, что вы пытаетесь сделать в main
@Configuration @ComponentScan(basePackages = "your.package") public class MainClass { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(MainClass.class); Instance1 inst = ctx.getBean(Instance1.class); inst.doSomething(); } }
Но в Spring-приложениях впринципе не принято делать никакую логику в main, кроме какой-то базовой инициализации самого Spring, т.к. этот код лежит за пределами контекста приложения.

воскресенье, 26 мая 2019 г.

Правила удержания аннотаций. SOURCE, CLASS, RUNTIME

Что обозначают правила SOURCE, CLASS и RUNTIME, инкапсулированные в перечисление java.lang.annotation.RetentionPolicy?


Ответ

Рассмотрим вопрос на примере аннотации @Override, которая указывает на переопределение метода.
Так выглядит @Override в своей реализации
@Retention(RetentionPolicy.SOURCE) public @interface Override { }
SOURCE в данном случае указывает на то, что аннотация @Override (как и другая, к которой это правило будет применимо) будет "отброшена" во время компиляции. CLASS - как другое правило, указывает, что аннотация, к которой оно будет применимо, сохранится в файле с расширением .class во время компиляции, но не будет доступна для виртуальной машины JVM во время выполнения. RUNTIME - как другое правило, указывает, что аннотация, к которой оно будет применимо, сохранится в файле с расширением .class во время компиляции, и будет доступна для виртуальной машины JVM во время выполнения.

среда, 10 октября 2018 г.

Использование ButterKnife

Прочитал об аннотациях в Андроиде и наткнулся на такую либу - ButterKnife.
Какая польза от ее использования? Что она дает, кроме того, что заменяет метод findViewById?


Ответ

Там не только
Button button = (Button) findViewById(R.id.button);
можно заменить на
@InjectView(R.id.button) Button mButton;
Но и колбеки инжектить.
Скажем:
button.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { // ... } });
превратится в:
@OnClick(R.id.button) public void onButtonClick() { // ... }
В адаптерах упрощается код. Если вы писали свой адаптер для ListView, то должны были писать и ViewHolder для него. Когда въюх много, то очень не красиво и не удобно в holder закидывать элементы. С помощью ButterKnife это просто:
static class ViewHolder{ @InjectView(R.id.image_in_item) ImageView image; @InjectView(R.id.textview_in_item) TextView text;
public ViewHolder(View view){ ButterKnife.inject(this, view); } }
Если вопрос именно в том, почему именно ButterKnife, а не, скажем, RoboGuice, то он компактнее. RoboGuice тянет много зависимостей и медленнее, ибо он в рантайме, а ButterKnife во время компиляции это делает.
Да и либу написал Jake Wharton. Это тот же, кто писал ActionBarSherlock и другие классные штуки.
UPD: как товарищ pavlofff верно заметил, в новых версиях библиотеки @InjectView был заменен на @Bind, плюс другие изменения были. Лучше смотреть сразу в репозитории библиотеки.

понедельник, 8 октября 2018 г.

В каких случаях на практике применять рефлексию, аннотации?

Помогите уяснить.
К примеру, одно из частных определений рефлексии говорит: "Рефлексия - это инструмент с помощью которого можно узнать всю информацию о классе: имена методов, параметры, поля, аннотации....".
У меня, как у новичка, возникает резонный вопрос, зачем мне эту информацию узнавать, если классы, методы, поля и т.д. я пишу сам и всё про них знаю?
Понимаю, что используется рефлексия не для своих классов и т.д., но не могу найти реальный пример, который был бы понятен новичку: в какой ситуации я столкнусь с тем, что не буду знать имя класса, метода и т.д.?
То же самое с аннотациями: "...средство, позволяющее встраивать справочную информацию в исходные файлы......". Ну встрою я её, ну а профит какой, что я в итоге с помощью этого получу? Какие плюшки для разработчика появятся при наличии аннотаций? Как они способны облегчить жизнь?


Ответ

Рефлексия и аннотации позволяют решать задачи, который в иных случаях можно было бы решить либо ручным монотонным кодированием, либо кодогенерацией.
И, конечно, когда они используются, то применяются не к конкретным классам, а с запасом, даже к тем классам, которые вы напишете в будущем. Часто их используют в библиотечном коде, который будет бродить между проектами и, соответственно, о классах тех проектов вообще не знать ничего.
Несколько конкретных примеров:
Аннотации Hibernate
Hibernate — это ORM, то есть библиотека для удобного отображения баз данных на объектный код. Часто в базе и в Java-коде применяются разные соглашения об именовании. Для того, чтобы Hibernate понимал, какое поле куда копировать, применяют аннотации. Для таблицы:
create table EMPLOYEE ( id INT NOT NULL auto_increment, first_name VARCHAR(20) default NULL, last_name VARCHAR(20) default NULL, salary INT default NULL, PRIMARY KEY (id) );
Можно применить аннотации:
@Entity @Table(name = "EMPLOYEE") public class Employee { @Id @GeneratedValue @Column(name = "id") private int id;
@Column(name = "first_name") private String firstName;
@Column(name = "last_name") private String lastName;
@Column(name = "salary") private int salary;
public Employee() {} public int getId() { return id; } public void setId( int id ) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName( String first_name ) { this.firstName = first_name; } public String getLastName() { return lastName; } public void setLastName( String last_name ) { this.lastName = last_name; } public int getSalary() { return salary; } public void setSalary( int salary ) { this.salary = salary; } }
Пример взят отсюда. Кратко, что здесь происходит: в базе данных поле называется, например, first_name, а в Java-коде — firstName. Благодаря аннотациям при загрузке записей из базы в объект Employee библиотека самостоятельно раскидает все поля как надо.
Компилятор Java
Компилятор также использует аннотации для дополнительных проверок или для изменения своих настроек внутри отдельных методов. Смотрите аннотации @Override и @SuppressWarnings
AndroidAnnotations
Проект http://androidannotations.org/ позволяет значительно упростить разработку кода для Android, реализовав частые задачи, и обернув их в аннотации. Это как раз хороший пример библиотечного кода, который будет работать в незнакомых проектах. Естественно, для реализации этого кода активно применяется рефлексия. Пример «до аннотаций» и «после аннотаций» приведён прямо на главной странице по ссылке выше.
Аспектно-ориентированное программирование
Про него много писать не буду, поскольку тема очень большая и новичку может быть не сильно нужная. Но в целом АОП как раз об этом. Например, вы можете написать свои классы, а потом озаботится проверкой прав доступа, навроде администратор может удалять записи, а обычный пользователь — нет
При классическом подходе вам придётся вносить однотипные изменения в большое количество существующих классов, а потом не забывать делать это для новых. В АОП вы можете просто придумать аннотации @Administrator, @User, @Moderator и расставить их у нужных классов и методов. Это тоже монотонно, но всё равно гораздо проще.
Рефлексия без аннотаций
Рефлексия применяется ещё чаще, например, в разного рода шаблонизаторах и мапперах. Шаблонизаторы позволяют вам использовать шаблоны писем, например, как этот:
Здравствуйте, %username%!
Напоминаем Вам, что вы задолжали нам крупную сумму денег в размере %amount% рублей. Мы помним!
С уважением, Коллекторское агентство «Солнышко»
Затем вы передаете шаблонизатору класс с полями username и amount и он самостоятельно сформирует текст письма. Такую задачу без рефлексии не сделать.
Заключение
В целом, рефлексия и аннотации позволяют избавиться от так называемого monkey coding, то есть от монотонного низкоуровнего кодирования.