¿Por qué cuando un constructor está anotado con @JsonCreator, sus argumentos deben anotarse con @JsonProperty?


108

En Jackson, cuando anota un constructor con @JsonCreator, debe anotar sus argumentos con @JsonProperty. Entonces este constructor

public Point(double x, double y) {
    this.x = x;
    this.y = y;
}

se convierte en esto:

@JsonCreator
public Point(@JsonProperty("x") double x, @JsonProperty("y") double y) {
    this.x = x;
    this.y = y;
}

No entiendo por qué es necesario. ¿Puede usted explicar por favor?

Respuestas:


112

Jackson tiene que saber en qué orden pasar los campos de un objeto JSON al constructor. No es posible acceder a los nombres de los parámetros en Java mediante la reflexión, por eso debe repetir esta información en las anotaciones.


9
Esto no es válido para Java8
MariuszS

12
@MariuszS Eso es cierto, pero esta publicación explica cómo deshacerse de anotaciones extrañas con la ayuda del indicador del compilador Java8 y un módulo Jackson. Probé el enfoque y funciona.
Quantum

Por supuesto, funciona como un encanto :) docs.oracle.com/javase/tutorial/reflect/member/…
MariuszS

52

Normalmente, el código Java no puede acceder a los nombres de los parámetros en tiempo de ejecución (porque el compilador los deja caer), por lo que si desea esa funcionalidad, debe usar la funcionalidad incorporada de Java 8 o usar una biblioteca como ParaNamer para obtener acceso lo.

Entonces, para no tener que utilizar anotaciones para los argumentos del constructor al usar Jackson, puede hacer uso de cualquiera de estos 2 módulos de Jackson:

nombres-de-parámetros-módulo-jackson

Este módulo le permite obtener argumentos de constructor sin anotaciones cuando usa Java 8 . Para utilizarlo, primero debe registrar el módulo:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new ParameterNamesModule());

Luego compila tu código usando la marca -parameters:

javac -parameters ...

Enlace: https://github.com/FasterXML/jackson-modules-java8/tree/master/parameter-names

jackson-module-paranamer

Este otro simplemente requiere que registre el módulo o configure una introspección de anotación (pero no ambos como lo señalan los comentarios). Le permite utilizar argumentos de constructor sin anotaciones en versiones de Java anteriores a la 1.8 .

ObjectMapper mapper = new ObjectMapper();
// either via module
mapper.registerModule(new ParanamerModule());
// or by directly assigning annotation introspector (but not both!)
mapper.setAnnotationIntrospector(new ParanamerOnJacksonAnnotationIntrospector());

Enlace: https://github.com/FasterXML/jackson-modules-base/tree/master/paranamer


28

Es posible evitar las anotaciones del constructor con jdk8 donde opcionalmente el compilador introducirá metadatos con los nombres de los parámetros del constructor. Luego, con el módulo jackson-module-parameter-names , Jackson puede usar este constructor. Puedes ver un ejemplo en la publicación Jackson sin anotaciones.




6

Uno puede simplemente usar la anotación java.bean.ConstructorProperties - es mucho menos detallada y Jackson también la acepta. Por ejemplo :

  import java.beans.ConstructorProperties;

  @ConstructorProperties({"answer","closed","language","interface","operation"})
  public DialogueOutput(String answer, boolean closed, String language, String anInterface, String operation) {
    this.answer = answer;
    this.closed = closed;
    this.language = language;
    this.anInterface = anInterface;
    this.operation = operation;
  }

4

Cuando entiendo esto correctamente, reemplaza el constructor predeterminado con uno parametrizado y, por lo tanto, tiene que describir las claves JSON que se utilizan para llamar al constructor.


3

Como se precisa en la documentación de la anotación , la anotación indica que el nombre del argumento se usa como el nombre de la propiedad sin ninguna modificación, pero se puede especificar un valor no vacío para especificar un nombre diferente:


0

Simplemente entréguelo y obtenga una respuesta en alguna parte. puede usar la anotación a continuación desde 2.7.0

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class Point {
    final private double x;
    final private double y;

    @ConstructorProperties({"x", "y"})
    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.