เหตุใดเมื่อตัวสร้างถูกใส่คำอธิบายประกอบด้วย @JsonCreator อาร์กิวเมนต์ของมันจึงต้องใส่คำอธิบายประกอบด้วย @JsonProperty


109

ใน Jackson เมื่อคุณใส่คำอธิบายประกอบตัวสร้างด้วย@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 และโมดูลแจ็คสัน ฉันได้ทดสอบแนวทางแล้วและได้ผล
quantum

แน่นอนทำงานอย่างมีเสน่ห์ :) docs.oracle.com/javase/tutorial/reflect/member/…
MariuszS

52

โดยปกติชื่อพารามิเตอร์จะไม่สามารถเข้าถึงได้โดยโค้ด Java ที่รันไทม์ (เนื่องจากถูกส่งโดยคอมไพเลอร์) ดังนั้นหากคุณต้องการฟังก์ชันดังกล่าวคุณจำเป็นต้องใช้ฟังก์ชันในตัวของ Java 8 หรือใช้ไลบรารีเช่น ParaNamer เพื่อเข้าถึง ไปเลย

ดังนั้นเพื่อที่จะไม่ต้องใช้คำอธิบายประกอบสำหรับอาร์กิวเมนต์ตัวสร้างเมื่อใช้ Jackson คุณสามารถใช้ประโยชน์จากโมดูลแจ็คสัน 2 โมดูลเหล่านี้:

แจ็คสันโมดูลพารามิเตอร์ชื่อ

โมดูลนี้จะช่วยให้คุณได้สร้างอาร์กิวเมนต์คำอธิบายประกอบฟรีเมื่อใช้Java 8 ในการใช้งานคุณต้องลงทะเบียนโมดูลก่อน:

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

จากนั้นคอมไพล์โค้ดของคุณโดยใช้แฟล็ก -parameters:

javac -parameters ...

ลิงก์: https://github.com/FasterXML/jackson-modules-java8/tree/master/parameter-names

แจ็คสันโมดูล 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());

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


28

เป็นไปได้ที่จะหลีกเลี่ยงการใส่คำอธิบายประกอบตัวสร้างด้วย jdk8 โดยที่คอมไพลเลอร์จะแนะนำเมทาดาทาพร้อมชื่อของพารามิเตอร์คอนสตรัคเตอร์ จากนั้นด้วยโมดูลชื่อแจ็คสันโมดูลพารามิเตอร์แจ็คสันสามารถใช้ตัวสร้างนี้ คุณสามารถดูตัวอย่างได้ที่โพสต์Jackson โดยไม่มีคำอธิบายประกอบ


เลิกใช้งานและย้ายไปที่jackson-module-java8 / parameter-names
naXa

6

เนื่องจาก Java bytecode ไม่เก็บชื่อของอาร์กิวเมนต์เมธอดหรือคอนสตรัคเตอร์


ไม่จริงอีกต่อไป: docs.oracle.com/javase/tutorial/reflect/member/…
MariuszS

1
@MariuszS แน่นอน แต่เนื่องจากนี่เป็นแฟล็กคอมไพเลอร์ใหม่ (และไม่ใช่ค่าเริ่มต้น) แจ็คสันจะต้องสนับสนุน@JsonPropertyคำอธิบายประกอบต่อไป
lcfd

6

เราสามารถใช้คำอธิบายประกอบ java.bean.ConstructorProperties - มันเป็น verbose น้อยกว่ามากและ Jackson ก็ยอมรับเช่นกัน ตัวอย่างเช่น :

  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;
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.