在Hibernate期间Session,我正在加载一些对象,由于延迟加载,它们中的一些已作为代理加载。一切正常,我不想关闭延迟加载。
但是稍后我需要通过RPC将一些对象(实际上是一个对象)发送到GWT客户端。碰巧这个具体对象是代理。所以我需要将其变成一个真实的对象。我在Hibernate中找不到类似“实现”的方法。
我如何才能将某些对象从代理变为真实,从而知道它们的类和ID?
目前,我看到的唯一解决方案是从Hibernate的缓存中逐出该对象并重新加载它,但是由于许多原因,它确实很糟糕。
在Hibernate期间Session,我正在加载一些对象,由于延迟加载,它们中的一些已作为代理加载。一切正常,我不想关闭延迟加载。
但是稍后我需要通过RPC将一些对象(实际上是一个对象)发送到GWT客户端。碰巧这个具体对象是代理。所以我需要将其变成一个真实的对象。我在Hibernate中找不到类似“实现”的方法。
我如何才能将某些对象从代理变为真实,从而知道它们的类和ID?
目前,我看到的唯一解决方案是从Hibernate的缓存中逐出该对象并重新加载它,但是由于许多原因,它确实很糟糕。
Answers:
这是我正在使用的方法。
public static <T> 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;
}HibernateProxy定义了writeReplace一种强制实现者在序列化过程中执行特殊操作的方法。
                    (T)Hibernate.unproxy(entity)
                    正如我在本文中所解释的,从Hibernate ORM 5.2.10开始,您可以像这样进行操作:
Object unproxiedEntity = Hibernate.unproxy(proxy);休眠之前5.2.10。最简单的方法是使用Hibernate内部实现提供的unproxy方法PersistenceContext:
Object unproxiedEntity = ((SessionImplementor) session)
                         .getPersistenceContext()
                         .unproxy(proxy);Departmentwith的List Student,是否还需要unproxy(department.getStudents())  -还是足够unproxy(department)?
                    PersistentContext#unproxy(proxy),如果一段时间未初始化代理,则会引发异常,Hibernate.unproxy(proxy)并LazyInitializer#getImplementation(proxy)在必要时初始化代理。由于这种差异,刚刚发现了一个例外。;-)
                    我编写了下面的代码,从代理中清除对象(如果尚未初始化)
public class PersistenceUtils {
    private static void cleanFromProxies(Object value, List<Object> 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> T cleanFromProxies(T value) {
        T result = unproxyObject(value);
        cleanFromProxies(result, new ArrayList<Object>());
        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> 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 <T> Set<T> unproxyPersistentSet(Map<T, ?> persistenceSet) {
        return new LinkedHashSet<T>(persistenceSet.keySet());
    }
}我在RPC服务的结果上使用此函数(通过方面),并且它递归地从代理中清除所有结果对象(如果未初始化)。
尝试使用 Hibernate.getClass(obj)
我推荐使用JPA 2的方式:
Object unproxied  = entityManager.unwrap(SessionImplementor.class).getPersistenceContext().unproxy(proxy);通过Spring Data JPA和Hibernate,我使用的是 JpaRepository查找属于使用“连接”策略映射的类型层次结构的对象。不幸的是,查询返回的是基本类型的代理,而不是预期的具体类型的实例。这使我无法将结果转换为正确的类型。像您一样,我来到这里寻找一种有效的方法来使我的实体不受约束。
弗拉德(Vlad)有正确的想法来消除这些结果。Yannis提供了更多细节。除了他们的答案,这是您可能需要的其余内容:
以下代码提供了一种简单的方法来取消代理实体的代理:
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> Type unproxy(Type proxied, Class<Type> type) {
        PersistenceContext persistenceContext =
            jpaContext
            .getEntityManagerByManagedType(type)
            .unwrap(SessionImplementor.class)
            .getPersistenceContext();
        Type unproxied = (Type) persistenceContext.unproxyAndReassociate(proxied);
        return unproxied;
    }
}您可以将未代理的实体或代理的实体传递给该unproxy方法。如果它们已经不被代理,则将它们简单地退回。否则,它们将被取消代理并返回。
希望这可以帮助!
另一个解决方法是致电
Hibernate.initialize(extractedObject.getSubojbectToUnproxy());在关闭会话之前。
我找到了使用标准Java和JPA API取消对类进行代理的解决方案。使用休眠进行测试,但不需要休眠作为依赖项,并且应与所有JPA提供程序一起使用。
仅一项要求-修改父类(地址)并添加简单的辅助方法的必要条件。
总体思路:将辅助方法添加到返回自身的父类中。当在代理上调用方法时,它将把调用转发到真实实例并返回该真实实例。
实现要稍微复杂一些,因为hibernate意识到代理类会返回自身,并且仍然返回proxy而不是实际实例。解决方法是将返回的实例包装到一个简单的包装类中,该包装类的类型与实际实例不同。
在代码中:
class Address {
   public AddressWrapper getWrappedSelf() {
       return new AddressWrapper(this);
   }
...
}
class AddressWrapper {
    private Address wrappedAddress;
...
}要将地址代理转换为真实的子类,请使用以下命令:
Address address = dao.getSomeAddress(...);
Address deproxiedAddress = address.getWrappedSelf().getWrappedAddress();
if (deproxiedAddress instanceof WorkAddress) {
WorkAddress workAddress = (WorkAddress)deproxiedAddress;
}从Hiebrnate 5.2.10开始,您可以使用Hibernate.proxy方法将代理转换为您的真实实体:
MyEntity myEntity = (MyEntity) Hibernate.unproxy( proxyMyEntity );感谢您提出的解决方案!不幸的是,它们都不适合我的情况:使用本机查询通过JPA-Hibernate从Oracle数据库接收CLOB对象的列表。
所有建议的方法都给了我ClassCastException或刚刚返回的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();
}希望这会帮助到别人!