Чому, коли конструктор позначається за допомогою @JsonCreator, його аргументи повинні бути помічені за допомогою @JsonProperty?


108

У Джексоні, коли ви коментуєте конструктор за допомогою @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;
}

Я не розумію, чому це потрібно. Чи можете ви поясніть, будь ласка?

Відповіді:


112

Джексон повинен знати, в якому порядку передавати поля від об'єкта JSON конструктору. Доступ до імен параметрів у Java за допомогою відображення неможливо - саме тому вам доведеться повторювати цю інформацію в анотаціях.


9
Це не дійсно для Java8
MariuszS

12
@MariuszS Це правда, але цей пост пояснює, як позбутися сторонніх приміток за допомогою прапора компілятора Java8 та модуля Джексона. Я перевірив підхід, і він працює.
квантовий

Звичайно, працює як шарм :) docs.oracle.com/javase/tutorial/reflect/member/…
MariuszS

52

Імена параметрів, як правило, недоступні коду Java під час виконання (тому що це скидання компілятором), тому якщо ви хочете, щоб ця функціональність вам була потрібна або вбудована функціональність Java 8, або використання бібліотеки, такої як ParaNamer, щоб отримати доступ йому.

Отже, щоб не використовувати анотації для аргументів конструктора при використанні Джексона, ви можете скористатися будь-яким із цих двох модулів Джексона:

jackson-module-parameter-names

Цей модуль дозволяє отримати аргументи конструктора без анотацій під час використання Java 8 . Щоб скористатися ним, спочатку потрібно зареєструвати модуль:

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

Потім компілюйте свій код, використовуючи прапор -parameters:

javac -parameters ...

Посилання: https://github.com/FasterXML/jackson-modules-java8/tree/master/parameter-names

jackson-module-paranamer

Цей інший просто вимагає зареєструвати модуль або налаштувати інтроспекцію анотацій (але не обидва, як зазначено в коментарях). Це дозволяє використовувати аргументи конструктора без анотацій у версіях 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 module Джексон може використовувати цей конструктор. Ви можете побачити приклад у посту Джексона без анотацій


застарілі і перейшли до jackson-module-java8 / parameter-names
naXa

6

Оскільки байт-код Java не зберігає назви аргументів методу чи конструктора.



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, які використовуються для виклику конструктора.


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;
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.