Greetings,
I'm working on a server app that currently uses Restlet 2.0.6 with the
org.restlet.ext.jackson.jar to accept/return JSON which is modeled internally
as simple java primitives (Map, List, String, Integer, etc...).
A trivial example of the types of Resources we use can be seen by modifying the
hello world Server example from the restlet tutorial like so, and running it
with the ext.jackson jars in the classpath...
public class EchoServer extends ServerResource {
public static void main(String[] args) throws Exception {
new Server(Protocol.HTTP, 8182, EchoServer.class).start();
}
@Post("json")
public Map<String,Object> echo(Map<String,Object> data) {
return data;
}
}
We've gotten more then a few requests from customers for better error messages
when they POST/PUT malformed JSON since the only details they get from restlet
at the moment is a 415 (Unsupported Media Type). For instance, the above
server responds as expected when the JSON is both well-formed and matches the
expected structure (Map)...
hossman@bester:~/tmp$ curl -sSD - -X POST -H 'Content-Type: application/json'
-d '{"foo":"bar","yak":"zad"}' http://localhost:8182/ && echo
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Date: Thu, 18 Aug 2011 00:43:48 GMT
Server: Restlet-Framework/2.0.6
Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept
Content-Type: application/json; charset=UTF-8
{"foo":"bar","yak":"zad"}
...but it returns no useful error message when the JSON is mallformed, or does
not parse into a Map...
hossman@bester:~/tmp$ curl -sSD - -X POST -H 'Content-Type: application/json'
-d '{malformed]' http://localhost:8182/ && echoHTTP/1.1 415 Unsupported Media
Type
Date: Thu, 18 Aug 2011 00:45:15 GMT
Server: Restlet-Framework/2.0.6
Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept
Content-Length: 0
hossman@bester:~/tmp$ curl -sSD - -X POST -H 'Content-Type: application/json'
-d '"string not a map"' http://localhost:8182/ && echo
HTTP/1.1 415 Unsupported Media Type
Date: Thu, 18 Aug 2011 00:45:24 GMT
Server: Restlet-Framework/2.0.6
Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept
Content-Length: 0
...even though the JacksonConvertor is logging useful errors on the server...
Aug 17, 2011 5:45:15 PM org.restlet.ext.jackson.JacksonRepresentation getObject
WARNING: Unable to parse the object with Jackson.
org.codehaus.jackson.JsonParseException: Unexpected character ('m' (code 109)):
was expecting double-quote to start field name
at [Source: org.restlet.engine.http.io.SizedInputStream@61a116c9; line: 1,
column: 3]
at org.codehaus.jackson.JsonParser._constructError(JsonParser.java:929)
at
org.codehaus.jackson.impl.JsonParserBase._reportError(JsonParserBase.java:632)
...
Aug 17, 2011 5:45:24 PM org.restlet.ext.jackson.JacksonRepresentation getObject
WARNING: Unable to parse the object with Jackson.
org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of
java.util.Map out of VALUE_STRING token
at [Source: org.restlet.engine.http.io.SizedInputStream@30e3c624; line: 1,
column: 1]
at
org.codehaus.jackson.map.JsonMappingException.from(JsonMappingException.java:159)
at
org.codehaus.jackson.map.deser.StdDeserializationContext.mappingException(StdDeserializationContext.java:131)
What we'd like to do when returning these 415 error responses is generate a
JSON Represation of an error message that contains more details about the
specifics of the parse error.
I know that we can register our own StatusService implementation to override
the default getStatus and getRepresentation methods used to generate errors in
restlet, but based on my testing StatusService.getStatus doesn't seem to be
called when these types of parse errors happen in the Converters on client
input, so we never see the JsonParseException or JsonMappingException from the
jackson parser. I do see my custom StatusService.getRepresentation method
getting called, but at that point in the workflow, I don't see any indication
of the cause of the error: Status.getThrowable() is null, and nothing in the
Request object seems to relate to accessing Conversion errors.
I briefly considered trying to reparse the Entity data myself using jackson to
see what error I'd get, but in this type of situation the raw JSON doesn't seem
to be available in the Request object passed to StatusService.getRepresentation
(Request.getEntityAsText() and request.getEntity().getText() both return null).
Am I missing something? Is there any programmatic way for Restlet apps to
access error messages generated when Converters parse client input?
I poked around in the trunk version of JacksonRepresentation.getObject() and it
looks like (as implemented) JacksonRepresentation logs these errors and then
immediately returns null (making me wonder how the restlet engine tells the
difference between a 415 error because the Convertor couldn't parse the request
vs. input that is genuinely null) but I've got my fingers crossed that an
expert will chime in here and explain how the StatusService API is actually
designed to support giving server apps access to these types of errors, and
that in this particular case the JacksonRepresentation class is buggy in how it
deals with errors and there is a simple patch to fix it to report the errors
correctly.
I hope.
-Hoss
------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=2823739