Warum müssen seine Argumente mit @JsonProperty kommentiert werden, wenn ein Konstruktor mit @JsonCreator kommentiert wird?

107

Wenn Sie in Jackson einen Konstruktor mit @JsonCreatorAnmerkungen versehen , müssen Sie seine Argumente mit Anmerkungen versehen @JsonProperty. Also dieser Konstruktor

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

wird dies:

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

Ich verstehe nicht, warum es notwendig ist. Kannst du bitte Erklären?

Ori Popowski
quelle

Antworten:

112

Jackson muss wissen, in welcher Reihenfolge Felder von einem JSON-Objekt an den Konstruktor übergeben werden sollen. Es ist nicht möglich, über Reflection auf Parameternamen in Java zuzugreifen. Deshalb müssen Sie diese Informationen in Anmerkungen wiederholen.

Lukasz Wiktor
quelle
9
Dies gilt nicht für Java8
MariuszS
12
@MariuszS Das stimmt, aber in diesem Beitrag wird erklärt, wie Sie überflüssige Anmerkungen mithilfe des Java8-Compiler-Flags und eines Jackson-Moduls entfernen können. Ich habe den Ansatz getestet und es funktioniert.
Quanten
Natürlich funktioniert es wie ein Zauber :) docs.oracle.com/javase/tutorial/reflect/member/…
MariuszS
52

Auf Parameternamen kann der Java-Code normalerweise zur Laufzeit nicht zugreifen (da er vom Compiler gelöscht wird). Wenn Sie diese Funktionalität benötigen, müssen Sie entweder die integrierte Funktionalität von Java 8 oder eine Bibliothek wie ParaNamer verwenden, um Zugriff zu erhalten dazu.

Um bei der Verwendung von Jackson keine Anmerkungen für die Konstruktorargumente verwenden zu müssen, können Sie eines dieser beiden Jackson-Module verwenden:

Jackson-Modul-Parameternamen

Mit diesem Modul können Sie bei Verwendung von Java 8 annotationsfreie Konstruktorargumente abrufen . Um es verwenden zu können, müssen Sie zuerst das Modul registrieren:

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

Kompilieren Sie dann Ihren Code mit dem Flag -parameters:

javac -parameters ...

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

Jackson-Modul-Paranamer

Bei diesem anderen müssen Sie lediglich das Modul registrieren oder eine Introspektion für Anmerkungen konfigurieren (jedoch nicht beide, wie in den Kommentaren angegeben). Sie können annotationsfreie Konstruktorargumente für Java-Versionen vor 1.8 verwenden .

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

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

Rodrigo Quesada
quelle
6

Weil Java-Bytecode nicht die Namen von Methoden- oder Konstruktorargumenten enthält.

lcfd
quelle
1
@MariuszS in der Tat, aber da dies ein neues (und nicht standardmäßiges Compiler-Flag) ist, muss Jackson seine @JsonPropertyAnnotation weiterhin unterstützen
lcfd
6

Man kann einfach die Annotation java.bean.ConstructorProperties verwenden - sie ist viel weniger ausführlich und Jackson akzeptiert sie auch. Zum Beispiel :

  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;
  }
letowianka
quelle
4

Wenn ich das richtig verstehe , ersetzen Sie den Standardkonstruktor durch einen parametrisierten und müssen daher die JSON-Schlüssel beschreiben, mit denen der Konstruktor aufgerufen wird.

Smutje
quelle
3

Wie in der Annotationsdokumentation angegeben , gibt die Annotation an, dass der Argumentname ohne Änderungen als Eigenschaftsname verwendet wird. Er kann jedoch als nicht leerer Wert angegeben werden, um einen anderen Namen anzugeben:

Guy Bouallet
quelle
0

Kommen Sie einfach darauf und bekommen Sie irgendwo eine Antwort. Sie können die folgenden Anmerkungen seit 2.7.0 verwenden

@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;
    }
}
Andrew
quelle