Почему, когда конструктор аннотируется @JsonCreator, его аргументы должны быть аннотированы @JsonProperty?

109

В Джексоне, когда вы аннотируете конструктор с помощью @JsonCreator, вы должны аннотировать его аргументы с помощью @JsonProperty. Итак, этот конструктор

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

становится это:

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

Я не понимаю, зачем это нужно. Не могли бы вы объяснить?

Ори Поповски
источник

Ответы:

113

Джексон должен знать, в каком порядке передавать поля из объекта JSON в конструктор. В Java невозможно получить доступ к именам параметров с помощью отражения - поэтому вам необходимо повторить эту информацию в аннотациях.

Лукаш Виктор
источник
9
Это не действует для Java8
MariuszS
12
@MariuszS Это правда, но в этом посте объясняется, как избавиться от посторонних аннотаций с помощью флага компилятора Java8 и модуля Джексона. Я протестировал этот подход, и он работает.
квант
Конечно, работает как шарм :) docs.oracle.com/javase/tutorial/reflect/member/…
MariuszS
52

Имена параметров обычно недоступны для кода Java во время выполнения (потому что они отбрасываются компилятором), поэтому, если вам нужна эта функциональность, вам нужно либо использовать встроенную функциональность Java 8, либо использовать библиотеку, такую ​​как ParaNamer, чтобы получить доступ. к нему.

Поэтому, чтобы не использовать аннотации для аргументов конструктора при использовании Джексона, вы можете использовать любой из этих двух модулей Джексона:

имена-параметров-модуля-Джексона

Этот модуль позволяет получать аргументы конструктора без аннотаций при использовании Java 8 . Чтобы использовать его, вам сначала необходимо зарегистрировать модуль:

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

Затем скомпилируйте свой код, используя флаг -параметры:

javac -parameters ...

Ссылка: https://github.com/FasterXML/jackson-modules-java8/tree/master/parameter-names

Джексон-модуль-параметр

Этот другой просто требует, чтобы вы зарегистрировали модуль или настроили самоанализ аннотации (но не то и другое, как указано в комментариях). Он позволяет использовать аргументы конструктора без аннотаций в версиях Java до 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());

Ссылка на сайт: https://github.com/FasterXML/jackson-modules-base/tree/master/paranamer

Родриго Кесада
источник
28

Можно избежать аннотаций конструктора с помощью jdk8, где необязательно компилятор будет вводить метаданные с именами параметров конструктора. Затем с модулем jackson-module-parameter-names Джексон может использовать этот конструктор. Вы можете увидеть пример в посте Джексона без аннотаций

Манос Николаидис
источник
устарело и перемещено в jackson-modules-java8 / parameter-names
naXa
6

Поскольку байт-код Java не сохраняет имена аргументов метода или конструктора.

ЖК-дисплей
источник
Больше не соответствует действительности: docs.oracle.com/javase/tutorial/reflect/member/…
MariuszS
1
@MariuszS действительно, но поскольку это новый (и нестандартный флаг компилятора), Джексон должен будет продолжать поддерживать его @JsonPropertyаннотацию
lcfd
6

Можно просто использовать аннотацию java.bean.ConstructorProperties - она ​​намного менее многословна, и Джексон также ее принимает. Например :

  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

Когда я понимаю , это правильно, вы замените конструктор по умолчанию с параметризованным один и , следовательно , должны описать ключи JSON , которые используются для вызова конструктора с.

Smutje
источник
3

Как указано в документации по аннотации , аннотация указывает, что имя аргумента используется как имя свойства без каких-либо изменений, но для него можно указать непустое значение, чтобы указать другое имя:

Гай Буалье
источник
0

Просто наткнулся на это и где-то получил ответ. вы можете использовать аннотацию ниже, начиная с 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;
    }
}
Андрей
источник