Annotation @JsonAnyGetter อนุญาตให้ใช้ Map เป็น container สำหรับ properties ที่ต้องการ serialize เป็น JSON ส่วน @JsonAnySetter สั่งให้ Jackson เรียก setter method เดียวกันสำหรับ unrecognized fields ทั้งหมดใน JSON object (ฟิลด์ที่ไม่ได้ map ไป property หรือ setter ใน Java object)
ไวยากรณ์
public @interface JsonAnyGetter
public @interface JsonAnySetter
ตัวอย่างโค้ดครบถ้วน
import java.io.*;
import java.util.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.annotation.*;
public class JsonAnyGetterAndSetterTest {
public static void main(String[] args) throws Exception {
Employee emp1 = new Employee();
emp1.setFirstName("Adithya");
emp1.setLastName("Sai");
emp1.setEmpId(125);
emp1.getAdditionalInformation().put("technology1", "Machine Learning");
emp1.getAdditionalInformation().put("technology2", "Robotics");
ObjectMapper mapper = new ObjectMapper();
String jsonStr = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(emp1);
System.out.println(jsonStr);
System.out.println("Deserializing JSON to Object:");
Employee emp2 = mapper.readValue(jsonStr, Employee.class);
System.out.println("id: " + emp2.getEmpId());
System.out.println("firstName: " + emp2.getFirstName());
System.out.println("lastName: " + emp2.getLastName());
System.out.println("Additional info: " + emp2.getAdditionalInformation());
}
}
// Employee class
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"firstName", "lastName", "technologies", "empId"})
class Employee {
@JsonProperty("EMPLOYEE_ID")
private int empId;
@JsonProperty("EMPLOYEE_FIRST_NAME")
private String firstName;
@JsonProperty("EMPLOYEE_LAST_NAME")
private String lastName;
private Map<String, String> additionalInformation = new HashMap<>();
// Getters & Setters...
public int getEmpId() { return empId; }
public void setEmpId(int empId) { this.empId = empId; }
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
@JsonAnyGetter
public Map<String, String> getAdditionalInformation() {
return additionalInformation;
}
public void setAdditionalInformation(Map<String, String> additionalInformation) {
this.additionalInformation = additionalInformation;
}
@JsonAnySetter
public void setAdditionalProperty(String name, String value) {
this.additionalInformation.put(name, value);
}
}
ผลลัพธ์
{
"EMPLOYEE_FIRST_NAME" : "Adithya",
"EMPLOYEE_LAST_NAME" : "Sai",
"EMPLOYEE_ID" : 125,
"technology1" : "Machine Learning",
"technology2" : "Robotics"
}
Deserializing JSON to Object:
id: 125
firstName: Adithya
lastName: Sai
Additional information: {technology1=Machine Learning, technology2=Robotics}
เมื่อไหร่ควรใช้
- @JsonAnyGetter: ต้องการ serialize dynamic properties / extension data / metadata ที่ไม่มีฟิลด์คงที่
- @JsonAnySetter: ต้องการ deserialize JSON ที่มีฟิลด์เพิ่มเติม ไม่รู้ล่วงหน้าว่ามีฟิลด์อะไรบ้าง (flexible schema)
- คู่กันใช้สำหรับ Open Content Models / Schema Evolution
ข้อควรระวัง
- Map key ต้องเป็น String
- ควรใช้ร่วมกับ
@JsonInclude(Include.NON_NULL)เพื่อไม่ serialize map ว่าง - Type safety ต่ำกว่า POPTH ธรรมดา - ควร validate ข้อมูลหลัง deserialize