Как стать автором
Обновить

Комментарии 24

Делал такой же изврат на Codedom + NHibernate. Из опыта уверен, что означенная проблема должна решаться как-то по другому )
1) каким образом происходим изменение Типов? к примеру удаление и удаление полей на лету? интересен момент работы с Hibernate в этот момент
2) получается каждый раз при поднятии сервера, он компилит классы типов заново?
1) При изменении структуры типов нужно заново строить классы (причём — в новом класс-лоадере, разумеется). Изменить класс на лету нельзя — можно только загрузить заново.

И после этого заново строится SessionFactory / EntityManagerFactory с новыми классами.

2) Да, при поднятии сервера и при изменении конфигурации. Но не надо боятся слова «компилит» — это происходит намного быстрее чем компилирование кода в Javac. Фактически класс загружается не с диска, а из памяти, так как код не компилирует, а практически записывает байт-код в массив.
1) > И после этого заново строится SessionFactory / EntityManagerFactory с новыми классами
это узкое место, хотя с учетом того что классы типы изменяются очень редко, это не критично
2) необязательно использовать javac, можно заюзать ToolProvider.getSystemJavaCompiler()
2) В том то и фишка, что компилятор вообще не используется, и это не отнимает время процессора. Какой бы JavaCompiler или EclipseJavaCompiler не использовать — это будет медленно, так как надо разобрать грамматику, найти зависимые класс, сгенерировать код и т.д. А тут — фактически двоичный код пишется, разве что байт-код, а не исполняемый машинный.
Спасибо за интересную и исчерпывающую статью. В текущей работе я, наверное, не буду стараться добавлять универсальности. Но на будущее очень полезно. Рад, что на хабре появляются статьи по java.
Можно ли обращаться к этим классам из обычных исходников? Если нет, то можно было бы использовать DynamicMap в Hibernate.
опишите в двух словах что даст DynamicMap? когда-то пытался его прикрутить, но чего-то не очень получилось, может примерчик скинете достойный?
docs.jboss.org/hibernate/core/3.3/reference/en/html/persistent-classes.html#persistent-classes-dynamicmodels

Если в 2 словах, то вместо POJO используется HashMap. Конфигурация задается в XML. Из минусов можно отметить гемор в написании бизнес логики (нет проверки имен и типов свойств на этапе компиляции).
не, с XML геморно, я делаю так: формирую исходный код с аннотациями и его подсовываю Хибернейту, перегружаю фабрику сессий и на выходе получаю модифицированные таблицы
Для обращении из обычных исходников делается так:

вариант а:
— обращаемся, как и раньше, по ((TextField)object.getField(name)).getValue()

вариант б:
— создаём интерфейс:
public interface ArticleContent {
    public String getContent();
    public void setContent(String value);
}

в описании ComplexType добавляем интерфейс:
    complexType.getInterfaces().add(ArticleContent.class);

Теперь после загрузки можно кастовать объект к этому интерфейсу и использовать поля:
    ArticleContent content = (ArticleContent) loaded;
    content.getContent();
Собственно, это и было одной из целей переделки :)
Я не очень понял суть решения, но не проще ли генерировать исходные ява-файлы, а не байт-код? И да, кодогенераци в данном примере имхо изврат и неправильный подход. Кодогенерацией как правило, пользуются, чтобы автоматизировать процес создания кода методом копипаста, что изначально неправильно.

И тем более в ява кодогенерация неоправданна, так как там код загружается не при каждом запросе как в PHP апри старте сервера. Вы можете сгенерировать лббые классы динамически.
НЛО прилетело и опубликовало эту надпись здесь
Нет, это не то. Генерировать классы динамически — значит создавать их в памяти, добавляя свойства и методы, а не байт код или исходный код.
Интересно послушать как, не добавляя байт-код или исходный-код, вы собираетесь добавлять методы. Что же они делать-то будут?

Может быть, вы имеете ввиду Proxy + interfaces + InvokationHandler, когда коду передаётся имя метода и он решает, как этот метод должен работать? Это тоже вариант, но намного более медленный.
Имхо у подхода есть один существенный недостаток: хибернейт при изменении модели не умеет делать ALTER таблицы, а вместо этого делает DELETE и затем CREATE таблицы. А значит что пропадает полностью все текущее состояние.
Если ты научил хибернейт менять схему, то дай знать пожалуйста.
да ну, у меня он делает ALTER при расширении полей типа, а вот при уменьшении поля таблицы остаются, нужно руками удалять
В общем случае этого нельзя добиться даже теоретически, так как неизвестно: переименовал ты колонку или удалил старую и добавил новую. Для того, чтобы заработало автоматическое обновление схемы нужно в некотором виде хранить историю изменений классов объектов с данными. Например, в аннотации к свойству указывать предыдущие имена.
а если операции переименовывания или удаления делать через спец методы, тогда можно добится
Поподробнее можно? ссылочку какую-нибудь подкиньте, пожалуйста.
подробнее в 2-х словах: переименование полей делаете через свой спец метод, который удалит старое поле в классе и создаст новое (после чего Хибернейт сделает ALTER) + этот же метод либо удалит старое поле в таблице, либо сначала скопирует данные в новое поле а только потом удалит старое. Вообщем это надо руками делать, но это реально реализуемо, мы сделали такой механизм у себя в сервисе структур
У меня делает Alter, что я делаю не так? :)
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.