Mengapa ketika konstruktor dianotasi dengan @JsonCreator, argumennya harus dianotasi dengan @JsonProperty?

109

Di Jackson, saat Anda memberi anotasi pada konstruktor @JsonCreator, Anda harus memberi anotasi pada argumennya @JsonProperty. Jadi konstruktor ini

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

menjadi ini:

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

Saya tidak mengerti mengapa itu perlu. Bisakah Anda menjelaskan?

Ori Popowski
sumber

Jawaban:

113

Jackson harus mengetahui dalam urutan apa untuk meneruskan bidang dari objek JSON ke konstruktor. Tidak mungkin untuk mengakses nama parameter di Java menggunakan refleksi - itulah mengapa Anda harus mengulangi informasi ini dalam anotasi.

Lukasz Wiktor
sumber
9
Ini tidak berlaku untuk Java8
MariuszS
12
@MariuszS Itu benar tetapi posting ini menjelaskan bagaimana menghilangkan anotasi asing dengan bantuan bendera compiler Java8 dan modul Jackson. Saya telah menguji pendekatannya dan berhasil.
kuantum
Tentu, bekerja seperti pesona :) docs.oracle.com/javase/tutorial/reflect/member/…
MariuszS
52

Nama parameter biasanya tidak dapat diakses oleh kode Java saat runtime (karena dijatuhkan oleh kompiler), jadi jika Anda menginginkan fungsionalitas itu, Anda perlu menggunakan fungsionalitas bawaan Java 8 atau menggunakan pustaka seperti ParaNamer untuk mendapatkan akses untuk itu.

Jadi agar tidak harus menggunakan anotasi untuk argumen konstruktor saat menggunakan Jackson, Anda dapat menggunakan salah satu dari 2 modul Jackson berikut:

jackson-module-parameter-names

Modul ini memungkinkan Anda mendapatkan argumen konstruktor bebas anotasi saat menggunakan Java 8 . Untuk menggunakannya, Anda harus mendaftarkan modul terlebih dahulu:

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

Kemudian kompilasi kode Anda menggunakan tanda -parameters:

javac -parameters ...

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

jackson-modul-paranamer

Yang lainnya ini hanya mengharuskan Anda untuk mendaftarkan modul atau mengkonfigurasi introspeksi anotasi (tetapi tidak keduanya seperti yang ditunjukkan oleh komentar). Ini memungkinkan Anda untuk menggunakan argumen konstruktor bebas anotasi pada versi Java sebelum 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());

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

Rodrigo Quesada
sumber
6

Karena bytecode Java tidak menyimpan nama metode atau argumen konstruktor.

lcfd
sumber
1
@MariuszS memang, tetapi karena ini adalah baru (dan bendera compiler non-default), Jackson harus terus mendukung @JsonPropertyanotasinya
lcfd
6

Seseorang dapat dengan mudah menggunakan anotasi java.bean.ConstructorProperties - jauh lebih sedikit verbose dan Jackson juga menerimanya. Sebagai contoh :

  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
sumber
4

Ketika saya memahami ini dengan benar, Anda mengganti konstruktor default dengan yang berparameter dan karena itu harus menjelaskan kunci JSON yang digunakan untuk memanggil konstruktor dengan.

Smutje
sumber
3

Seperti yang dijelaskan sebelumnya dalam dokumentasi anotasi , anotasi tersebut menunjukkan bahwa nama argumen digunakan sebagai nama properti tanpa modifikasi apa pun, tetapi dapat ditentukan ke nilai yang tidak kosong untuk menentukan nama yang berbeda:

Guy Bouallet
sumber
0

Temukan saja dan dapatkan jawaban di suatu tempat. Anda dapat menggunakan anotasi di bawah ini sejak 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;
    }
}
Andrew
sumber