I'm programming a RESTful web application with jersey and MOXy for JAXB based JSON support.
My goal is to use a POJO as a method parameter that consumes JSON.
@POST
@Consumes(MediaType.APPLICATION_JSON)
public void postRequest(MyPOJO myPOJO) {
System.out.println(myPOJO.name);
System.out.println(myPOJO.currency);
}
This POJO has a string member and a member of type java.util.Currency.
@XmlRootElement
public class MyPOJO {
public String name;
public Currency currency;
public MyPOJO() {};
}
I have also a custom Currency ParamConverter (and Provider), see below. With this I'm able to handle a QueryParam of type Currency correctly.
But if I query my resource by POST with the following JSON content currency is not mapped and will be null while name is mapped correctly.
{ "name": "peter", "currency": "EUR" }
Console output therefor results in:
peter
null
What else I have to do to tell MOXy to correctly map this nested object members?
This is my ParamConverter for Currency:
@Provider
public class CurrencyParamConverterProvider implements ParamConverterProvider {
@Override
public <T> ParamConverter<T> getConverter(final Class<T> rawType, Type genericType, Annotation[] annotations) {
return rawType != Currency.class ? null : new ParamConverter<T>() {
@Override
public T fromString(String value) {
if (value == null) {
throw new IllegalArgumentException(LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value"));
}
try {
return rawType.cast(Currency.getInstance(value));
} catch (IllegalArgumentException e) {
throw new ExtractorException("Currency must be a valid ISO 4217 code of the currency.", e);
}
}
@Override
public String toString(T value) {
if (value == null) {
throw new IllegalArgumentException(LocalizationMessages.METHOD_PARAMETER_CANNOT_BE_NULL("value"));
}
return value.toString();
}
};
}
}
Currency
is an object, so in the JSON world, it should be
{ "name": "peter", "currency": { "fieldName" :"EUR"} }
The reason you don't get any failure notice is that MOXy by default is just meant o ignore these type of missing/unknown property issues.
One way to get around this is to use an XmlAdapter
. For example
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class CurrencyAdapter extends XmlAdapter<String, Currency>{
@Override
public Currency unmarshal(String v) throws Exception {
Currency c = new Currency();
c.type = v;
return c;
}
@Override
public String marshal(Currency v) throws Exception {
return v.type;
}
}
Where Currency.type
is simply the field to hold the "EUR"
value. Then you just need to annotate the property/field with the adapter
@XmlRootElement
public class MyPojo {
public String name;
@XmlJavaTypeAdapter(CurrencyAdapter.class)
public Currency currency;
}