2

Jackson version: 2.9.8

I'm converting an object not to JSON, but to a Map, using objectMapper.convertValue(myObject, Map.class)

Here is a simple example to reproduce. My Pojo:

public static class Foo {
    private final String string;
    private final LocalDate date;
    public Foo(String string, LocalDate date) {
        this.string = string;
        this.date = date;
    }
    public String getString() {
        return string;
    }
    public LocalDate getDate() {
        return date;
    }
}

Conversion code:

public static void main(String[] args) {
    Foo foo = new Foo("hello", LocalDate.of(1999, 12, 31));

    ObjectMapper objectMapper = new ObjectMapper();
    Map map = objectMapper.convertValue(foo, Map.class);

    Object string = map.get("string");
    System.out.println("string: >>>"+ string +"<<< of type "+ string.getClass().getName());

    Object date = map.get("date");
    System.out.println("date: >>>"+ date +"<<< of type "+ date.getClass().getName());
}

This prints:

string: >>>hello<<< of type java.lang.String
date: >>>{year=1999, month=DECEMBER, chronology={id=ISO, calendarType=iso8601}, era=CE, dayOfMonth=31, dayOfWeek=FRIDAY, dayOfYear=365, leapYear=false, monthValue=12}<<< of type java.util.LinkedHashMap

When enabling the JavaTimeModule with

objectMapper.registerModule(new JavaTimeModule());

it prints:

string: >>>hello<<< of type java.lang.String
date: >>>[1999, 12, 31]<<< of type java.util.ArrayList

But what I need is to KEEP the LocalDate instance in the Map. No conversion. I can't find how to configure Jackson to keep (not convert) a type.

I have tried with a noop converter:

private static class KeepLocalDateJsonSerializer extends JsonSerializer<LocalDate> {
    @Override
    public void serialize(LocalDate localDate, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeObject(localDate);
    }
};

registering it with

    SimpleModule mod = new SimpleModule("KeepLocalDate");
    mod.addSerializer(LocalDate.class, new KeepLocalDateJsonSerializer());
    objectMapper.registerModule(mod);

and this leads to a StackOverflowError with detail:

ReadOnlyClassToSerializerMap.typedValueSerializer(ReadOnlyClassToSerializerMap.java:85)
JsonMappingException: Infinite recursion $Foo["date"]

Apparently Jackson tries to convert the returned value also. Looks like a bug to me. If the converter writes the same object through, even the same instance, then obviously the intention is to keep it. When converting to JSON then I understand we can't keep a LocalDate instance, but in a Map that's not the case.

How can I achieve this, in a generic way, so that it works for any data structure? Without annotations in the Pojo. So that all instances of a certain data type are passed through untouched.

There is this similar question Jackson Convert Object to Map preserving Date type but it's 5 years old, uses Date not LocalDate, and the solution with SerializationFeature.WRITE_DATES_AS_TIMESTAMPS does not work here.

Fabian Kessler
  • 804
  • 11
  • 12

0 Answers0