Недостатки обработки аннотаций в Java?

Я рассматриваю возможность запуска проекта, который используется для генерации кода в Java с помощью аннотаций (я не буду вдаваться в подробности, поскольку это не очень актуально). Меня интересует обоснованность и полезность проекта, и что-то, что поразило меня, - это зависимость от инструмента обработки аннотации (apt).

Что я хотел бы знать, поскольку я не могу говорить по опыту, каковы недостатки использования обработки аннотаций в Java?

Это может быть что угодно, в том числе:

  • Трудно делать TDD при записи процессора
  • Трудно включить обработку в систему сборки
  • обработка занимает много времени, и очень сложно заставить ее работать быстро
  • Использование аннотаций в среде IDE требует плагина для каждого, чтобы заставить его вести себя одинаково при сообщениях об ошибках.

Это просто примеры, а не мое мнение. Я в процессе исследования, если кто-либо из них правдивый (в том числе задающий этот вопрос;-))

Я уверен, что должны быть недостатки (например, Qi4J специально перечислять не использование препроцессоров в качестве преимущества), но я не имеют опыта с ним, чтобы рассказать, что они собой представляют.

Разумной альтернативой использованию обработки аннотаций, вероятно, является создание плагинов для соответствующих IDE для генерации кода (это было бы нечто похожее на функцию переопределения/реализации методов, которая генерировала бы все подписи без тел метода). Однако этот шаг нужно повторять каждый раз, когда соответствующие части кода меняются, обработка аннотаций, насколько я могу судить, не будет.

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

Ответ 1

