我从服务器收到以下错误响应。
HTTP状态500 -
类型异常报表
讯息
描述服务器遇到内部错误(),导致无法完成此请求.
例外情况
javax.servlet.ServletException:异常错误:尝试序列化java.lang.Class:忘记注册类型适配器了吗?
根本原因
异常错误:尝试序列化java.lang.Class:忘记注册类型适配器了吗?
从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中见过该类型)。我如何知道何时取消代理对象?我应该取消代理该auto可能具有的所有关联吗?在我的代码的哪一层?当我取消代理时,是否会影响我的应用程序的性能?是否有其他解决方案?我从错误消息中看到,我可以创建一个类型适配器。是的,我可以,但之后我必须对所有域对象都这样做,以确保转换正确完成。也许当我尝试将域转换为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|WARNING|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.service() for servlet javax.ws.rs.core.Application
threw exception java.lang.UnsupportedOperationException: Attempted to
serialize java.lang.Class: org.hibernate.proxy.HibernateProxy. Forgot
to register a type adapter?
at com.google.gson.internal.bind.TypeAdapters$1.write(TypeAdapters.java:64)
at com.google.gson.internal.bind.TypeAdapters$1.write(TypeAdapters.java:61)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ArrayTypeAdapter.write(ArrayTypeAdapter.java:93)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:96)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:60)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
at com.google.gson.Gson.toJson(Gson.java:586)
at com.google.gson.Gson.toJson(Gson.java:565)
at com.google.gson.Gson.toJson(Gson.java:520)
at com.myapp.AutoResource.produceAuto(AutoResource.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.glassfish.ejb.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1052)
at org.glassfish.ejb.security.application.EJBSecurityManager.invoke(EJBSecurityManager.java:1124)
at com.sun.ejb.containers.BaseContainer.invokeBeanMethod(BaseContainer.java:5388)
at com.sun.ejb.EjbInvocation.invokeBeanMethod(EjbInvocation.java:619)
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:800)
at com.sun.ejb.EjbInvocation.proceed(EjbInvocation.java:571)
at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.doAround(SystemInterceptorProxy.java:162)
at com.sun.ejb.containers.interceptors.SystemInterceptorProxy.aroundInvoke(SystemInterceptorProxy.java:144)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.sun.ejb.containers.interceptors.AroundInvokeInterceptor.intercept(InterceptorManager.java:861)
at com.sun.ejb.containers.interceptors.AroundInvokeChainImpl.invokeNext(InterceptorManager.java:800)
at com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:370)
at com.sun.ejb.containers.BaseContainer.__intercept(BaseContainer.java:5360)
at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:5348)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:214)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:89)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:205)
at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75)
at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:288)
at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108)
at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147)
at com.sun.jersey.server.impl.uri.rules.RootResourceClassesRule.accept(RootResourceClassesRule.java:84)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1469)
at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1400)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349)
at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339)
at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:708)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:770)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1550)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
at org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
at org.apache.catalina.core.StandardHostValve.__invoke(StandardHostValve.java:161)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:860)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:757)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1056)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:229)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:722) |#]
7条答案
按热度按时间wwtsj6pe1#
您可以使用自定义的
TypeAdapter
来完成所有操作,而无需手动取消代理。要使用它,您必须先注册它:
请注意,这将递归地初始化对象层次结构中的每个代理;因为无论如何,您都必须序列化整个数据,所以无论如何都应该这样做。
"这是怎么回事"
GSON包含许多
TypeAdapterFactory
实现,用于各种类型(基元类型、String
或Date
等常见类型、列表、数组...)。(create
的参数是TypeToken
而不是Class
,以便捕获关于泛型类型的可能信息,Class
不具有的类型)。如果工厂能够串行化/反串行化类型,则它用TypeAdapter
示例来响应;否则它以null
响应。HibernateProxyTypeAdapter.FACTORY
验证 type 是否实现HibernateProxy
;在这种情况下,它返回一个HibernateProxyTypeAdapter
的示例以进行序列化。该适配器提取底层对象的原始类型,并向GSON请求原始类型的标准TypeAdapter
,通常为ReflectiveTypeAdapter
。然后它检索原始类的一个示例,而不是直接使用代理。这是必要的,因为
ReflectiveTypeAdapter
访问directly to fields,而不是使用getter;访问被代理对象的字段是不起作用的,并且是典型的Hibernate pitfall。作为一种可能的性能改进,应该在
create
方法中获取委托TypeAdapter
。我发现在代理Class
上调用getSuperclass()
似乎会产生原始基类。然后代码可以变成:np8igboo2#
既然您提到了错误在快速加载时仍然存在,那么问题可能不是Hibernate的问题,而是GSON实现的问题。我认为在创建JSON时需要一个Type,不确定它是否已注册,但可能是这样的:
然后创建一个AdapterClass,例如:
iswrvxsc3#
在通常情况下,您不希望域对象通过服务以XML/JSON的形式公开,通常您需要创建一个DTO,因为您的实体不适合您的消费者的需要。而且即使它现在适合,在内部重构数据库之后,它也不适合明天。所以我的建议是,如果您遇到这样的麻烦,现在就创建DTO。顺便说一句,您甚至可以通过使用结果转换器或创建视图并将Hibernate实体Map到这些视图来在Hibernate级别上创建这些DTO。
另一个技巧是使用Dozer,以便将所需的字段复制到另一个类(实际上是 * 相同 * 的类,但没有代理)。
注意:您使用的是Gson,它访问您的 * 字段 *,而不是访问器,这使得它无法与Hibernate代理一起工作,因为它将尝试访问代理本身的字段,这些字段总是
null
。5m1hhzi44#
是的,你可以一直取消代理,如果它有一个Hibernate代理(它不会序列化),它会消失,并被实际的底层实现所取代,或者它会让类保持原样,并给予你一个实现。我认为你的解决方案应该工作得很好。提醒你一下,我真的不怎么使用Hibernate,但它对我来说确实有意义。
另一方面,您可能更信任Hibernate,但更简单的方法可能是:
此解决方案不应给予已实现/已初始化的类,而只提供类,或者该函数应由以下项提供:
我相信后者可能会返回超类,所以您可能会从Hibernate.getClass(obj)开始;
同时:
上述代码借用自:Converting Hibernate proxy to real object的变量名可能更好,因为它们并不意味着实体总是一个代理。此外,它会抛出一个异常来警告你,但这取决于你是否想要这个异常。
当然,您也可以摆脱懒惰负载,但我不认为这是最好的解决方案。
iugsix8n5#
尝试通过ObjectMapper解析为
06odsfpq6#
当我遇到这个问题的时候,我遇到了这个帖子,它为我的情况指出了正确的方向。我意识到我不需要序列化整个实体,特别是因为我已经标记了一些字段为惰性加载。所以我试图找到一种方法来跳过这些字段,ExclusionStrategy是神奇的。这似乎解决了我的问题
然后我将这个类应用到GsonBuilder,如下所示:
kiayqfof7#
另一个选择是创建Expose only字段,您希望通过使用
@Expose
注解将其序列化为JSON。这样,您就可以避免序列化Hibernate代理(如果这样的序列化对您来说足够)。在Hibernate实体中注解字段:
并以下列方式调用JSON序列化:
显然,这个方法只在你需要序列化非Hibernate代理的字段时有用,但对于这种情况,它是一个简单的解决方案,不需要创建自定义的TypeAdapter。