Pregunta inicial

¿Es posible tener múltiples métodos @JsonCreator y que Jackson detecte cuál debe usar según la definición del método?

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

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

Actualizar

El JSON que falla (porque id = nulo) es el siguiente:

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

Los siguientes trabajos:

 {"comment":null, "processes":[{"stateOfComm":"CA"}]}
3
Menios 17 oct. 2017 a las 18:02

3 respuestas

La mejor respuesta

Resolví este problema deshaciéndome de las anotaciones @JsonCreator y usando un StdDeserializer personalizado que funcionó.

Aquí está un ejemplo:

@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);
                }
            }
        }
    }
1
Menios 18 sep. 2019 a las 18:22

Pude analizar ambos ejemplos de JSON en tu pregunta:

  1. utilizando la dependencia jackson-modules-java8 versión 2.9.1
  2. Invocar el compilador de Java 8 con el argumento -parameters
  3. Introducir todos los constructores de argumentos para todas las clases involucradas
  4. evitando @JsonProperty en métodos de creación estáticos y constructores
  5. definiendo una clase:

    class CustomType {
        private final String id;
    }
    

Tengo entendido que Jackson no pudo discernir entre múltiples creadores en la versión anterior. P.ej. vea la respuesta aquí y el problema de github aquí. Parece que la opción de tener nombres de parámetros en código compilado en Java 8 ayuda en este caso.

3
Manos Nikolaidis 19 oct. 2017 a las 10:30

Puede tener varios métodos @JsonCreator, pero requiere usar @JsonProperty para especificar qué propiedad está inicializando.

@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());  
}
0
Yogi 17 oct. 2017 a las 15:15