jojoob
jojoob

Reputation: 153

How to map/convert nested params with jersey-media-moxy?

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();
            }
        };
    }
}

Upvotes: 1

Views: 962

Answers (1)

Paul Samsotha
Paul Samsotha

Reputation: 209112

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;
}

Upvotes: 1

Related Questions