On Aug 7, 2009, at 5:00 PM, Bao,Sam wrote:
> 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),
See here:
https://jersey.dev.java.net/servlets/ProjectMailingListList
> 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?
Yes, that may partially explain why you are getting a 200 response.
See issue 337:
https://jersey.dev.java.net/issues/show_bug.cgi?id=337
which is fixed in the 1.1.2.-ea-SNAPSHOT. It all depends if the
exception is thrown before or after some bytes (of the XML document)
have been written.
> 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
Right. This seem to indicate that the error is occurring after some
bytes have been written.
>
> 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.
Jersey by default *streams* stuff to avoid buffering. So it is not
about being premature. If there is an error in the processing of
writing out content, some of which has already been sent to the
client, there is not much one can do to recover and report an
appropriate error to the client.
> So I’m not sure how I can fix it on my end. Any guidance would be
> appreciated. Thanks.
The only way you can guarantee that an HTTP error response is sent to
the client is that the response entity is buffered, e.g. written out
to a ByteArrayOutputStream and then bytes of that output stream are
written out on the wire. Thus we need a container response filter that
buffers content. See:
https://jersey.dev.java.net/nonav/apidocs/1.1.1-ea/jersey/com/sun/jersey/api/container/filter/package-summary.html
https://jersey.dev.java.net/nonav/apidocs/1.1.1-ea/jersey/com/sun/jersey/spi/container/ContainerResponseFilter.html
I do not have time right now to present an example of how to do this.
But may be able to do this on Monday.
This of course has it's own consequences in that buffering can be
inefficient, especially for large responses.
Once buffering is enabled we then need to change the implementation of
AbstractRootElementProvider. writeTo to throw a
WebApplicationException(500). Then you can map the exception.
Paul.
>
> -------------------------------------------------------------------------------------------------------------------------------
> 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.