0 Replies Latest reply on Oct 4, 2011 3:47 PM by ddc

    Problem with JSONProvider & dropRootElement

    ddc

      Hello,

       

      I ran into a problem with a camel cxfrs endpoint that is caused by what appears to be a bug in JSONProvider/JSONUtils when configured with dropRootElement true.

       

      Based on guidance in http://cxf.apache.org/docs/jax-rs-data-bindings.html#JAX-RSDataBindings-JAXBsupport for the simplest way to deal with collections, I created a Topics class to represent a collection of topics.  It has a getTopics method with return type Collection.  My web service @Produces("application/json") and has a method getTopics with return type Topics.  With default JSONProvider settings, the web service method returns something like the following:

       

      {"topics":{"topics":[{"name":"foo"},{"name":"bar"}]}}

       

      To get rid of the outer topics name, I configured the JSONProvider with dropRootElement = true.  However that caused the following exception:

       

      javax.xml.stream.XMLStreamException: Too many closing tags.

           at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:322)

           at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:172)

           at org.apache.cxf.jaxrs.provider.JSONProvider.marshal(JSONProvider.java:387)

           at org.apache.cxf.jaxrs.provider.JSONProvider.marshal(JSONProvider.java:420)

           at org.apache.cxf.jaxrs.provider.JSONProvider.writeTo(JSONProvider.java:300)

           at org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.serializeMessage(JAXRSOutInterceptor.java:256)

           at org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.processResponse(JAXRSOutInterceptor.java:144)

           at org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor.handleMessage(JAXRSOutInterceptor.java:83)

           at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)

           at org.apache.cxf.interceptor.OutgoingChainInterceptor.handleMessage(OutgoingChainInterceptor.java:77)

           at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)

           at org.apache.cxf.phase.PhaseInterceptorChain.resume(PhaseInterceptorChain.java:232)

           at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:75)

           at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.serviceRequest(JettyHTTPDestination.java:318)

           at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.doService(JettyHTTPDestination.java:286)

           at org.apache.cxf.transport.http_jetty.JettyHTTPHandler.handle(JettyHTTPHandler.java:72)

           at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:939)

           at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:875)

           at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)

           at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:185)

           at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:110)

           at org.eclipse.jetty.server.Server.handleAsync(Server.java:387)

           at org.eclipse.jetty.server.HttpConnection.handleRequest(HttpConnection.java:594)

           at org.eclipse.jetty.server.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:1048)

           at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:601)

           at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:214)

           at org.eclipse.jetty.server.HttpConnection.handle(HttpConnection.java:411)

           at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:535)

           at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:40)

           at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:529)

           at java.lang.Thread.run(Thread.java:662)

      Caused by: javax.xml.stream.XMLStreamException: Too many closing tags.

           at org.codehaus.jettison.mapped.MappedXMLStreamWriter.writeEndElement(MappedXMLStreamWriter.java:237)

           at org.apache.cxf.staxutils.DelegatingXMLStreamWriter.writeEndElement(DelegatingXMLStreamWriter.java:123)

           at org.apache.cxf.jaxrs.provider.JSONUtils$IgnoreContentJettisonWriter.writeEndElement(JSONUtils.java:226)

           at com.sun.xml.bind.v2.runtime.output.XMLStreamWriterOutput.endTag(XMLStreamWriterOutput.java:144)

           at com.sun.xml.bind.v2.runtime.output.XmlOutputAbstractImpl.endTag(XmlOutputAbstractImpl.java:120)

           at com.sun.xml.bind.v2.runtime.output.NamespaceContextImpl$Element.endElement(NamespaceContextImpl.java:499)

           at com.sun.xml.bind.v2.runtime.XMLSerializer.endElement(XMLSerializer.java:314)

           at com.sun.xml.bind.v2.runtime.property.ArrayElementProperty.serializeListBody(ArrayElementProperty.java:171)

           at com.sun.xml.bind.v2.runtime.property.ArrayERProperty.serializeBody(ArrayERProperty.java:155)

           at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:340)

           at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:593)

           at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:324)

           at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:494)

           at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:315)

           ... 30 more

       

      The problem is occurring because the name of the class (Topics) matches the name of its property (getTopics) when translated to their json equivalents (topics).  JSONProvider uses JSONUtils whose inner class IgnoreContentJettisonWriter uses the qualified name of the root element to know when to drop the json outer object wrapper that represents the class being serialized.  When the class name matches the property name, the algorithm drops not only the outer object wrapper, but also drops the name of the matching property.

       

      A workaround was to add a namespace to the Topics class's @XmlRootElement.

       

      The workaround was easy, but it took me a day to figure out what was going on, and it seems like the dropRootElement solution should be more aware of whether it's really dropping the root element vs. a name/value pair with a name that matches the root name.

       

      Can someone with more experience with this code check my conclusions?  And if you agree that it's a problem, please let me know what I need to do to get the bug logged properly.

       

      David