Menelaos
Menelaos

Reputation: 26004

Multiple JsonCreator annotated methods

Initial Question

Is it possible to have multiple @JsonCreator methods, and for jackson to detect which one it should use depending on the method definiton?

@JsonCreator
public static StateOfComm factory(String id) {
    return StateOfComm.valueOf(id);
}

@JsonCreator
public static StateOfComm factory(CustomType value) {
    return StateOfComm.valueOf(value.getId());  
}

Update

The JSON that fails (because id=null), is the following:

{"comment":null, "processes":[{"stateOfComm":{"id":"CA"}}]}

The following works:

 {"comment":null, "processes":[{"stateOfComm":"CA"}]}

Upvotes: 7

Views: 12950

Answers (3)

Menelaos
Menelaos

Reputation: 26004

I solved this problem by getting rid of the @JsonCreator annotations, and using a custom StdDeserializer that did the trick.

Here is an example:

@JsonIgnoreProperties(
        ignoreUnknown = true
    )
    @JsonDeserialize(
        using = IdTextEntry.Deserializer.class
    )
    @Data
    public class IdTextEntry implements IdAndText {
        String id;
        String text;

        public IdTextEntry(Enum<?> val) {
            if (val != null) {
                this.id = val.name();
                this.text = val.toString();
            }

        }        

        public static class Deserializer extends StdDeserializer<IdTextEntry> {
            public Deserializer() {
                this((Class)null);
            }

            Deserializer(Class<?> vc) {
                super(vc);
            }

            public IdTextEntry deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
                JsonNode node = (JsonNode)jp.getCodec().readTree(jp);
                String id;
                if (node.has("id") && node.has("text")) {
                    id = node.get("id").asText();
                    String text = node.get("text").asText();
                    return new IdTextEntry(id, text);
                } else if (node.has("id")) {
                    id = node.get("id").asText();
                    return new IdTextEntry(id, id);
                } else {
                    id = node.asText();
                    return new IdTextEntry(id, id);
                }
            }
        }
    }

Upvotes: 4

Manos Nikolaidis
Manos Nikolaidis

Reputation: 22234

I was able to parse both JSON examples in your question by:

  1. using jackson-modules-java8 version 2.9.1 dependency
  2. invoking the java 8 compiler with -parameters argument
  3. introducing all argument constructors for all classes involved
  4. avoiding @JsonProperty on static creation methods and constructors
  5. defining a class:

    class CustomType {
        private final String id;
    }
    

My understanding is that Jackson couldn't discern between multiple creators in older version. E.g. see answer here and github issue here. It seems that the option to have parameter names in compiled code in java 8 helps in this case.

Upvotes: 3

Yogi
Yogi

Reputation: 1895

You can have multiple @JsonCreator methods but it requires to use @JsonProperty for specifying which property you are initializing.

@JsonCreator
public static StateOfComm factory(@JsonProperty("id") String id) {
    return StateOfComm.valueOf(id);
}

@JsonCreator
public static StateOfComm factory(@JsonProperty("value") CustomType value) {
    return StateOfComm.valueOf(value.getId());  
}

Upvotes: -1

Related Questions