在一个Hibernate Session
,我加载某些对象,其中一些被加载,因为延迟加载代理。 这是一切OK,我不希望把延迟加载关闭。
但后来我需要通过RPC发送一些对象(实际上是一个对象),将GWT客户端。 和它发生,这种具体的对象是一个代理。 所以,我需要把它变成一个真正的对象。 我找不到在休眠的方法等“兑现”。
我怎样才能把一些从代理到雷亚尔知道自己的等级和ID的对象呢?
此刻,我看到的唯一的解决办法是驱逐出Hibernate的缓存对象,并重新加载它,但它是非常糟糕的原因是多方面的。
Answer 1:
下面是我使用的方法。
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;
}
Answer 2:
正如我在解释这篇文章 ,因为Hibernate ORM 5.2.10,你能做到这likee:
Object unproxiedEntity = Hibernate.unproxy( proxy );
Hibernate的5.2.10之前。 要做到这一点最简单的方法是使用unproxy由Hibernate内部提供的方法PersistenceContext
实现:
Object unproxiedEntity = ((SessionImplementor) session)
.getPersistenceContext()
.unproxy(proxy);
Answer 3:
我已经写了下面的代码从代理清除对象(如果它们尚未初始化)
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服务(通过方面),并递归清理从代理的所有结果对象(如果它们不会被初始化)。
Answer 4:
尝试使用Hibernate.getClass(obj)
Answer 5:
我建议使用JPA 2的方式:
Object unproxied = entityManager.unwrap(SessionImplementor.class).getPersistenceContext().unproxy(proxy);
Answer 6:
随着春天的数据JPA和Hibernate,我用的子接口JpaRepository
查找属于该用的是“加盟”策略映射一个类型层次的对象。 不幸的是,查询返回了基地型,而不是预期的具体类型的实例的代理。 这让我无法铸造结果为正确的类型。 和你一样,我来到这里找得到我的entites非代理的有效途径。
弗拉德有unproxying这些结果正确的观念; 雅尼斯提供更详细一点。 添加到自己的答案,这里是什么,你可能会寻找其他部分:
下面的代码提供了一个简单的方法来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> Type unproxy(Type proxied, Class<Type> type) {
PersistenceContext persistenceContext =
jpaContext
.getEntityManagerByManagedType(type)
.unwrap(SessionImplementor.class)
.getPersistenceContext();
Type unproxied = (Type) persistenceContext.unproxyAndReassociate(proxied);
return unproxied;
}
}
您可以通过其中的entites非代理或代理机构向unproxy
方法。 如果他们已经非代理,他们会简单地返回。 否则,他们将得到和非代理返回。
希望这可以帮助!
Answer 7:
另一个解决方法是调用
Hibernate.initialize(extractedObject.getSubojbectToUnproxy());
就在会议闭幕。
Answer 8:
我发现了一个解决方案使用标准的Java和JPA API来deproxy类。 与休眠测试,但不休眠需要作为一个依赖,并应与所有JPA提供商合作。
Onle一个要求 - 其需要修改父类(地址),并添加一个简单的辅助方法。
总体思路:添加辅助方法,它返回自己的父类。 当呼吁代理方法,它会调用转发到真正的实例,并返回这个现实的实例。
实现更复杂一点,因为休眠承认代理的类返回本身仍返回代理,而不是真正的实例。 解决方法是换行返回的实例为一个简单的包装类,它有不同的类类型比真实的实例。
在代码:
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;
}
Answer 9:
谢谢你的建议的解决方案! 不幸的是,他们没有工作了我的情况:从Oracle数据库通过JPA CLOB对象的列表 - 休眠,使用本机查询。
所有提出的方法给了我要么一个ClassCastException或刚刚回到Java代理对象(深内含有希望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();
}
希望这会帮助别人!
Answer 10:
从开始Hiebrnate 5.2.10你可以用Hibernate.proxy方法把代理转换到你的真正的实体:
MyEntity myEntity = (MyEntity) Hibernate.unproxy( proxyMyEntity );
文章来源: Converting Hibernate proxy to a real entity object