Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Customize JSON serialization with JaxRS

Tags:

java

json

jax-rs

In a webservice call, I would like to return my objects with this JSON structure.

{
  "date" : "30/06/2014",
  "price" : {
    "val" : "12.50",
    "curr" : "EUR"
  }
}

I'd like to map this JSON code to this Java structure (with joda-time and joda-money):

public class MyResponse {
  LocalDate date;
  Money price;
}

My webservice currently looks like this:

@javax.ws.rs.POST
@javax.ws.rs.Path("test")
@javax.ws.rs.Produces({MediaType.APPLICATION_JSON})
@javax.ws.rs.Consumes({MediaType.APPLICATION_JSON})
public MyResponse test(MyRequest request) {
  MyResponse response = new MyResponse();
  response.setDate(LocalDate.now());
  response.setMoney(Money.parse("EUR 12.50"));
  return response;
}

So my question is: where do I register a custom handler to format dates as I want as well as money representations?

like image 318
Olivier Grégoire Avatar asked Jun 30 '14 11:06

Olivier Grégoire


1 Answers

If you are using Jackson (which should be the default for JBoss EAP 6) you can use custom JsonSerializers

For the LocalDate:

public class DateSerializer extends JsonSerializer<LocalDate> {

    @Override
    public void serialize(LocalDate date, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
        jgen.writeString(date.toString("dd/MM/yyyy"));
    }

}

For the Money:

public class MoneySerializer extends JsonSerializer<Money> {

    @Override
    public void serialize(Money money, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
        jgen.writeStartObject();
        jgen.writeStringField("val", money.getAmount().toString());
        jgen.writeStringField("curr", money.getCurrencyUnit().getCurrencyCode());
        jgen.writeEndObject();
    }

}

Both Serializers can be registered globally:

@Provider
public class JacksonConfig implements ContextResolver<ObjectMapper> {

    private ObjectMapper objectMapper;

    public JacksonConfig() {
        objectMapper = new ObjectMapper();
        SimpleModule module = new SimpleModule("MyModule", new Version(1, 0, 0, null));
        module.addSerializer(Money.class, new MoneySerializer());
        module.addSerializer(LocalDate.class, new DateSerializer());
        objectMapper.registerModule(module);
    }

    public ObjectMapper getContext(Class<?> objectType) {
        return objectMapper;
    }

}

For parsing JSON in this custom format you need to implement custom JsonDeserializers.

If you are using Jettison you can do the same thing with custom XmlAdapters.

like image 143
lefloh Avatar answered Oct 01 '22 10:10

lefloh