Преобразование прокси-сервера Hibernate в объект реального объекта

Во время сеанса Hibernate я загружаю некоторые объекты, а некоторые из них загружаются как прокси-серверы из-за ленивой загрузки. Все в порядке, и я не хочу, чтобы ленивая загрузка.

Но позже мне нужно отправить некоторые объекты (фактически один объект) клиенту GWT через RPC. И бывает, что этот конкретный объект является прокси. Поэтому мне нужно превратить его в реальный объект. Я не могу найти такой метод, как «материализоваться» в Hibernate.

Как я могу перевернуть некоторые объекты из прокси-сервера в реалы, зная их class и идентификатор?

На данный момент единственным решением, которое я вижу, является выseleniumие этого объекта из кэша Hibernate и его перезагрузка, но это очень плохо по многим причинам.

Вот метод, который я использую.

public static  T initializeAndUnproxy(T entity) { if (entity == null) { throw new NullPointerException("Entity passed for initialization is null"); } Hibernate.initialize(entity); if (entity instanceof HibernateProxy) { entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer() .getImplementation(); } return entity; } 

Я написал следующий код, который очищает объект от прокси (если они еще не инициализированы)

 public class PersistenceUtils { private static void cleanFromProxies(Object value, List handledObjects) { if ((value != null) && (!isProxy(value)) && !containsTotallyEqual(handledObjects, value)) { handledObjects.add(value); if (value instanceof Iterable) { for (Object item : (Iterable) value) { cleanFromProxies(item, handledObjects); } } else if (value.getClass().isArray()) { for (Object item : (Object[]) value) { cleanFromProxies(item, handledObjects); } } BeanInfo beanInfo = null; try { beanInfo = Introspector.getBeanInfo(value.getClass()); } catch (IntrospectionException e) { // LOGGER.warn(e.getMessage(), e); } if (beanInfo != null) { for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) { try { if ((property.getWriteMethod() != null) && (property.getReadMethod() != null)) { Object fieldValue = property.getReadMethod().invoke(value); if (isProxy(fieldValue)) { fieldValue = unproxyObject(fieldValue); property.getWriteMethod().invoke(value, fieldValue); } cleanFromProxies(fieldValue, handledObjects); } } catch (Exception e) { // LOGGER.warn(e.getMessage(), e); } } } } } public static  T cleanFromProxies(T value) { T result = unproxyObject(value); cleanFromProxies(result, new ArrayList()); return result; } private static boolean containsTotallyEqual(Collection collection, Object value) { if (CollectionUtils.isEmpty(collection)) { return false; } for (Object object : collection) { if (object == value) { return true; } } return false; } public static boolean isProxy(Object value) { if (value == null) { return false; } if ((value instanceof HibernateProxy) || (value instanceof PersistentCollection)) { return true; } return false; } private static Object unproxyHibernateProxy(HibernateProxy hibernateProxy) { Object result = hibernateProxy.writeReplace(); if (!(result instanceof SerializableProxy)) { return result; } return null; } @SuppressWarnings("unchecked") private static  T unproxyObject(T object) { if (isProxy(object)) { if (object instanceof PersistentCollection) { PersistentCollection persistentCollection = (PersistentCollection) object; return (T) unproxyPersistentCollection(persistentCollection); } else if (object instanceof HibernateProxy) { HibernateProxy hibernateProxy = (HibernateProxy) object; return (T) unproxyHibernateProxy(hibernateProxy); } else { return null; } } return object; } private static Object unproxyPersistentCollection(PersistentCollection persistentCollection) { if (persistentCollection instanceof PersistentSet) { return unproxyPersistentSet((Map) persistentCollection.getStoredSnapshot()); } return persistentCollection.getStoredSnapshot(); } private static  Set unproxyPersistentSet(Map persistenceSet) { return new LinkedHashSet(persistenceSet.keySet()); } } 

Я использую эту функцию по результатам моих служб RPC (через аспекты) и рекурсивно ретуширует все объекты результатов из прокси (если они не инициализированы).

Попробуйте использовать Hibernate.getClass(obj)

Как я объяснил в этой статье , поскольку Hibernate ORM 5.2.10, вы можете сделать это следующим образом:

 Object unproxiedEntity = Hibernate.unproxy( proxy ); 

До спящего режима 5.2.10. Самый простой способ сделать это – использовать метод unproxy, предлагаемый внутренней реализацией PersistenceContext Hibernate:

 Object unproxiedEntity = ((SessionImplementor) session) .getPersistenceContext() .unproxy(proxy); 

Способ, которым я рекомендую использовать JPA 2:

 Object unproxied = entityManager.unwrap(SessionImplementor.class).getPersistenceContext().unproxy(proxy); 

С Spring Data JPA и Hibernate я использовал подинтерфейсы JpaRepository для поиска объектов, принадлежащих иерархии типов, которые были сопоставлены с использованием страtagsи объединения. К сожалению, запросы возвращали прокси базового типа вместо экземпляров ожидаемых конкретных типов. Это помешало мне привести результаты к правильным типам. Как и вы, я пришел сюда, пытаясь найти эффективный способ, чтобы мои собеседники не обвинялись.

У Влада есть правильная идея отказаться от этих результатов; Яннис дает немного более подробную информацию. Добавляя к своим ответам, остальное, что вы можете искать:

Следующий код обеспечивает простой способ unproxy для ваших проксированных объектов:

 import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.SessionImplementor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.jpa.repository.JpaContext; import org.springframework.stereotype.Component; @Component public final class JpaHibernateUtil { private static JpaContext jpaContext; @Autowired JpaHibernateUtil(JpaContext jpaContext) { JpaHibernateUtil.jpaContext = jpaContext; } public static  Type unproxy(Type proxied, Class type) { PersistenceContext persistenceContext = jpaContext .getEntityManagerByManagedType(type) .unwrap(SessionImplementor.class) .getPersistenceContext(); Type unproxied = (Type) persistenceContext.unproxyAndReassociate(proxied); return unproxied; } } 

Вы можете передать либо непрошеные entites, либо прокси-объекты в метод unproxy . Если они уже не заявлены, они просто будут возвращены. В противном случае они будут освобождены и возвращены.

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

Другим обходным решением является вызов

 Hibernate.initialize(extractedObject.getSubojbectToUnproxy()); 

Перед закрытием сессии.

Я нашел решение для депроксирования classа с использованием стандартных Java и JPA API. Протестировано спящим режимом, но не требует спящего режима в качестве зависимости и должно работать со всеми поставщиками JPA.

Единственное требование – его необходимо изменить родительский class (адрес) и добавить простой вспомогательный метод.

Общая идея: добавить вспомогательный метод к родительскому classу, который возвращает себя. когда метод называется прокси, он переадресует вызов в реальный экземпляр и возвращает этот реальный экземпляр.

Реализация немного сложнее, так как hibernate распознает, что прокси-class возвращает себя и все еще возвращает прокси вместо реального экземпляра. Обходным путем является перенос возвращаемого экземпляра в простой class-оболочку, который имеет другой тип classа, чем реальный экземпляр.

В коде:

 class Address { public AddressWrapper getWrappedSelf() { return new AddressWrapper(this); } ... } class AddressWrapper { private Address wrappedAddress; ... } 

Чтобы передать адресный прокси в настоящий подclass, используйте следующее:

 Address address = dao.getSomeAddress(...); Address deproxiedAddress = address.getWrappedSelf().getWrappedAddress(); if (deproxiedAddress instanceof WorkAddress) { WorkAddress workAddress = (WorkAddress)deproxiedAddress; } 

Благодарим вас за предлагаемые решения! К сожалению, ни один из них не работал для моего случая: получение списка объектов CLOB из базы данных Oracle через JPA – Hibernate с использованием собственного запроса.

Все предложенные подходы дали мне либо ClassCastException, либо только что возвращенный объект Java Java Proxy (который глубоко внутри содержал желаемый Clob).

Поэтому мое решение заключается в следующем (на основе нескольких вышеприведенных подходов):

 Query sqlQuery = manager.createNativeQuery(queryStr); List resultList = sqlQuery.getResultList(); for ( Object resultProxy : resultList ) { String unproxiedClob = unproxyClob(resultProxy); if ( unproxiedClob != null ) { resultCollection.add(unproxiedClob); } } private String unproxyClob(Object proxy) { try { BeanInfo beanInfo = Introspector.getBeanInfo(proxy.getClass()); for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) { Method readMethod = property.getReadMethod(); if ( readMethod.getName().contains("getWrappedClob") ) { Object result = readMethod.invoke(proxy); return clobToString((Clob) result); } } } catch (InvocationTargetException | IntrospectionException | IllegalAccessException | SQLException | IOException e) { LOG.error("Unable to unproxy CLOB value.", e); } return null; } private String clobToString(Clob data) throws SQLException, IOException { StringBuilder sb = new StringBuilder(); Reader reader = data.getCharacterStream(); BufferedReader br = new BufferedReader(reader); String line; while( null != (line = br.readLine()) ) { sb.append(line); } br.close(); return sb.toString(); } 

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

Начиная с Hiebrnate 5.2.10 вы можете использовать метод Hibernate.proxy для преобразования прокси в ваш реальный объект:

 MyEntity myEntity = (MyEntity) Hibernate.unproxy( proxyMyEntity ); 
Interesting Posts

Что предназначено для распространения с обновленным компьютером?

Windows 7: Дисковое пространство: windirstat показывает 88 ГБ: Windows показывает 143 ГБ

Папка продолжает меняться обратно в режим «только для чтения». Какая настройка разрешений вызывает это в Windows?

Проблема с регулярным выражением SCJP6

Как сделать автозапуск CD / DVD?

Я хочу, чтобы виртуализировать свою рабочую станцию ​​(уровень 1), искать гипервизор Bare Metal для компонентов потребительского класса

Обработка длинных списков редактирования в XMLStarlet

Как читать хорошо сформированный XML в Java, но пропустить схему?

Написание собственного контейнера STL

Как включить трассировку WCF?

Перенаправить на приложение, если оно установлено, иначе в App Store

Возможно ли передать аутентификацию из Webbrowser в WebRequest

Как добавить тип в белый список политики сериализации GWT?

HttpServletRequest – как получить ссылочный URL?

Можно ли указать номера JSON?

Давайте будем гением компьютера.