Problem serializing an object to json

265 views
Skip to first unread message

David Castro

unread,
Apr 15, 2010, 9:10:28 PM4/15/10
to grails-jaxrs-discuss
I wasn't having issues with this, but somehow along the way I started to get this when asking for JSON content for a custom object of mine (code below).  It is particularly unkind because it results in a 500 internal server error as well.  It should probably respond with a 415 Unsupported Media Type when it fails in this way too.

Apr 15, 2010 5:52:42 PM com.sun.jersey.spi.container.ContainerResponse write
SEVERE: A message body writer for Java type, class net.mediatemple.ResponseEntity, and MIME media type, application/json, was not found
Apr 15, 2010 5:52:42 PM com.sun.jersey.server.impl.application.WebApplicationImpl onException
SEVERE: Internal server error
javax.ws.rs.WebApplicationException
        at com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:253)
        at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:814)
        at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:740)
        at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:731)
        at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:372)
        at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:452)
        at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:633)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
        at org.grails.jaxrs.web.JaxrsContext$JaxrsServiceImpl.process(JaxrsContext.java:150)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoCachedMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:229)
        at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:52)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:129)
        at JaxrsController$_closure1.doCall(JaxrsController.groovy:36)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSite.invoke(PogoMetaMethodSite.java:225)
        at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:51)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:143)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:151)
        at JaxrsController$_closure1.doCall(JaxrsController.groovy)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:234)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1049)
        at groovy.lang.ExpandoMetaClass.invokeMethod(ExpandoMetaClass.java:923)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:880)
        at groovy.lang.Closure.call(Closure.java:279)
        at groovy.lang.Closure.call(Closure.java:274)
        at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsControllerHelper.handleAction(SimpleGrailsControllerHelper.java:377)
        at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsControllerHelper.executeAction(SimpleGrailsControllerHelper.java:244)
        at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsControllerHelper.handleURI(SimpleGrailsControllerHelper.java:202)
        at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsControllerHelper.handleURI(SimpleGrailsControllerHelper.java:137)
        at org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsController.handleRequest(SimpleGrailsController.java:88)
        at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
        at org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet.doDispatch(GrailsDispatcherServlet.java:255)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:716)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:647)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:552)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:70)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:70)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:70)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:70)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:70)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:646)
        at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:436)
        at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:374)
        at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
        at org.codehaus.groovy.grails.web.util.WebUtils.forwardRequestForUrlMappingInfo(WebUtils.java:302)
        at org.codehaus.groovy.grails.web.util.WebUtils.forwardRequestForUrlMappingInfo(WebUtils.java:278)
        at org.codehaus.groovy.grails.web.util.WebUtils.forwardRequestForUrlMappingInfo(WebUtils.java:270)
        at org.codehaus.groovy.grails.web.mapping.filter.UrlMappingsFilter.doFilterInternal(UrlMappingsFilter.java:187)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter.obtainContent(GrailsPageFilter.java:249)
        at org.codehaus.groovy.grails.web.sitemesh.GrailsPageFilter.doFilter(GrailsPageFilter.java:140)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.grails.jaxrs.web.JaxrsFilter.doFilterInternal(JaxrsFilter.java:46)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.codehaus.groovy.grails.web.servlet.filter.GrailsReloadServletFilter.doFilterInternal(GrailsReloadServletFilter.java:101)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:65)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.codehaus.groovy.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:66)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
        at java.lang.Thread.run(Thread.java:637)
support.GrailsOpenSessionInViewInterceptor Flushing single Hibernate Session in OpenSessionInViewInterceptor
support.GrailsOpenSessionInViewInterceptor Eagerly flushing Hibernate session
support.GrailsOpenSessionInViewInterceptor Closing single Hibernate Session in OpenSessionInViewInterceptor

Service method:

    @GET
    @Path('/{zone}')
    @Produces(["application/json", "application/xml"])
    def getZone(@PathParam("zone") String zone) {
        ResponseEntity response = new ResponseEntity();
        response.statusCode = 404;
        return response;
    }

Object to serialize - ResponseEntity.java:

package net.mediatemple;

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import java.util.Date;

