我从服务器收到以下错误响应。
HTTP 状态 500 -
类型异常报告
信息
说明服务器遇到内部错误 (),导致它无法完成此请求。
例外
javax.servlet.ServletException:java.lang.UnsupportedOperationException:尝试序列化 java.lang.Class:org.hibernate.proxy.HibernateProxy。忘记注册类型适配器?
根本原因
java.lang.UnsupportedOperationException:尝试序列化 java.lang.Class:org.hibernate.proxy.HibernateProxy。忘记注册类型适配器?
从 Java 调试器:
org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer@7632012e
我正在使用 Gson 将我的 Java 对象转换为 JSON。下面我粘贴了一些我的代码。
这是我的资源:
@Stateless
@LocalBean
@Path("/autos")
@Produces(MediaType.APPLICATION_JSON)
public class AutoResource {
@EJB
private CarAssembler warehouse;
@Context
private UriInfo uriInfo;
@GET
public Response allAutos() {
// Building a context, lots of code...
// Creating a Gson instance and configures it...
final Auto auto = warehouse.list(context);
final String autoJson = gson.toJson(auto);
return Response.ok(autoJson).build();
}
}
CarAssembler 只是一个调用存储库的服务。我没有在这里粘贴服务的代码。
存储库:
@Override
public Question findById(final int id, final FetchType fetchType) {
final Auto question = getEntityManager().find(Auto.class, id);
if (fetchType == FetchType.LAZY) {
return auto;
}
Hibernate.initialize(auto.getManufacturer());
Hibernate.initialize(auto.getAssemblyHouse());
return auto;
}
如您所见,我提供了对象的延迟加载和急切加载。我使用 Hibernate.initialize 来渴望获取 JPA 关联。但是,问题是如何修复我收到的代理错误。为什么只有 AssemblyHouse 仍然附加到 JavaAssist,而 Manufacturer 不是(我在 Java Debugger 中看到过这种类型)。我怎么知道什么时候取消代理对象?我应该取消代理这辆车可能拥有的所有关联吗?在我的代码的哪一层?当我取消代理时,它会影响我的应用程序的性能吗?还有其他解决方案吗?我从错误消息中看到我可以制作一个类型适配器。是的,我可以,但我必须对所有域对象都这样做,以确保正确完成转换。当我也尝试将其转换为 JSON 表示时,我域中的其他对象可能开始失败,但我不知道何时或为何。其他对象都没事只是运气好吗?
这是我取消代理对象的方式,但我还没有实现它,因为我不知道这是好是坏,也不知道在什么层做这个,我应该什么时候做。我应该一直取消代理对象吗?
public class HibernateUtilities {
public static <T> T unproxy(T proxy) {
if (proxy == null) {
return null;
}
if (proxy instanceof HibernateProxy) {
Hibernate.initialize(proxy);
HibernateProxy hibernateProxy = (HibernateProxy) proxy;
T unproxiedObject = (T) hibernateProxy.getHibernateLazyInitializer().getImplementation();
return unproxiedObject;
}
return proxy;
}
}
根据要求进行堆栈跟踪:
[#|2012-11-22T17:17:13.285+0100|警告|glassfish3.1.2|javax.enterprise.system.container.web.com.sun.enterprise.web|_ThreadID=71;_ThreadName=Thread-8;| StandardWrapperValve[javax.ws.rs.core.Application]:
PWC1406:servlet javax.ws.rs.core.Application 的 Servlet.service()
抛出异常 java.lang.UnsupportedOperationException:试图
序列化 java.lang.Class: org.hibernate.proxy.HibernateProxy。忘记
注册类型适配器?
在 com.google.gson.internal.bind.TypeAdapters$1.write(TypeAdapters.java:64)
在 com.google.gson.internal.bind.TypeAdapters$1.write(TypeAdapters.java:61)
在 com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
在 com.google.gson.internal.bind.ArrayTypeAdapter.write(ArrayTypeAdapter.java:93)
在 com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
在 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
在 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
在 com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
在 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
在 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
在 com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
在 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
在 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
在 com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
在 com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:96)
在 com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:60)
在 com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
在 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
在 com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
在 com.google.gson.Gson.toJson(Gson.java:586)
在 com.google.gson.Gson.toJson(Gson.java:565)
在 com.google.gson.Gson.toJson(Gson.java:520)
在 com.myapp.AutoResource.produceAuto(AutoResource.java:48)
在 sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)
在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
在 java.lang.reflect.Method.invoke(Method.java:601)
在 org.glassfish.ejb.security.application.EJBSecurityManager.runMethod (EJBSecurityManager.java:1052)
在 org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1124)
在 com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:5388)
在 com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:619)
在 com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:800)
在 com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:571)
在 com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doAround(SystemInterceptorProxy.java:162)
在 com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke(SystemInterceptorProxy.java:144)
在 sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)
在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
在 java.lang.reflect.Method.invoke(Method.java:601)
在 com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:861)
在 com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:800)
在 com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:370)
在 com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:5360)
在 com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:5348)
在 com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:214)
在 com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:89)
在 sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)
在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
在 java.lang.reflect.Method.invoke(Method.java:601)
在 com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
在 com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:205)
在 com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
在 com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)
在 com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
在 com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
在 com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
在 com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1469)
在 com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1400)
在 com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349)
在 com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339)
在 com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)
在 com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
在 com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:708)
在 javax.servlet.http.HttpServlet.service(HttpServlet.java:770)
在 org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550)
在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
在 org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:175)
在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java)
在 org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
在 org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
在 org.apache.catalina.core.StandardHostValve.__invoke(StandardHostValve.java:161)
在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java)
在 org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
在 com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
在 com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
在 com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
在 com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
在 com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
在 com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
在 com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
在 com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
在 com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
在 com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
在 com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
在 com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
在 com.sun.grizzly.ContextTask.run(ContextTask.java:71)
在 com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
在 com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
在 java.lang.Thread.run(Thread.java:722) |#]
原文由 Andreas 发布,翻译遵循 CC BY-SA 4.0 许可协议
您可以通过使用自定义
TypeAdapter
手动解除所有代理。沿着这些线的东西:要使用它,您必须先注册它:
请注意,这将递归地初始化对象层次结构中的每个代理;但是,由于您必须序列化整个数据,所以无论如何您都应该这样做。
这是如何运作的?
GSON 包含许多
TypeAdapterFactory
实现,用于各种类型(原始类型,常见类型,如String
或Date
,b6… 列表,数组—)。每个工厂都被询问是否能够序列化某种 Java 类型(参数create
是一个TypeToken
而不是Class
以捕获可能的信息关于泛型类型,Class
没有)。如果工厂能够序列化/反序列化一个类型,它会响应TypeAdapter
实例;否则它会响应null
。HibernateProxyTypeAdapter.FACTORY
验证 类型 是否实现HibernateProxy
;在这种情况下,它返回一个实例HibernateProxyTypeAdapter
用于序列化。write
方法在实际对象必须被序列化时被调用;适配器提取底层对象的原始类型,并向 GSON 询问原始类型的标准TypeAdapter
,通常是ReflectiveTypeAdapter
。然后它检索原始类的实例,而不是直接使用代理。这是必要的,因为
ReflectiveTypeAdapter
直接访问字段,而不是使用 getter;访问代理对象的字段是行不通的,这是一个经典的 Hibernate 陷阱。作为可能的性能改进,委托
TypeAdapter
应该在create
方法中获取。我发现在代理上调用getSuperclass()
Class
似乎产生原始基类。然后代码可以变成: