将Hibernate代理转换为真实实体对象

And*_*gin 153 java proxy hibernate jpa lazy-loading

在Hibernate期间Session,我正在加载一些对象,并且由于延迟加载,其中一些被加载为代理.一切都好,我不想把懒人装完.

但后来我需要通过RPC将一些对象(实际上是一个对象)发送到GWT客户端.碰巧这个具体对象是代理.所以我需要把它变成一个真实的对象.我在Hibernate中找不到类似"实现"的方法.

如何知道他们的类和ID,将一些对象从代理转换为实际?

目前,我看到的唯一解决方案是从Hibernate的缓存中驱逐该对象并重新加载它,但由于许多原因它真的很糟糕.

Boz*_*zho 227

这是我正在使用的方法.

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 你可以在没有自己的util类的情况下做同样的事情 - `````(T)Hibernate.unproxy(entity)``` (4认同)

Vla*_*cea 32

正如我在本文中解释的那样,自Hibernate ORM 5.2.10以来,你可以这样做:

Object unproxiedEntity = Hibernate.unproxy(proxy);
Run Code Online (Sandbox Code Playgroud)

在Hibernate 5.2.10之前.最简单的方法是使用Hibernate内部实现提供的unproxy方法PersistenceContext:

Object unproxiedEntity = ((SessionImplementor) session)
                         .getPersistenceContext()
                         .unproxy(proxy);
Run Code Online (Sandbox Code Playgroud)

  • 仅初始化给定的代理。它不会级联到关联,因为如果您碰巧取消代理根实体,可能会加载大量数据。 (2认同)

小智 13

我编写了以下代码来清除代理中的对象(如果它们尚未初始化)

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());
    }

}
Run Code Online (Sandbox Code Playgroud)

我在RPC服务的结果(通过方面)上使用此函数,并且它从代理中递归清除所有结果对象(如果它们未初始化).


小智 12

尝试使用 Hibernate.getClass(obj)

  • 这将返回类而不是deproxied对象本身 (15认同)
  • 实际上,当我们试图找到 obj 的类进行实例比较时,这个解决方案非常有用。 (3认同)

小智 8

我推荐JPA 2的方式:

Object unproxied  = entityManager.unwrap(SessionImplementor.class).getPersistenceContext().unproxy(proxy);
Run Code Online (Sandbox Code Playgroud)

  • 你的答案与我的不同之处是什么? (2认同)

O.B*_*adr 6

Hiebrnate 5.2.10开始,您可以使用Hibernate.proxy方法将代理转换为真实实体:

MyEntity myEntity = (MyEntity) Hibernate.unproxy( proxyMyEntity );
Run Code Online (Sandbox Code Playgroud)