18 Dec 2012

Hibernate. Аннотации против XML

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

Хотя в интернетах можно найти много споров по поводу того какой подход лучше: аннотации или XML - они в большей своей степени субъективны и зависят от личных религиозных соображений. Хотелось бы здесь описать объективные причины когда и почему один из способов может быть лучше или хуже с практической стороны.
Итак, плюсы аннотаций:

  • Это движение к стандартизации если говорить про JPA-аннотации. Это может быть неправдой если вы используете Hibernate аннотации, и вам это придется делать если маппинг будет хотя бы чуточку сложный. Однако это все равно ближе к стандарту нежели XML (конечно есть JPA XML, однако никогда не видел его применения на практике, поэтому речь здесь веду именно об hbm.xml).

  • С аннотациями проще и быстрей начинать проект, ибо не нужны доп файлы. Во время старта итак много всяких артефактов и контекстов нужно создавать, а тут еще и hbm.xml файлы.

Минусы аннотаций:

  • Аннотациями вы “загрязняете” свои классы. Это может быть неправдой если у вас достаточно простой маппинг и, особенно, когда имена сущностей совпадают с именами таблиц (что редкость..). Представьте что вам еще нужно JAXB, Lucene маппинги на сущностях делать. В какой-то момент эти все аннотации трудно будет читать.

  • Вам придется писать HQL запросы прямо в Java-классах, что неизбежно приведет к конкатенации оных. В общем читабельность таких запросов ниже плинтуса.

В то же время минусы XML:

  • Появляются те самые доп файлы.

  • Формат ниразу не стандартный, и это затруднит переход к другим JPA реализациям.

Ну и наконец плюсы XML:

  • Оставляет классы чистыми аки совесть младенца. Это особенно приятно в случае со сложными маппингами.

  • Там можно оставлять длинные HQL запросы, и они не так будут смущать глаз.

  • XML проще для начинающих, потому как есть XSD/DTD, автоподсказки и т.п. С аннотациями же нужно точно знать что куда можно ставить, и в редких случаях нагуглить решение совсем не тривиально.

  • Есть возможность замапить одну и ту же Java сущность на несколько таблиц. Пример: представьте что у вас есть продукт (StoreItem) у которого может быть набор свойств. Эти свойства могут быть самыми разными: картинка, цвет, масса и пр. Все они должны иметь определения (хотя бы название -> значение). Причем значения еще могут иметь какие-то умолчания. Итого, появляется таблица PROPERTY_DEFINITION в которую помещаются все возможные свойства и их значения. Ну и конечно есть таблица со значениями этих свойств для конкретных продуктов ITEM_PROPERTY. Когда создается StoreItem мы копируем какие-то свойства из PROPERTY_DEFINITION и помещаем их в ITEM_PROPERIY, на которую уже ссылается конкретный StoreItem. Итого мы имеем класс Property, который может маппиться на обе таблицы. Аннотации не смогут дать такую гибкость, в то время как XML может использовать entity-name.

  • Если вы делите общие классы между несколькими проектами помещая их в jar-файлы, вполне возможно, что проекты захотят по-разному мапить эти сущности на таблицы БД. Иногда это важно и у вас просто не остается выбора кроме как использовать XML (прошу заметить что я не призываю к такому дизайну, и даже наоборот, считаю подход с общими классами неправильным, однако такое случается на практике, и иногда мы просто это получаем в руки).

  • Также бывают случаи, что классы генерируются по XSD или каким-то другим определениям типов. Такие классы могут не находится в репозитории и создаваться во время сборки. Если вы хотите замапить такие классы, у вас не остается выбора кроме как XML. Однако имейте в виду, что вы скорей всего не хотите оказаться в такой ситуации, обычно DB Entities и DTO - это разные классы, иначе рефакторинг одной из сторон будет усложнять жизнь, если делаете так, то только на начальных этапах проекта с заметкой “на рефакторинг”.

  • БД-нейтральность. Если наше приложение должно поддерживать несколько СУБД, на аннотациях мы бы писали два модуля с разными сущностями и разным маппингом, потому как в реальной жизни Hibernate не настолько СУБД-нейтрален, те же стратегии для генерации PK: sequence vs. identity. В случае же с XML мы можем создать два модуля с разными маппингами.