Аннотации стали доступны в 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@LoadWithActorsAndAwardspublic 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 Роберто Кортеса в блоге |

