Failed to serialize HibernateProxy object reason

I get the following error response from the server.

HTTP Status 500 -

Type of exception report

message

description The server detected an internal error () that prevented it from executing this request.

exceptions

javax.servlet.ServletException: java.lang.UnsupportedOperationException: attempt to serialize java.lang.Class: org.hibernate.proxy.HibernateProxy. Forgot to register type adapter?

The main reason

java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: org.hibernate.proxy.HibernateProxy. Forgot to register type adapter?

From the Java debugger:

org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer@7632012e 

I use Gson to convert Java objects to JSON. Below I have inserted some code.

This is my resource:

 @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 is just a service that calls a repository. I did not embed the service code here.

Repository:

 @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; } 

As you can see, I provide both lazy and impatient loading of objects. I use Hibernate.initialize to interest JPA associations. However, the question is how can I fix the proxy error that I get. Why only come AssemblyHouse, which is still connected to JavaAssist, while the manufacturer does not (I saw the type in Java Debugger). How to find out when for unproxy objects? Should I ignore all associations that this car may have? And in what layer of my code? Does it affect the performance of my application when I don't trust? Are there other solutions? The error message shows that I can make a type adapter. Yes, I could, but then I have to do this for all the objects in the domain to make sure the conversion is done correctly. Other objects in my domain may crash when I try to convert it to a JSON representation, but I don’t know when and why. Is it just luck that other objects are okay?

This is how I make opaque objects, but I haven’t implemented it yet, because I don’t know if it is good or bad, at what level to do it, and when I will do it. Do I have unproxy objects all the time?

 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 on request:

 [# | 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∗86)
     at com.google.gson.Gson.toJson (Gson.java∗65)
     at com.google.gson.Gson.toJson (Gson.java∗20)
     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∗71)
     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.javahaps70)
     at com.sun.ejb.containers.BaseContainer .__ intercept (BaseContainer.java:5360)
     at com.sun.ejb.containers.BaseContainer.intercept (BaseContainer.java∗348)
     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∗37)
     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=95)
     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.javahaps31)
     at org.apache.catalina.connector.CoyoteAdapter.service (CoyoteAdapter.java:231)
     at com.sun.enterprise.v3.services.impl.ContainerMapper $ AdapterCallable.call (ContainerMapper.java data17)
     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∗32)
     at com.sun.grizzly.util.AbstractThreadPool $ Worker.run (AbstractThreadPool.java∗13)
     at java.lang.Thread.run (Thread.java:722) | #]
+43
java java-ee gson hibernate jax-rs
Nov 19 '12 at 18:18
source share
5 answers

