users@jersey.java.net

[Jersey] MarshalException not caught in AbstractRootElementProvider

From: Bao,Sam <Sam.Bao_at_Cerner.com>
Date: Fri, 7 Aug 2009 10:00:07 -0500

Paul,

Forgive me, but I don't know how to just respond to the mailing list without creating a new email (I'm not getting the mailing list subscriptions), so I'm just copying and paste your comment into the end of this email.

 

I am using 1.1.1-ea version of the core, and the code matches what you attached. I am using the simple com.sun.net.httpserver.HttpServer. Is that the lightweight server you're referring to? I'm leaning more to #2 as the cause because when I hit the server using jersey client, I get this:

com.sun.jersey.api.client.ClientHandlerException: java.net.SocketException: Unexpected end of file from server

 

When I hit the server using Poster, I get no message body whatsoever, but a 200 status.

 

As for your suggestions, #1 was what I had in mind as well because it seems in the readFrom you catch an UnmarshalException and then throw a WebApplicationException(ex, 400). Obviously 500 would be appropriate here, but I would like MarshalException to be wrapped so that I can get the message of the exception in my mapper to send back in the response.

 

I'm going to try and extend the AbstractRootElementProvider and overwrite the writeTo method myself until a version of your changes gets released.

 

I don't understand why some bytes would prematurely be written out in the output stream. So I'm not sure how I can fix it on my end. Any guidance would be appreciated. Thanks.

 

-------------------------------------------------------------------------------------------------------------------------------

On Aug 6, 2009, at 11:41 PM, Bao,Sam wrote:

 

> In the writeTo method in AbstractRootElementProvider, it doesn't

> catch for MarshalException similar to how the readFrom method

> catches the UnmarshalException in line 99. So the resource is still

> return a 200 status with no response entity.

>

 

What HTTP container are you using. Servlet?

 

What version of the code are you looking at? here is the trunk:

 

     public final void writeTo(

             Object t,

             Class<?> type,

             Type genericType,

             Annotation annotations[],

             MediaType mediaType,

             MultivaluedMap<String, Object> httpHeaders,

             OutputStream entityStream) throws IOException {

         try {

             final Marshaller m = getMarshaller(type, mediaType);

             final Charset c = getCharset(mediaType);

             if (c != UTF8) {

                 m.setProperty(Marshaller.JAXB_ENCODING, c.name());

             }

             writeTo(t, mediaType, c, m, entityStream);

         } catch (JAXBException cause) {

             throw ThrowHelper.withInitCause(cause,

                     new

IOException(ImplMessages.ERROR_MARSHALLING_JAXB(t.getClass()))

                     );

         }

     }

 

It catches JAXBException and MarshalException extends from that and re-

throws it as an IOException.

 

If the above code is the same as what you are looking at then an

IOException should be thrown which is passed to the underlying HTTP

container (e.g. servlet layer) and a 500 response should be returned

if one of the following is not occurring:

 

1) If you are using the LW HTTP server, there was a bug in that server

(which has been worked around in the trunk)

      which does not react to exceptions passed to it; or

 

2) If some bytes of the JAXB object have been written to the output

stream and sent out on the TCP connection then a client

     may receive the 200 status code and headers, but the client

should observe a terminated connection from the server.

 

I think what i should to is change the code to throw a

WebApplicationException(500) instead of wrapping in an IOException.

That should give you the chance to map WebApplicationException if the

response has not been committed (no bytes written out). But as i noted

if some bytes of the response have already been written there is not

much that can be done. To reliably catch marshaling errors it would be

necessary to buffer the response before it is written on the wire.

 

 

So in summary i think there are two things that can be done to improve

the situation:

 

1) the writers throw WebApplicationException(500, ex); and

 

2) define a response filter to buffer the response so that errors can

be trapped when writing.

 

Paul.

 

> So I had previously asked about how to handle the

> WebApplicationException with status 400, and so I was thinking that

> likewise it would apply to MarshalException except for the fact that

> it's never caught and rethrow WebApplicationException for my

> exception mapper to handle. What is the reason MarshalException is

> not caught? Is it intentional or an oversight? I'm leaning towards

> the former and thus would like to understand the reason. Mainly

> because I'm still getting a 200 status which is definitely not

> correct. In the meantime, how should I handle being able to return

> my own status code and response entity? I thought about validating

> and marshalling the xml myself. The other was to extend

> AbstractRootElementProvider and override the writeTo method. I'm

> leaning towards the first idea, but I'd like to hear other

> suggestions and comments.

>

> Thanks.

 

----------------------------------------------------------------------
CONFIDENTIALITY NOTICE This message and any included attachments are from Cerner Corporation and are intended only for the addressee. The information contained in this message is confidential and may constitute inside or non-public information under international, federal, or state securities laws. Unauthorized forwarding, printing, copying, distribution, or use of such information is strictly prohibited and may be unlawful. If you are not the addressee, please promptly delete this message and notify the sender of the delivery error by e-mail or you may call Cerner's corporate offices in Kansas City, Missouri, U.S.A at (+1) (816)221-1024.