[java] Hibernate 프록시를 실제 엔티티 객체로 변환하는 방법

최대 절전 모드 Session에서 일부 객체를로드하고 있으며 일부는 지연로드로 인해 프록시로로드됩니다. 괜찮습니다. 게으른 로딩을 끄고 싶지 않습니다.

그러나 나중에 RPC를 통해 일부 객체 (실제로 하나의 객체)를 GWT 클라이언트에 보내야합니다. 그리고이 구체적인 객체는 프록시입니다. 그래서 나는 그것을 실제 물체로 바꿔야합니다. Hibernate에서 “materialize”와 같은 방법을 찾을 수 없습니다.

프록시에서 클래스 및 ID를 알고있는 객체로 일부 객체를 전환하려면 어떻게해야합니까?

현재 내가 볼 수있는 유일한 해결책은 Hibernate의 캐시에서 해당 객체를 제거하고 다시로드하는 것이지만 여러 가지 이유로 실제로 나쁩니다.



답변

여기 내가 사용하는 방법이 있습니다.

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


답변

이 기사 에서 설명했듯이 Hibernate ORM 5.2.10 부터 다음과 같이 할 수 있습니다.

Object unproxiedEntity = Hibernate.unproxy(proxy);

최대 절전 모드 전에 5.2.10 . 가장 간단한 방법 은 Hibernate 내부 구현에서 제공 하는 unproxy 메소드 를 사용하는 PersistenceContext것입니다.

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


답변

사용하려고 Hibernate.getClass(obj)


답변

프록시에서 객체를 정리하는 다음 코드를 작성했습니다 (아직 초기화되지 않은 경우)

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 서비스의 결과 (측면을 통해)에 사용하고 프록시에서 모든 결과 객체를 재귀 적으로 정리합니다 (초기화되지 않은 경우).


답변

JPA 2에서 권장하는 방법 :

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


답변

Spring Data JPA와 Hibernate에서는 하위 인터페이스를 사용했습니다. JpaRepository 사용하여 “join”전략을 사용하여 매핑 된 유형 계층 구조에 속하는 객체를 검색했습니다. 불행히도 쿼리는 예상되는 구체적인 유형의 인스턴스 대신 기본 유형의 프록시를 반환했습니다. 이로 인해 결과를 올바른 유형으로 캐스팅하지 못했습니다. 당신처럼, 나는 내 유물을 프록시하지 않는 효과적인 방법을 찾기 위해 여기에 왔습니다.

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

세션을 닫기 직전에