@XmlRootElement(name = "response")
@XmlType(name = "response", propOrder = {"statusCode", "timeStamp"})
public class ResponseEntity {

    private int statusCode = 0;
    private Date timeStamp = new Date();

    public void setStatusCode(int statusCode) {
        this.statusCode = statusCode;
    }

    public int getStatusCode() {
        return this.statusCode;
    }

    public Date getTimeStamp() {
        return timeStamp;
    }

    public void setTimeStamp(Date timeStamp) {
        this.timeStamp = timeStamp;
    }
}

The method is invoked just fine and everything is great.  I want to return a ResponseEntity and have it serialized.

I see that jaxrs contains a JSON message body writer and I am assuming that it's the JaxrsGrailsPlugin that searches for all @Provider annotated writers to get them recognized by Jersey.  The interesting thing is that it works for some classes (serializes to json just fine...they happen to be groovy) and not for others (this one happens to be java)...but I swear this was all fine before.  And it's only JSON that's failing when it does fail.  Scratching my head atm.

Thoughts?

David Castro

unread,
Apr 15, 2010, 9:28:52 PM4/15/10
to grails-jaxrs-discuss
My start-up does in fact show the message body writers getting wired up as show below...even more strange.  For good measure I created a groovy class an tried using that instead of the Java class, with the same result (note: I did need @XmlAccessorType( XmlAccessType.FIELD ) added to the groovy glass for XML serialization to be happy as expected).

INFO: Using default applicationContext
Apr 15, 2010 6:16:51 PM com.sun.jersey.spi.spring.container.SpringComponentProviderFactory register
INFO: Registering Spring bean, org.grails.jaxrs.provider.DomainObjectWriter, of type org.grails.jaxrs.provider.DomainObjectWriter as a provider class
Apr 15, 2010 6:16:51 PM com.sun.jersey.spi.spring.container.SpringComponentProviderFactory register
INFO: Registering Spring bean, org.grails.jaxrs.provider.DomainObjectReader, of type org.grails.jaxrs.provider.DomainObjectReader as a provider class
Apr 15, 2010 6:16:51 PM com.sun.jersey.spi.spring.container.SpringComponentProviderFactory register
INFO: Registering Spring bean, org.grails.jaxrs.provider.JSONWriter, of type org.grails.jaxrs.provider.JSONWriter as a provider class
Apr 15, 2010 6:16:51 PM com.sun.jersey.spi.spring.container.SpringComponentProviderFactory register
INFO: Registering Spring bean, org.grails.jaxrs.provider.JSONReader, of type org.grails.jaxrs.provider.JSONReader as a provider class
Apr 15, 2010 6:16:51 PM com.sun.jersey.spi.spring.container.SpringComponentProviderFactory register
INFO: Registering Spring bean, org.grails.jaxrs.provider.XMLReader, of type org.grails.jaxrs.provider.XMLReader as a provider class
Apr 15, 2010 6:16:51 PM com.sun.jersey.spi.spring.container.SpringComponentProviderFactory register
INFO: Registering Spring bean, DNSService, of type net.mediatemple.service.DNSService as a root resource class
Apr 15, 2010 6:16:51 PM com.sun.jersey.spi.spring.container.SpringComponentProviderFactory register
INFO: Registering Spring bean, accountResource, of type net.mediatemple.service.AccountResource as a root resource class
Apr 15, 2010 6:16:51 PM com.sun.jersey.spi.spring.container.SpringComponentProviderFactory register
INFO: Registering Spring bean, org.grails.jaxrs.provider.XMLWriter, of type org.grails.jaxrs.provider.XMLWriter as a provider class
Apr 15, 2010 6:16:51 PM com.sun.jersey.server.impl.application.WebApplicationImpl initiate
INFO: Initiating Jersey application, version 'Jersey: 1.1.4.1 11/24/2009 01:30 AM'

David Castro

unread,
Apr 15, 2010, 10:22:50 PM4/15/10
to grails-jaxrs-discuss
Well, I can also tell that none of the jaxrs MessageBodyWriter classes are being invoked.  I added some debugging, so I print when writeTo() is called and isSuported().

Looks like for both XML/JSON I get a single isSupported() line to print, always with return value false.  Here is the JSON one:

