Note: The complete source and necessary jars are available in github here. For just downloading, unzipping and importing the project into Eclipse, press
on the github site.
Important: this is a collection of projects, the relevant project for this post is gae-rest-sample and spring3-resttemplate.
Finally I succeeded in getting REST (with the new REST support in Spring 3) done in the Google App Engine.
It wouldn’t be an easy task, but thanks to one brilliant blog post, a forum post and a very helpful JIRA issue, it can be resolved just by searching.
- The brilliant blog post about Spring REST in general by Eyal Lupu.
This post is just a rewrite of that one, just adding the GAE-related stuff.
All details about REST content negotiation and how the Spring MVC works with REST is explained there. - The forum post about problems with GAE and XStream.
This helps to unterstand the reason for the sun.reflect.ReflectionFactory is a restricted class exception when using XStream on GAE. - The JIRA issue 566, which investigates the problem in more detail and provides a solution which is valid for at least the usage in this context (note the last entry).
I finally took the snapshot jar attached to the JIRA issue, which works well for the samples in this post. Nevertheless, there might still be difficulties with XStream on the GAE, so be aware.
The client
Eyal Lupu also provides a JSON-Client in his post. The client itself is straightforward – it uses the Spring RestTemplate. The JsonHttpMessageConverter uses Spring’s FileCopyUtils for InputStream String conversion which is quite cool.
Spring RestTemplate:
RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(new HttpMessageConverter[]{new JsonHttpMessageConverter()});
JSONObject result = restTemplate.getForObject("http://localhost:8080/users/.js", JSONObject.class);
JSONArray aresult = result.getJSONArray("payload");
for (int x=0; x<aresult.length(); ++x) {
JSONObject currResult = (JSONObject) aresult.get(x);
System.out.format("%-100s | %s%n", currResult.get("name"), currResult.get("lastLoggedInAt"));
}
JSON-Unmarshaller:
@Override
protected JSONObject readInternal(Class<JSONObject> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
MediaType contentType = inputMessage.getHeaders().getContentType();
Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : Charset.forName("utf-8");
String stringResult = FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), charset));
JSONObject jObject;
try {
jObject = new JSONObject(stringResult);
} catch (JSONException e) {
throw new IOException (e);
}
return jObject;
}
Annoyances
Here are some things I don’t understand and I had to work around.
Please comment if you know more about the problem.
- In the web.xml, the url-pattern has to be / instead of /* (or /rest in the original sample) to get it working in the GAE
- Usually, I would prefer having the jsp-views in /WEB-INF/*. However, this does not work in GAE (doesn’t find WEB-INF or anything below WEB-INF)






