0

I have found how to customize ObjectMapper date format in order to let Spring to help to auto serialize/deserialize (serialize when I want to return object to client, deserialize when the request body is json object), but I have lot of DTO with different date format, some might need yyyy-mm-dd, some is dd-mm-yyyy, one ObjectMapper will not work for different required date format, what is the best practice solution for this issue?

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    super.configureMessageConverters(converters);
    converters.add(mappingJacksonHttpMessageConverter());
}

MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter() {
    MappingJacksonHttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJacksonHttpMessageConverter();
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.setDateFormat(new SimpleDateFormat("dd-MM-yyyy"));
    objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
    mappingJacksonHttpMessageConverter.setObjectMapper(objectMapper);
    mappingJacksonHttpMessageConverter.setPrettyPrint(true);
    return mappingJacksonHttpMessageConverter;
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Sam YC
  • 10,725
  • 19
  • 102
  • 158
  • Do you have different pojos mapped to DTOs or using same POJO to map different DTOs? – harshavmb Jun 07 '17 at 04:34
  • Erm... In the controller, I only use DTOs, my POJO is database entity. I am not sure what you mean "map"? – Sam YC Jun 07 '17 at 06:20
  • Am talking about pojos mapped in your repository layer of DTOs – harshavmb Jun 07 '17 at 06:21
  • Yes, I have few POJO entity, because my form data or returned data is not the same as the POJO entity, so I created lot of DTO which is almost the same as POJO but some may not same, and DTO contain some validation logic. – Sam YC Jun 07 '17 at 06:24
  • okies, I thought of telling you to make changes in the member variables representing json date fields with `@JsonFormat (shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy")` annotation. pattern might vary with the incoming json. – harshavmb Jun 07 '17 at 06:27
  • oh, never thought we can use annotation, will annotation overwrite the configuration in `ObjectMapper`? – Sam YC Jun 07 '17 at 06:56
  • Nope, I don't think so. It should just override the properties locally applied to that member variable not other properties applied globally – harshavmb Jun 07 '17 at 06:57
  • Sorry, I should say precedence taken not overwrite, for example, my spring global `ObjectMapper` configured to format date as `yyyy-MM-dd` but annotation stated the member variable's date should format as `dd-MM-yyyy`, `ObjectMapper` should take the annotation one right? – Sam YC Jun 07 '17 at 07:07
  • Hmm., I'm not sure of this. Probably you can test this and let me know. I'm just a starter.. :) You seem to be an expert in this area.. – harshavmb Jun 07 '17 at 07:10
  • OK thanks for your feedback, at least I know now, there is such annotation and possibly will be one of the solution. Later I will try it out. – Sam YC Jun 07 '17 at 07:16
  • use @JsonFormat - https://stackoverflow.com/questions/12463049/date-format-mapping-to-json-jackson/27102120#27102120 – Oleg Jun 07 '17 at 16:54
  • 1
    @harshavmb yes, I have tried it, the annotation indeed take higher precedence than the global `ObjectMapper` configuration. – Sam YC Jun 08 '17 at 08:05
  • Oh, nice! Please post this as an answer. It helps many. Thanks @GMsoF! – harshavmb Jun 08 '17 at 08:07

1 Answers1

1

You could use custom Serializers and handle the different formats within a single Serializer. Here are a few pages that have some info on how to create custom Serializer/Deserializers:

Create Custom Serializer

Create Custom Deserializer

-- Edit --

From the documentation for MappingJacksonHttpMessageConverter (some emphasis added):

setObjectMapper
public void setObjectMapper(org.codehaus.jackson.map.ObjectMapper objectMapper)

    Set the ObjectMapper for this view. If not set, a default ObjectMapper is used.

    Setting a custom-configured ObjectMapper is one way to take further control
    of the JSON serialization process. For example, an extended SerializerFactory
    can be configured that provides custom serializers for specific types.
    The other option for refining the serialization process is to use Jackson's
    provided annotations on the types to be serialized, in which case a
    custom-configured ObjectMapper is unnecessary.

This means that you do not even need to call setObjectMapper if you have Serializers/Deserializers defined by annotations (as described in the links I posted above). For your benefit, here is an example:

For Serializing:

Create a StdSerializer object to handle the type you are interested in

public class ItemSerializer extends StdSerializer<Item> {
    // ...

    @Override
    public void serialize(Item value, JsonGenerator jgen, SerializerProvider provider) {
        // Write the Item data into the JsonGenerator
    }
}

Define the Serializer for the object via annotations

@JsonSerialize(using = ItemSerializer.class)
public class Item {
    // ...
}

For Deserialization

Create a StdDeserializer object to handle the type you are interested in

public class ItemDeserializer extends StdDeserializer<Item> { 
    // ... 

    @Override
    public Item deserialize(JsonParser jp, DeserializationContext ctxt) 
      throws IOException, JsonProcessingException {
        // Handle the different date formats here!

        return new Item(/*parsed date object*/);
    }
}

Define the Deserializer for the object via annotations

@JsonDeserialize(using = ItemDeserializer.class)
public class Item {
    // ...
}
pacifier21
  • 813
  • 1
  • 5
  • 13