isSupported: type=class net.mediatemple.ResponseEntity2 genericType=class net.mediatemple.ResponseEntity2 mediaType=application/json typeArgument=class grails.converters.JSON supported=false

I never see the writeTo() methods being invoked.  I double checked and added the provider package via the com.sun.jersey.config.property.packages init param to the servlet, which printed out more classes being registered with the same resut...so it seems safe to assume that they are registered and just not getting invoked for another reason.

http://www.tmro.net/tag/jersey/ may or may not be helpful.  I did notice that they wire up the provider classes in the web.xml

David Castro

unread,
Apr 16, 2010, 12:12:59 AM4/16/10
to grails-jaxrs-discuss
K, now I'm really confused...

in ProviderSupport.java I commented out the isAssignable() test and returned true, which then yields the following error:

errors.GrailsExceptionResolver net.mediatemple.ResponseEntity2 cannot be cast to grails.converters.JSON
java.lang.ClassCastException: net.mediatemple.ResponseEntity2 cannot be cast to grails.converters.JSON

Why would we ever be trying to cast an object to a JSON instance?  Is that supposed to be a groovy/grails shorthand for performing a "Object as XML"?  Not sure I get it.  In any case, it seems the isSupported() method for those writers always returns false because of this test and hence I don't know that they ever really get used in any cases.  I think serializers are actually getting used...

Cheers,
David

Martin Krasser

unread,
Apr 16, 2010, 3:46:51 AM4/16/10
to grails-jax...@googlegroups.com
I'll take a look at it as soon as I can (today or tomorrow). Thanks for
reporting.

David Castro schrieb:
--
Martin Krasser

Blog: http://krasserm.blogspot.com
Twitter: http://twitter.com/mrt1nz



--
Subscription settings: http://groups.google.com/group/grails-jaxrs-discuss/subscribe?hl=en

Martin Krasser

unread,
Apr 16, 2010, 4:56:25 AM4/16/10
to grails-jax...@googlegroups.com
Hi David,

the grails-jaxrs plugin supports JSON serialization only for Grails
domain classes, not for arbitrary classes (as in your case). Since
ResponseEntity isn't a Grails domain class, Jersey looks for a default
entity provider that supports the 'application/json' media type but
Jersey doesn't have one (as this is not required by the JAX-RS spec).
Therefore it throws a WebApplicationException(500). I need to look at
the JAX-RS spec more detailed whether returning a 500 is appropriate
here instead of 415. If not, then this is a Jersey issue.

On the other hand, if you set the Accept request header to
application/xml then Jersey selects the JAXB entity provider and an XML
response is returned as expected. The JAXB provider *is* required by
specification.

So what are your options?

- either make ResponseEntity a Grails domain class then it should work
(... but I didn't test that)
- or use the JSON provider from the Jersey project
(https://jersey.dev.java.net/nonav/documentation/latest/user-guide.html#json)
and add it to the Spring application context (maybe that's not even
needed when you install the jersey-json module).

Hope that helps,
Martin

David Castro schrieb:

David Castro

unread,
Apr 17, 2010, 4:07:44 PM4/17/10
to grails-jax...@googlegroups.com
On Fri, Apr 16, 2010 at 1:56 AM, Martin Krasser <kras...@googlemail.com> wrote:
Hi David,

the grails-jaxrs plugin supports JSON serialization only for Grails domain classes, not for arbitrary classes (as in your case). Since ResponseEntity isn't a Grails domain class, Jersey looks for a default entity provider that supports the 'application/json' media type but Jersey doesn't have one (as this is not required by the JAX-RS spec). Therefore it throws a WebApplicationException(500). I need to look at the JAX-RS spec more detailed whether returning a 500 is appropriate here instead of 415. If not, then this is a Jersey issue.


Ah, didn't realize that it had to be a domain class, hrmm.  See with CXF for instance, I can pass in any object at all and it'll try to serialize it via a MessageBodyWriter for whatever MediaType is annotated.  Perhaps I just need to add the jersey-json then, I'll give that a go and see if it helps.

Looks like the 500 instead of 415 it is a jersey choice...I saw the jersey source.  Dunno why they'd do a 500 for that, but there may be a good reason.
Reply all
Reply to author
Forward
0 new messages