Преобразование Hibernate proxy в реальный объект без перезагрузки
Быстрый ответ
Для преобразования прокси Hibernate в реальный объект используйте функцию Hibernate.unproxy()
:
import org.hibernate.Hibernate;
// ...
YourEntityClass proxyEntity = // Получение прокси-объекта
// Раскрытие реального объекта
YourEntityClass realEntity = (YourEntityClass) Hibernate.unproxy(proxyEntity);
Учитывайте, что эту операцию необходимо проводить в контексте открытой сессии Hibernate, иначе может произойти исключение LazyInitializationException
.
Подробности преобразования прокси
Краткое решение, представленное выше, позволяет быстро добраться до сути. Теперь же давайте углубимся в детали и посмотрим, что происходит под капотом.
Ручная инициализация прокси
Метод Hibernate.unproxy()
появился не сразу. До его появления мы использовали Hibernate.initialize()
, который загружает все связанные данные сущности.
// Проверка, является ли объект прокси
if (proxyEntity != null && !Hibernate.isInitialized(proxyEntity)) {
Hibernate.initialize(proxyEntity); // Инициализация объекта
}
YourEntityClass realEntity = (YourEntityClass) proxyEntity;
Работа с прокси-сущностями
Прокси-сущности на первый взгляд не отличаются от обычных, однако внутри они устроены иначе. Чтобы узнать истинный класс за прокси:
Class<?> realClass = Hibernate.getClass(proxyEntity); // Определение реального класса объекта
Применение EntityManager
Hibernate.unproxy()
может быть недоступен из-за каких-то причин. В таких случаях можно воспользоваться EntityManager
:
SessionImplementor sessionImplementor = entityManager.unwrap(SessionImplementor.class);
YourEntityClass realEntity = (YourEntityClass) sessionImplementor.getPersistenceContext().unproxy(proxyEntity);
Управление постоянными коллекциями
Постоянные коллекции типов PersistentBag
и PersistentList
требуют отдельного внимания. Преобразуйте их в LinkedHashSet
для избавления от дубликатов и сохранения порядка элементов:
if (proxyEntity instanceof PersistentCollection) {
PersistentCollection collection = (PersistentCollection) proxyEntity;
return new LinkedHashSet<>(collection); // Управление коллекцией
}
Визуализация
Прокси Hibernate можно представить в виде флеш-накопителя, на котором есть ярлык, указывающий на файл.
Hibernate Proxy (💾): [Ярлык 📄]
"Распаковка" прокси сравнима со следованием по ярлыку к полноценному файлу:
🔄 Распаковка Прокси (💾➡️📄):
1. Вставляем накопитель (вызываем метод на прокси)
2. Следуем по ярлыку (инициируем объект)
3. Доступ к файлу открыт (получаем реальную сущность)
В результате помимо ярлыка у вас появляется полноценный документ.
Продвинутые методы преобразования прокси
С прокси нужно обращаться осторожно – в них могут скрываться сюрпризы. Рассмотрим более продвинутые способы работы с ними.
Рекурсивное преобразование прокси
Иногда работа с вложенными прокси напоминает бесконечное зеркальное отражение. В таких случаях уместен рекурсивный подход:
public Object unproxyDeeply(Object proxyEntity) {
if (proxyEntity instanceof HibernateProxy) {
// Рекурсивное раскрытие прокси
return unproxyDeeply(((HibernateProxy) proxyEntity).getHibernateLazyInitializer().getImplementation());
}
if (proxyEntity instanceof PersistentCollection) {
// Преобразование в обычную коллекцию данных
return new LinkedHashSet<>(((PersistentCollection) proxyEntity));
}
return proxyEntity; // Объект без проксирования
}
Проверка на null для стабильности
Проверяйте объекты на null, чтобы избежать попыток инициализации несуществующих данных:
if (proxyEntity != null) {
// Здесь может производиться раскрытие прокси
}
Преимущества использования кеша
"Вытаскивание" данных из кеша звучит приятно, однако лучше использовать unproxy()
, чтобы данные оставались в кеше:
// Хороший тон: данные всегда под рукой, в кеше
YourEntityClass realEntity = (YourEntityClass) Hibernate.unproxy(proxyEntity);
Полезные материалы
- Hibernate (Hibernate Javadocs) — Документация по преобразованию Hibernate Proxy в реальный объект.
- Преобразование прокси Hibernate в реальный объект сущности – Stack Overflow — Обсуждение практик раскрытия прокси.
- Антипаттерн "открытая сессия" – Vlad Mihalcea — Размышления о вредоносных паттернах открытой сессии и их влиянии на прокси.
- Руководство пользователя Hibernate ORM — Подробный анализ прокси в Hibernate.
- Учебник | DigitalOcean — Особенности жадной и ленивой загрузки в Hibernate.
- Подробное руководство по реализации equals() и hashCode() в Hibernate — Об отсоединении и присоединении сущностей при работе с прокси.