최대 절전 모드 프록시를 실제 엔티티 개체로 변환하는 방법
최대 절전 모드 중Session
나는 몇몇 물건을 싣고 있고, 그 중 일부는 게으른 짐 때문에 대리점으로 적재된다.다 괜찮아 그리고 나는 게으른 짐을 끄고 싶지 않아.
하지만 나중에 RPC를 통해 GWT 클라이언트에 일부 객체(실제로 하나의 객체)를 보내야 한다.그리고 이 구체적인 물체가 대리인이 되는 일이 일어난다.그래서 나는 그것을 진짜 물건으로 만들어야 해.나는 겨울잠에서 "물리화" 같은 방법을 찾을 수 없다.
클래스와 ID를 알고 있는 일부 객체를 프록시에서 리얼로 어떻게 변환할 수 있는가?
지금 내가 보는 유일한 해결책은 브라이버나이트의 캐시에서 그 물체를 꺼내고 다시 로드하는 것이지만, 그것은 여러 가지 이유로 정말 나쁘다.
여기 내가 사용하고 있는 방법이 있다.
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;
}
ORM 5.2.10을 최대 절전 모드로 전환하므로 다음과 같이 하십시오.
Object unproxiedEntity = Hibernate.unproxy(proxy);
최대 절전 모드 5.2.10. 가장 간단한 방법은 내부 절전 모드(Veatnates)에서 제공하는 언프록시 방법을 사용하는 것이었다.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);
Hiebrnat 5.2.10부터 Brievenat.proxy 방법을 사용하여 프록시를 실제 엔티티로 변환할 수 있다.
MyEntity myEntity = (MyEntity) Hibernate.unproxy( proxyMyEntity );
또 다른 해결책은 전화를 거는 것이다.
Hibernate.initialize(extractedObject.getSubojbectToUnproxy());
세션을 닫기 직전에.
Spring Data JPA 및 최대 절전 모드에서는 의 하위 인터페이스를 사용하고 있었다.JpaRepository
"일반" 전략을 사용하여 매핑된 유형 계층에 속하는 개체를 검색하십시오.불행하게도, 쿼리는 예상되는 콘크리트 유형의 인스턴스 대신 기본 유형의 프록시를 반환하고 있었다.이것은 내가 결과를 올바른 유형으로 결정하지 못하게 했다.너처럼, 난 여기 내 동료들을 체포할 효과적인 방법을 찾으려고 왔어
블라드는 이러한 결과를 증명할 수 있는 올바른 생각을 가지고 있다; 야니스는 좀 더 자세한 정보를 제공한다.고객의 답변에 덧붙여 다음과 같은 사항을 살펴보십시오.
다음 코드는 프록시 엔티티를 쉽게 해제할 수 있는 방법을 제공한다.
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
만약 받을 만약 그들이 이미 의심받지 않았다면, 그들은 간단히 되돌려 받을 것이다.그렇지 않으면, 그들은 체포되지 않고 돌아올 것이다.
이것이 도움이 되기를!
제안된 해결책 고마워!불행히도, 그 중 어느 것도 내 경우에 효과가 없었다. JPA - 최대 절전 모드를 통해 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();
}
이게 누군가에게 도움이 되길 바래!
나는 표준 자바와 JPA API를 사용하여 수업을 빼는 해결책을 찾았다.최대 절전 모드로 테스트되었지만 종속성으로 최대 절전 모드가 필요하지 않으며 모든 JPA 제공자와 함께 작업해야 한다.
Onle 하나의 요구사항 - 상위 클래스(Address)를 수정하고 간단한 도우미 방법을 추가하는 데 필요함.
일반 아이디어: 자신을 반환하는 부모 클래스에 도우미 메서드를 추가하십시오.메서드가 프록시를 호출하면 호출이 실제 인스턴스로 전달되고 이 실제 인스턴스가 반환된다.
최대 절전 모드에서는 프록시 클래스가 실제 인스턴스 대신 프록시를 반환한다는 것을 인식하고 있기 때문에 구현이 조금 더 복잡하다.해결 방법은 반환된 인스턴스를 실제 인스턴스와 클래스 유형이 다른 단순 래퍼 클래스로 포장하는 것이다.
코드:
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;
}
참조URL: https://stackoverflow.com/questions/2216547/how-to-convert-a-hibernate-proxy-to-a-real-entity-object
'IT이야기' 카테고리의 다른 글
C의 구조 메모리 레이아웃 (0) | 2022.05.18 |
---|---|
유니언 및 유형 퍼닝 (0) | 2022.05.18 |
C의 주 인수에 대한 인수 (0) | 2022.05.17 |
Vuex/Vues의 작업에서 다른 작업을 호출하는 방법 (0) | 2022.05.17 |
어떻게 비동기적으로 Vuetify 텍스트 필드를 확인하기 위해? (0) | 2022.05.17 |