1

I am trying to use Jackson ObjectMappper to convert my Java POJO to Map. But, on converting, the Date changes to String.

This is my POJO:

public class Sample {

    @Id
    private String id;
    private Date date;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }
}

Here is my code:

@Test
public void testGenMap() {
    Sample sample = new Sample();
    sample.setId("a");
    sample.setDate(new Date());
    Map<String, Object> map = generateMap(sample);
    System.out.println(map.get("date") instanceof Date); //false
}

private Map<String, Object> generateMap(Sample sample) {
Map<String, Object> map = CommonsContextUtil.getBean(ObjectMapper.class).convertValue(sample,Map.class);
        map.values().removeIf(Objects::isNull);
        return map;
    }

I know this already has a possible answer here. But my ObjectMapper is already configured in the same way and still it is not working.

Here is the ObjectMapper Bean:

@Bean
public ObjectMapper objectMapper() {
    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    mapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    return mapper;
}
Shubham Rana
  • 370
  • 1
  • 4
  • 12
  • I believe you need to use custom Deserializer for that purposes. Or you could check this post https://stackoverflow.com/questions/50171472/deserialising-string-to-map-with-multiple-types-using-jackson – Echoinacup Jan 24 '19 at 17:23
  • Try to pass 'Sample.class' to 'readValue()' method on the mapper object. – Vebbie Jan 24 '19 at 17:27
  • FYI, the terribly troublesome old date-time classes such as [`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html), [`java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html), and `java.text.SimpleDateFormat` are now [legacy](https://en.wikipedia.org/wiki/Legacy_system), supplanted by the [*java.time*](https://docs.oracle.com/javase/10/docs/api/java/time/package-summary.html) classes built into Java 8 and later. See [*Tutorial* by Oracle](https://docs.oracle.com/javase/tutorial/datetime/TOC.html). – Basil Bourque Jan 25 '19 at 00:10
  • Better use solutions from here: https://stackoverflow.com/questions/6796187/java-introspection-object-to-map. That ObjectMapper loses object types info. – Gangnus Feb 24 '20 at 13:36

1 Answers1

3

When it comes to Dates, I usually create my own custom serializer and deserializer like so. This should solve your problem.

@Bean
public ObjectMapper objectMapper() {
    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    mapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    registerModule(
        new SimpleModule("foo")
            .addDeserializer(Date.class, new DateDeserializer())
            .addSerializer(Date.class, new DateSerializer())
    );
    return mapper;
}

Then have 2 static methods for deserialization and serialization:

    public static class DateSerializer extends StdScalarSerializer<Date> {

        public DateSerializer() {
            super(Date.class);
        }

        @Override
        public void serialize(Date value, JsonGenerator gen, SerializerProvider provider)
            throws IOException {
            String output = value.toString();
            gen.writeString(output);
        }
    }

    public static class DateDeserializer extends StdScalarDeserializer<Date> {

        public DateDeserializer() {
            super(Date.class);
        }

        @Override
        public LocalDate deserialize(JsonParser p, DeserializationContext ctxt)
            throws IOException {
            try {
                return Date.parse(p.getValueAsString());
            } catch (Exception e) {
                return null;
            }
        }
    }
Brandon
  • 933
  • 1
  • 10
  • 19
  • 1
    It makes ObjectMapper to create a pair key-value, where the value is a string. Yes, it is a string filled by the date, but it is NOT what is required. – Gangnus Feb 21 '20 at 15:21