我正在尝试使用JAX-RS将对象公开为XML。
我有一个名为Client
的类,我将返回它的实例:
@Transactional(readOnly=true)
@GET
@Produces("application/xml")
@Path("/{clientId}.xml")
public Client getCleintAsXML(@PathParam("clientId") int clientId) {
Client c = em.find(Client.class, clientId);
return c;
}
但是Client
对象有一个Group
对象列表,而Group
对象又有其他对象列表。
当JAX-RS尝试序列化Client
对象时,它会遍历整个对象图。当它为groups
生成Hibernate代理时,代码会中断,因为延迟加载仅在事务内部起作用。
很公平,所以我在退出交易之前急切地加载groups
。
但它仍然失败,因为每个Group
对象依次具有一对多关系,即更多代理列表。
我在输出中甚至不需要它们。我意识到如果删除这些代理,即设置为null,我的问题就会得到解决。
我不想手动将它们设置为null,因为这容易出错且无法维护。有没有办法自动执行此操作?
或者,我可以告诉hibernate不使用此特定查询的代理吗?或者只使用1级深度的代理?
我在JPA后面使用Hibernate。我希望尽可能不直接引用Hibernate。
我找到了不同用户编写的十几个类来摆脱代理。有没有标准的方法来做到这一点?如果这是一个常见的问题,我猜,会有一个标准的解决方案。
答案 0 :(得分:0)
通过删除未初始化的hibernate代理解决了这个问题。这只删除了我的要求。随意为其他用户提供修改建议。
首先剪切:
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import org.apache.commons.beanutils.PropertyUtils;
import org.hibernate.Hibernate;
import org.hibernate.collection.PersistentCollection;
import org.springframework.beans.BeanUtils;
public class HibernateProxyCleaner {
public static Object clean(Object bean) {
return clean(bean,0,2);
}
public static Object clean(Collection bean, int depth, int maxDepth) {
if (bean == null || depth>maxDepth)
return bean;
for (Object o : (Collection) bean) {
clean(o,depth,maxDepth);
}
return bean;
}
public static Object clean(Object bean, int depth, int maxDepth) {
if (bean == null || depth>maxDepth)
return bean;
try {
PropertyDescriptor[] pda = BeanUtils.getPropertyDescriptors(bean
.getClass());
for (PropertyDescriptor pd : pda) {
Object o = PropertyUtils.getProperty(bean, pd.getName());
if (o != null) {
if (o instanceof PersistentCollection) {
if (PropertyUtils.isReadable(bean, pd.getName()) && PropertyUtils.isWriteable(bean, pd.getName())) {
if (!Hibernate.isInitialized((PersistentCollection) o)) {
o = null;
PropertyUtils.setProperty(bean, pd.getName(), o);
}
}
} else {
clean(o,depth+1,maxDepth);
}
}
}
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return bean;
}
}