Аннотации стали доступны в Java 1.5 в 2004 году , десять лет назад. Трудно представить наш код без этой функции. Фактически, аннотации были впервые введены, чтобы избавить разработчиков от боли написания утомительного стандартного кода и сделать код более читабельным. Подумайте о J2EE 1.4 (аннотации недоступны) и Java EE 5. Принятие аннотаций значительно упростило разработку приложения Java EE, избавившись от всего XML конфигурации. Даже сегодня к новейшей версии Java EE добавляется больше аннотаций. Идея состоит в том, чтобы разгрузить разработчика и повысить производительность. Другие технологии и фреймворки также широко их используют.
Аннотации везде
Давайте рассмотрим пример того, как аннотации упростили наш код (из моего поста о графах сущностей JPA ):
Movie.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
@Entity @Table (name = "MOVIE_ENTITY_GRAPH" ) @NamedQueries ({ @NamedQuery (name = "Movie.findAll" , query = "SELECT m FROM Movie m" ) }) @NamedEntityGraphs ({ @NamedEntityGraph ( name = "movieWithActors" , attributeNodes = { @NamedAttributeNode ( "movieActors" ) } ), @NamedEntityGraph ( name = "movieWithActorsAndAwards" , attributeNodes = { @NamedAttributeNode (value = "movieActors" , subgraph = "movieActorsGraph" ) }, subgraphs = { @NamedSubgraph ( name = "movieActorsGraph" , attributeNodes = { @NamedAttributeNode ( "movieActorAwards" ) } ) } ) }) public class Movie implements Serializable { @Id private Integer id; @NotNull @Size (max = 50 ) private String name; @OneToMany @JoinColumn (name = "ID" ) private Set<MovieActor> movieActors; @OneToMany (fetch = FetchType.EAGER) @JoinColumn (name = "ID" ) private Set<MovieDirector> movieDirectors; @OneToMany @JoinColumn (name = "ID" ) private Set<MovieAward> movieAwards; } |
Подожди минуту! Упрощенный? В самом деле? Разве аннотации не должны сделать мой код более читабельным? Этот пример имеет больше аннотаций, чем фактический код. Честно говоря, я не включаю геттеры и сеттеры. Кроме того, часть аннотированного кода может быть лучше сжата, но это затруднит чтение кода. Конечно, это крайний случай. Во всяком случае, я счастлив, поскольку я выиграл титул Annotatiomaniac of the Year . Спасибо, Лукас!
Мы настолько полагаемся на аннотации, что в итоге злоупотребляем ими. Забавно, что аннотации в некоторых случаях вызывают те же проблемы, которые они намеревались решить.
Что, если?
Давайте перепишем предыдущий пример так:
Movie.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
@MovieEntity @FindAll @LoadWithActors @LoadWithActorsAndAwards public class Movie implements Serializable { @Id private Integer id; @Name private String name; @MovieActors private Set<MovieActor> movieActors; @MovieDirectors private Set<MovieDirector> movieDirectors; @MovieAwards private Set<MovieAward> movieAwards; } |
Это выглядит более читабельным. Но этих аннотаций не существует. Откуда они?
@LoadWithActors
LoadWithActors.java
1
2
3
4
5
6
7
|
@NamedEntityGraph ( name = "movieWithActors" , attributeNodes = { @NamedAttributeNode ( "movieActors" ) } ) public @interface LoadWithActors {} |
@LoadWithActorsAndAwards
LoadWithActorsAndAwards.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
@NamedEntityGraph ( name = "movieWithActorsAndAwards" , attributeNodes = { @NamedAttributeNode (value = "movieActors" , subgraph = "movieActorsGraph" ) }, subgraphs = { @NamedSubgraph ( name = "movieActorsGraph" , attributeNodes = { @NamedAttributeNode ( "movieActorAwards" ) } ) } ) public @interface LoadWithActorsAndAwards {} |
И так далее для всего остального. Вы получаете чувство. Идея заключается в том, чтобы извлечь и сгруппировать метаданные аннотации в свои собственные аннотации. Ваша аннотация может затем использоваться для представления всех аннотированных данных в вашем коде, что облегчает понимание. Это как Java 8 Lambdas, читать как постановка задачи.
Еще один пример:
WoWBusinessBean.java
1
2
3
4
5
6
7
8
|
@Named @Stateless @TransactionAttribute (TransactionAttributeType.SUPPORTS) @ApplicationPath ( "/resources" ) @Path ( "wowauctions" ) @Consumes (MediaType.APPLICATION_JSON) @Produces (MediaType.APPLICATION_JSON) public class WoWBusinessBean extends Application implements WoWBusiness {} |
переписан:
WoWBusinessBean.java
1
2
|
@RestStatelessBean ( "wowauctions" ) public class WoWBusinessBean extends Application implements WoWBusiness {} |
@RestStatelessBean
RestStatelessBean
01
02
03
04
05
06
07
08
09
10
|
@Named @Stateless @TransactionAttribute (TransactionAttributeType.SUPPORTS) @ApplicationPath ( "/resources" ) @Path ( "#{path}" ) @Consumes (MediaType.APPLICATION_JSON) @Produces (MediaType.APPLICATION_JSON) public @interface RestStatelessBean { String value() default "#{path}" ; } |
Обычно я пишу эти аннотации один раз, чтобы определить поведение моего POJO и никогда больше не заглядываю в них. Как было бы здорово, если бы я мог просто повторно использовать одну аннотацию для всех моих служб отдыха без сохранения состояния?
Другим приятным эффектом является то, что метаданные конфигурации аннотации напрямую не связаны в коде. Вместо этого он абстрагируется в другую аннотацию. В этом случае можно будет переопределить или заменить значения во время компиляции / выполнения.
Мета аннотации
Впервые я услышал об этой концепции от Дэвида Блевинса . Он написал очень хороший пост об этих идеях в своем посте Meta-Annotations и даже написал возможную реализацию .
Было бы удобно иметь простую поддержку Java SE для наследования, абстракции и инкапсуляции аннотаций. Это серьезный сдвиг в том, как аннотации обрабатываются всеми существующими технологиями. Это имеет смысл, только если все начнут поддерживать такое поведение.
Кто-то может спросить, нужна ли нам эта функция? Давайте попробуем взвесить некоторые плюсы и минусы:
Pros
- Упрощенный код.
- Повторное использование аннотации.
- Конфигурация аннотации напрямую не связана с кодом. Значения могут быть переопределены.
Cons
- Еще один уровень абстракции.
- Свобода создания пользовательских аннотаций может запутать реальное поведение.
- Возможно столкнуться с какой-то проблемой множественного наследования.
Вывод
Маловероятно, что эти метааннотации будут доступны в Java SE в обозримом будущем. В Java 9 основное внимание уделяется Jigsaw. У нас пока нет большой информации о Java 10, за исключением типов значений и общей специализации. На самом деле, все эти проблемы с аннотациями не являются проблемой для простого Java SE.
Количество комментариев, присутствующих в наших исходных файлах, становится проблемой в отношении читабельности и удобства обслуживания. Это особенно верно для Java EE и других подобных технологий. Подумайте о HTML и CSS. Если вы разрабатываете страницу HTML, и вам нужна только пара стилей CSS, вы обычно вставляете их в элементы или включаете их непосредственно на странице. Если у вас слишком много стилей, вы продолжаете извлекать их во внешний файл CSS и просто применяете стиль. Я действительно считаю, что что-то должно быть сделано либо путем принятия метааннотаций, либо чего-то еще У тебя есть другие идеи? Пожалуйста, поделитесь ими!
Ресурсы
Не забудьте проверить пост Дэвида Блевинса о метааннотациях . Он объясняет это намного лучше меня, включая технические детали.
Также презентация JavaOne EJB с метааннотациями, обсуждающая эти идеи Дэвида Блевинса .
А что лучше, чем слушать самого Дэвида Блевинса ? Java EE 7, Infinite Extensibility встречает бесконечное повторное использование .
Ссылка: | Аннотации, аннотации везде от нашего партнера по JCG Роберто Кортеса в блоге |