Using XStream on Google App Engine
Dienstag, 4. Oktober 2011
When building the new "Enrich contacts" feature I've been using GSon for parsing JSON responses.
This was super-easy and did work more or less instantly.
Unfortunately the LinkedIn API is using XML and strange enough it became quite complicated to parse XML on GAE.
I tried to find an approach similar to GSon for XML but due to security restrictions on App Engine I struggled to use XStream in the first place.
After finding a patched jar that allows to use XStram on GAE I was still surprised how complicated it was to map XML to fields. As XML typically uses dashes in tag names I thought it would map to camel-case syntax automatically, but XStream wanted me to define an alias for each mapping.
After getting an ever growing list of mappings I decided to create a mapper to do this once and for all.
As I assume that a lot of people face exactly the same problem, I'd like to share the code with you:
To convince XStream to use this custom mapper, create your XStream instance like this:
This was super-easy and did work more or less instantly.
Unfortunately the LinkedIn API is using XML and strange enough it became quite complicated to parse XML on GAE.
I tried to find an approach similar to GSon for XML but due to security restrictions on App Engine I struggled to use XStream in the first place.
After finding a patched jar that allows to use XStram on GAE I was still surprised how complicated it was to map XML to fields. As XML typically uses dashes in tag names I thought it would map to camel-case syntax automatically, but XStream wanted me to define an alias for each mapping.
After getting an ever growing list of mappings I decided to create a mapper to do this once and for all.
As I assume that a lot of people face exactly the same problem, I'd like to share the code with you:
private static class CamelCaseMapper extends MapperWrapper {
public CamelCaseMapper(Mapper wrapped) {
super(wrapped);
}
@Override
public String serializedMember(Class type, String memberName) {
StringBuilder dashed = new StringBuilder();
for (int i = 0; i < memberName.length(); i++) {
if (Character.isUpperCase(memberName.charAt(i))) {
dashed.append('-').
append(Character.toLowerCase(memberName.charAt(i)));
} else {
dashed.append(memberName.charAt(i));
}
}
return super.serializedMember(type, dashed.toString());
}
@Override
public String realMember(Class type, String serialized) {
int index = -1;
while ((index = serialized.indexOf("-")) > -1) {
serialized = serialized.substring(0, index) +
String.valueOf(serialized.charAt(index + 1)).toUpperCase() +
serialized.substring(index + 2);
}
return super.realMember(type, serialized);
}
}
To convince XStream to use this custom mapper, create your XStream instance like this:
XStream xstream = new XStream(new DomDriver()) {
protected MapperWrapper wrapMapper(MapperWrapper next) {
return new CamelCaseMapper(next);
}
};