Недавно, увидев на Хабре пост про борьбу с lazy initialization в Hibernate, я заинтересовался – прочитал сам пост и ждал пока наберется побольше комментариев – не предложит ли кто-нибудь способ, которым данную проблему решили мы. Ничего похожего я не увидел. Способ под катом.
Опишу на примере. Допустим, есть сущность:
Мы хотим гарантировать, чтобы, когда представление этой сущности будет отправляться на клиент, список children был проинициализирован и, более того, не тянул за собой никаких Hibernate'овских подвязок. Для этого объявляем следующий интерфейс:
Именно такое представление и будет отправляться клиенту. Обратите внимание, что Person не реализует IPerson. И клиент вообще не знает о существовании Person. Для него существуют лишь только различные его представлени�� в виде интерфейсов. Проксирование выгладит так:
Как это работает? Метод ProxyFactory.getProxy() создает с помощью механизма динамических прокси имплементацию интерфейса IPerson, в хэндлере которого лежит Map со значениями полей. Для заполнения этого мэпа ProxyFactory читает рефлексией поля сущности examplePerson. Соответственно, когда на интерфейсе вызывается какой-нибудь геттер/cеттер хэндлер лезет в этот мэп.
Естественно, у сущности может быть несколько интерфейсов, а прокси могут содержать только часть полей. Для ситуации со списком (как в примере List<IPerson>) также можно конкретно указывать из каких прокси состоит список (например, List<IPersonOnlyWithName>).
Для того чтобы проверка интерфейсов прокси (что интерфейс действительно соответствует сущности) происходила на этапе компиляции для эклипса был написан простенький Ant-билдер, который проходит по проаннотированным следующим образом сущностям:
Данный подход доказал свою жизнеспособность на практике и оброс большим количеством разнообразных дополнений. Было бы интересно увидеть какую-нибудь конструктивную критику и комментарии.
Опишу на примере. Допустим, есть сущность:
@Entity public class Person { @Id private long id; private String firstName; private String lastName; @OneToMany private List<Person> children; // getters-setters }
Мы хотим гарантировать, чтобы, когда представление этой сущности будет отправляться на клиент, список children был проинициализирован и, более того, не тянул за собой никаких Hibernate'овских подвязок. Для этого объявляем следующий интерфейс:
public interface IPerson { public long getId(); public void setId(long id); // getters-setters for firstName/lastName public List<IPerson> getChildren(); public void setChildren(List<IPerson> children); }
Именно такое представление и будет отправляться клиенту. Обратите внимание, что Person не реализует IPerson. И клиент вообще не знает о существовании Person. Для него существуют лишь только различные его представлени�� в виде интерфейсов. Проксирование выгладит так:
Person examplePerson = getPersonFromDb(); IPerson personProxy = ProxyFactory.getProxy(IPerson.class, examplePerson);
Как это работает? Метод ProxyFactory.getProxy() создает с помощью механизма динамических прокси имплементацию интерфейса IPerson, в хэндлере которого лежит Map со значениями полей. Для заполнения этого мэпа ProxyFactory читает рефлексией поля сущности examplePerson. Соответственно, когда на интерфейсе вызывается какой-нибудь геттер/cеттер хэндлер лезет в этот мэп.
Естественно, у сущности может быть несколько интерфейсов, а прокси могут содержать только часть полей. Для ситуации со списком (как в примере List<IPerson>) также можно конкретно указывать из каких прокси состоит список (например, List<IPersonOnlyWithName>).
Для того чтобы проверка интерфейсов прокси (что интерфейс действительно соответствует сущности) происходила на этапе компиляции для эклипса был написан простенький Ant-билдер, который проходит по проаннотированным следующим образом сущностям:
@Entity @ProxyBinding(interfaceClass = IPerson.class) public class Person { // … }
Данный подход доказал свою жизнеспособность на практике и оброс большим количеством разнообразных дополнений. Было бы интересно увидеть какую-нибудь конструктивную критику и комментарии.