You can do without manually deleting everyone using a custom TypeAdapter . Something like that:

 /** * 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); } } 

To use it, you must first register it:

 GsonBuilder b = new GsonBuilder(); ... b.registerTypeAdapterFactory(HibernateProxyTypeAdapter.FACTORY); ... Gson gson = b.create(); 

Note that this will recursively initialize every proxy server that you have in the hierarchy of objects; since, nevertheless, you need to serialize all the data, you still had to do it.

How it works?

GSON contains a number of implementations of TypeAdapterFactory for different types (primitive types, generic types like String or Date , lists, arrays ...). Each factory is asked if it can serialize a specific Java type (the create parameter is a TypeToken instead of a Class to capture possible information about common types that a Class does not have). If the factory is able to serialize / deserialize the type, it responds with an instance of the TypeAdapter ; otherwise, it answers null .

HibernateProxyTypeAdapter.FACTORY checks if the HibernateProxy type implements; in this case, it returns an instance of HibernateProxyTypeAdapter for serialization. The write method is called when the actual object needs to be serialized; the adapter retrieves the source type of the base object and queries GSON for the standard TypeAdapter for the source type, which is usually the ReflectiveTypeAdapter .

It then retrieves an instance of the source class instead of using the proxy directly. This is necessary because the ReflectiveTypeAdapter accesses the fields directly instead of using getters; Access to the proxy object fields does not work and is a classic Hibernate pitfall .

As a possible performance improvement, a TypeAdapter delegate should be acquired in the create method. I found out that calling getSuperclass() on the Class proxy seems to give the original base class. Then the code can become:

 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()); } 
+66
Nov 23
source share

In normal cases, you do not want your domain objects to be displayed as XML / JSON through services, often you need to create a DTO because your Entity does not fit your consumer's needs. And even if this happens now, after internal database refactoring, it will not match tomorrow. Therefore, my advice is to create a DTO right now if you encounter such problems. BTW, you can create these DTOs even at the Hibernate level, by using the Transformers of the result, or by creating views and matching Hibernate objects with these views.

Another trick would be to use Dozer to copy the required fields to another class (which is actually the same class, but without a proxy).

And note: you use Gson, which refers to your fields, not to them, this makes it impossible to work with the Hibernate proxy server, because it will try to access the fields of the proxy server itself, which are always null .

+2
Nov 22 '12 at 7:02
source share

Seeing that you mentioned that the error persists during active loading, the problem probably lies not so much in Hibernate, but possibly in the implementation of GSON. I think you will need a Type when creating your JSON, not sure if it has been registered, but maybe something like this:

 public String autosToJson(Auto autos) { GsonBuilder gsonBuilder = new GsonBuilder(); Gson gson = gsonBuilder.registerTypeAdapter(Auto.class, new AutoAdapter()).create(); return gson.toJson(autos); } 

Then just create an AdapterClass, for example:

 public class AutoAdapter implements JsonSerializer<Auto> { @Override public JsonElement serialize(Auto auto, Type type, JsonSerializationContext jsc) { JsonObject jsonObject = new JsonObject(); jsonObject.addProperty("auto_id", auto.getId()); jsonObject.addProperty("auto_name", auto.getAutoName()); jsonObject.addProperty("auto__manufacture_date", auto.getManufactureDate().toString()); return jsonObject; } } 
+2
Nov 22
source share

Yes, you can just unproxy all the time if it has HibernateProxy (which will not be serialized), it will be deleted and replaced with the actual base implementation, or it will leave the class as it is and give you the implementation, I think your solution should work fine. Keep in mind that I really don't use Hibernate, but that makes sense to me.

On the other hand, you can still trust Hibernate, but a simpler method could be:

 Hibernate.getClass(obj); 

This solution should not give you implemented / initialized classes, just a class or this function should be offered:

 HibernateProxyHelper.getClassWithoutInitializingProxy(superClass) 

I believe the latter can return a superclass, so you can start with Hibernate.getClass (obj);

and

 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; } 

The above code was borrowed from: Converting a Hibernate proxy to a real object, the variable names from it are probably better, since they do not imply that the entity is always a proxy. It will also throw an exception to warn you, but it is up to you whether you want an exception or not.

Of course, you can also get rid of lazy workload, but I do not think this is the best solution.

0
Nov 21 '12 at 20:25
source share

I had this problem when I came across this message in which I pointed in the right direction for my situation. I realized that I did not need to serialize the entire object, especially for the reason that I noted some fields that would be lazy to load. So I tried to find a way to skip these fields, and ExclusionStrategy was magical. This seems to fix my problem.

 public class ExcludeProxiedFields implements ExclusionStrategy{ @Override public boolean shouldSkipField(FieldAttributes fa) { return fa.getAnnotation(ManyToOne.class) != null || fa.getAnnotation(OneToOne.class) != null || fa.getAnnotation(ManyToMany.class) != null || fa.getAnnotation(OneToMany.class) != null ; } @Override public boolean shouldSkipClass(Class<?> type) { return false; } } 

Then I applied this class to GsonBuilder as follows:

 Gson gson = new GsonBuilder().setExclusionStrategies(new ExcludeProxiedFields()).create(); 
0
Oct 23 '17 at 3:49 on
source share



All Articles