我从服务器收到以下错误响应。
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。忘记注册类型适配器?
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,而制造商却没有(我已经在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; } }
根据要求的Stacktrace:
[#| 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)|#]
您可以通过使用custom无需手动取消代理所有内容TypeAdapter。遵循以下原则:
TypeAdapter
/** * This TypeAdapter unproxies Hibernate proxied objects, and serializes them * through the registered (or default) TypeAdapter of the base class. */ public class HibernateProxyTypeAdapter extends TypeAdapter<HibernateProxy> { public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() { @Override @SuppressWarnings("unchecked") public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { return (HibernateProxy.class.isAssignableFrom(type.getRawType()) ? (TypeAdapter<T>) new HibernateProxyTypeAdapter(gson) : null); } }; private final Gson context; private HibernateProxyTypeAdapter(Gson context) { this.context = context; } @Override public HibernateProxy read(JsonReader in) throws IOException { throw new UnsupportedOperationException("Not supported"); } @SuppressWarnings({"rawtypes", "unchecked"}) @Override public void write(JsonWriter out, HibernateProxy value) throws IOException { if (value == null) { out.nullValue(); return; } // Retrieve the original (not proxy) class Class<?> baseType = Hibernate.getClass(value); // Get the TypeAdapter of the original class, to delegate the serialization TypeAdapter delegate = context.getAdapter(TypeToken.get(baseType)); // Get a filled instance of the original class Object unproxiedValue = ((HibernateProxy) value).getHibernateLazyInitializer() .getImplementation(); // Serialize the value delegate.write(out, unproxiedValue); } }
要使用它,您必须首先注册它:
GsonBuilder b = new GsonBuilder(); ... b.registerTypeAdapterFactory(HibernateProxyTypeAdapter.FACTORY); ... Gson gson = b.create();
注意,这将递归地初始化对象层次结构中的每个代理。但是由于您必须序列化整个数据,因此无论如何都应该这样做。
这是如何运作的?
GSON包含许多TypeAdapterFactory针对各种类型(原始类型,常见类型(例如String或)Date,列表,数组等)的实现。询问每个工厂是否能够序列化某种Java类型(参数to create是a TypeToken而不是a Class,以便捕获有关泛型的可能信息,而Class没有泛型)。如果工厂能够序列化/反序列化类型,则它会以一个TypeAdapter实例进行响应;否则它会以回应null。
TypeAdapterFactory
String
Date
create
TypeToken
Class
null
HibernateProxyTypeAdapter.FACTORY验证 类型 是否实现HibernateProxy; 在这种情况下,它将返回一个实例HibernateProxyTypeAdapter进行序列化。write当必须对实际对象进行序列化时,将调用该方法。适配器提取基础对象的原始类型,并向GSON询问TypeAdapter原始类型的标准,通常为ReflectiveTypeAdapter。
HibernateProxyTypeAdapter.FACTORY
HibernateProxy
HibernateProxyTypeAdapter
write
ReflectiveTypeAdapter
然后,它检索原始类的实例,而不是直接使用代理。这是必要的,因为直接ReflectiveTypeAdapter访问字段,而不是使用getters。访问代理对象的字段无效,这是经典的Hibernate陷阱。
作为可能的性能改进,TypeAdapter应在create方法中获取委托。我发现调用getSuperclass()代理Class似乎产生了原始基类。代码可以变成:
getSuperclass()
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() { @Override @SuppressWarnings("unchecked") public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { return (HibernateProxy.class.isAssignableFrom(type.getRawType()) ? (TypeAdapter<T>) new HibernateProxyTypeAdapter((TypeAdapter)gson.getAdapter(TypeToken.get(type.getRawType().getSuperclass()))) : null); } }; private final TypeAdapter<Object> delegate; private HibernateProxyTypeAdapter(TypeAdapter<Object> delegate) { this.delegate = delegate; } @SuppressWarnings({"rawtypes", "unchecked"}) @Override public void write(JsonWriter out, HibernateProxy value) throws IOException { if (value == null) { out.nullValue(); return; } delegate.write(out, ((HibernateProxy) value).getHibernateLazyInitializer() .getImplementation()); }