jacksonjson-deserializationjackson-databind

Configure Jackson Deserialzer using static method for types with a given super class


Currently I am getting an exception when deserializing a codestable typed class.

Imagine the following scenario:

public abstract class AbstractCodestableEntry implements java.io.Serializable {

    private final String category;
    private final String code;

    protected AbstractCodestableEntry(final String category, final String code) {
        this.category = category;
        this.code = code;
    }

    // Getter for category and code
}

Here is one example of a concrete codestable class. Of this type we have ~100 classes (salutation, gender, workdays, ... and a lot of more functional related codestables)

public class SalutationCodestableEntry extends AbstractCodestableEntry {

    public static final String KATEGORIE = "SALUTATION";

    public static final SalutationCodestableEntry MR = new SalutationCodestableEntry ("1");
    public static final SalutationCodestableEntry MRS = new SalutationCodestableEntry ("2");
    ...

    private static final Map<String, SalutationCodestableEntry> BY_CODE = initCache();

    private SalutationCodestableEntry(final String code) {
        super(KATEGORIE, code);
    }

    private static Map<String, SalutationCodestableEntry> initCache() {
        final SalutationCodestableEntry[] values = new SalutationCodestableEntry[] {MR, MRS, ...};
        final Map<String, SalutationCodestableEntry> map = new HashMap<>();
        for (final SalutationCodestableEntry e : values) {
            map.put(e.getCode(), e);
        }
        return Collections.unmodifiableMap(map);
    }

    public static SalutationCodestableEntry valueOf(final String code) {
        return BY_CODE.get(code);
    }
}

When serializing an attribute of type SalutationCodestableEntry to JSON it looks like this

"org.company.SalutationCodestableEntry":{"category":"SALUTATION","code":"1"}

Currently when deserializing this I get the following exception:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `org.company.SalutationCodestableEntry` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: UNKNOWN; byte offset: #UNKNOWN] (through reference chain: java.lang.Object[][0]->org.company.Dto["codestableEntry"])

I can adjust all the classes as I want, but actually

I already did some special serializing configurations for a few classes with Mixins. But that seems not to work here because of the inheritance (SalutationCodestableEntry extends AbstractCodestableEntry) and the use of a static method to return an object (SalutationCodestableEntry.valueOf(String code)).

Currently my ObjectMapper configuration looks like this

    @Bean(name = OBJECTMAPPER_QUALIFIER)
    public ObjectMapper outboxObjectMapper() {    
        return new ObjectMapper()
            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true)
            .registerModule(new JavaTimeModule())
            .addMixIn(AnySpecialClass.class, AnySpecialClassMixin.class)
            .addMixIn(...);
    }

Is there any way to let Jackson know how to deserialize the codestable classes (like SalutationCodestableEntry)?


Solution

  • I asked this question on Jackson's GitHub: https://github.com/FasterXML/jackson/discussions/237

    I solved this by adding the @JsonCreator annotation to all concrete codestable classes e.g.

        @JsonCreator
        public static SalutationCodestableEntry valueOf(final @JsonProperty("code") code) {
            return BY_CODE.get(code);
        }
    

    As the codestable classes are generated and I am able to adjust the generator this seems to be the easiest solution for me in this case, even if I was looking for another centralized solution without modifying the concrete codestable classes.