Я создал набор аннотаций JavaBean (http://code.google.com/p/javadude/wiki/Annotations)

[Примечание: сейчас я работаю над новой версией, поэтому код соединительной линии не соответствует загрузке сайта обновлений.

Тестирование

Тестирование их может быть довольно сложным...

Я обычно подхожу к нему, создавая проект в eclipse с помощью тестового кода и строя его, затем делаю копию и отключая обработку аннотаций.

Затем я могу использовать Eclipse для сравнения "активного" тестового проекта с "ожидаемой" копией проекта.

У меня еще не слишком много тестовых примеров (очень утомительно создавать так много комбинаций атрибутов), но это помогает.

Система сборки

Использование аннотаций в системе сборки на самом деле очень просто. Взгляните на http://code.google.com/p/javadude/wiki/Annotations для примера того, как он используется в ant script, а его использование в eclipse - это просто вопрос создания плагина с указанием расширения обработчика аннотаций и включения обработки аннотаций в проектах, которые хотят его использовать.

Я использовал обработку аннотаций в непрерывной среде сборки, построил аннотации и процессор, а затем использовал ее в остальной части сборки. Это действительно очень безболезненно.

Время обработки

Я не считаю, что это проблема - будьте осторожны с тем, что вы делаете в процессорах. Я генерирую много кода в моем, и он работает нормально. Это немного медленнее в ant.

Обратите внимание, что процессоры Java6 могут работать немного быстрее, потому что они являются частью обычного процесса компиляции. Тем не менее, у меня возникли проблемы с тем, чтобы они работали правильно в генерации кода (я думаю, что большая часть проблемы - поддержка eclipse и запуск многофазных компиляторов). На данный момент я придерживаюсь Java 5.

Обработка ошибок

Это одна из самых прозаических вещей в API аннотации. API имеет объект "мессенджер", который обрабатывает все ошибки. Каждая среда IDE предоставляет реализацию, которая преобразует ее в соответствующие сообщения об ошибках в нужном месте в коде.

Единственное, что я делал, это бросить объект среды обработки, чтобы я мог проверить, был ли он запущен как сборка или согласование редактора. Если редактирование, я выхожу. В конце концов я изменю это, чтобы просто проверять ошибки во время редактирования, чтобы он мог сообщать о ошибках по мере ввода. Однако будьте осторожны - вам нужно поддерживать его очень быстро для использования во время согласования, или редактирование становится вялым.

Генерация кода Gotcha

[добавлено немного больше комментариев]

В спецификациях процессора аннотаций указано, что вам не разрешено изменять класс, содержащий аннотацию. Я подозреваю, что это упрощает обработку (в дальнейших раундах не нужно включать аннотированные классы, предотвращая также бесконечные петли обновления)

Однако вы можете создавать другие классы, и они рекомендуют этот подход.

Я создаю суперкласс для всех методов get/set и всего, что мне нужно для создания. У меня также есть процессор, проверяющий, что аннотированный класс расширяет сгенерированный класс. Например:

@Bean(...)
public class Foo extends FooGen

Я генерирую класс в том же пакете с именем аннотированного класса плюс "Gen" и проверяю, что объявленный класс объявлен для его расширения.

Я видел, как кто-то использовал дерево компилятора api для изменения аннотированного класса - это противоречит спецификации, и я подозреваю, что они закроют это отверстие в какой-то момент, так что это не сработает.

Я бы рекомендовал создать суперкласс.

В целом

Мне очень нравится использование обработчиков аннотаций. Очень хорошо разработан, особенно глядя на независимость от IDE/командной строки.

В настоящее время я рекомендую придерживаться аннотационных процессоров Java5, если вы создаете код - вам нужно запустить отдельный инструмент apt для их обработки, а затем выполнить компиляцию.

Обратите внимание, что API-интерфейсы для Java 5 и Java 6 отличаются! API обработки Java 6 лучше IMHO, но мне просто не повезло с процессорами java 6, которые делают то, что мне нужно.

Когда Java 7 выйдет, я дам новый подход к обработке еще одним выстрелом.

Не стесняйтесь, напишите мне, если у вас есть вопросы. ([email protected])

Надеюсь, это поможет!

Ответ 2

Я думаю, что если обработчик аннотации тогда определенно использует версию API Java 6. Это тот, который будет поддержан в будущем. API Java 5 по-прежнему находился в неофициальном пространстве имен com.sun.xyz.

Я думаю, что в ближайшем будущем мы увидим гораздо больше использования API-интерфейса обработчика аннотаций. Например, Hibernate разрабатывает процессор для новой статической метамодели, связанной с запросом на запрос JPA 2. Они также разрабатывают процессор для проверки Bean аннотаций проверки. Таким образом, обработка аннотации должна оставаться.

Интеграция инструментов в порядке. В последних версиях основных IDE содержатся параметры для настройки обработчиков аннотаций и их интеграции в процесс сборки. Инструменты создания основного потока также поддерживают обработку аннотаций, где maven все еще может вызвать некоторое горе.

Тестирование Я нахожу большую проблему. Все тесты косвенны и как-то проверяют конечный результат обработки аннотации. Я не могу писать простые модульные тесты, которые просто утверждают простые методы, работающие над TypeMirrors или другими классами, основанными на отражении. Проблема заключается в том, что нельзя создавать экземпляры этих типов вне цикла компиляции процессоров. Я не думаю, что Sun имела в виду при тестировании API.

Ответ 3

Один конкретный вопрос, который был бы полезен при ответе на вопрос, был бы противоположным тому, что? Не делать проект или делать это без использования аннотаций? А если не использовать аннотации, каковы альтернативы?

Лично я нахожу чрезмерные аннотации нечитаемыми и много раз слишком негибкими. Взгляните на это для одного метода в веб-службе для реализации требуемого поставщика WSDL:

    @WebMethod(action=QBWSBean.NS+"receiveResponseXML")
@WebResult(name="receiveResponseXML"+result,targetNamespace = QBWSBean.NS)
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public int receiveResponseXML(
        @WebParam(name = "ticket",targetNamespace = QBWSBean.NS) String ticket,
        @WebParam(name = "response",targetNamespace = QBWSBean.NS) String response,
        @WebParam(name = "hresult",targetNamespace = QBWSBean.NS) String hresult,
        @WebParam(name = "message",targetNamespace = QBWSBean.NS) String message) {

Я нахожу этот код очень нечитаемым. Альтернатива конфигурации XML не обязательно лучше.