Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Java

วิธีนำ Custom Deserializer ไปใช้กับ @JsonDeserialize ใน Java

คำอธิบายประกอบ @JsonDeserialize ใช้ประกาศ custom deserializer ขณะ deserialize JSON เป็น Java object เราสามารถนำ custom deserializer ไปใช้โดยการ extends คลาส StdDeserializer พร้อม generic type Employee และ override เมธอด deserialize() ของ StdDeserializer

Syntax

@Target(value={ANNOTATION_TYPE, METHOD, FIELD, TYPE, PARAMETER})
@Retention(value=RUNTIME)
public @interface JsonDeserialize

ตัวอย่างการใช้งาน

import java.io.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.*;
import com.fasterxml.jackson.databind.deser.std.*;

public class JsonDeSerializeAnnotationTest {
    public static void main(String[] args) throws JsonProcessingException, IOException {
        Employee emp = new Employee(115, "Adithya");
        ObjectMapper mapper = new ObjectMapper();
        String jsonString = mapper.writeValueAsString(emp);
        emp = mapper.readValue(jsonString, Employee.class);
        System.out.println(emp);
    }
}

// CustomDeserializer class
class CustomDeserializer extends StdDeserializer<Employee> {
    public CustomDeserializer(Class<Employee> t) {
        super(t);
    }
    
    public CustomDeserializer() {
        this(Employee.class);
    }
    
    @Override
    public Employee deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
        int id = 0;
        String name = null;
        JsonToken currentToken = null;
        
        while ((currentToken = jp.nextValue()) != null) {
            switch (currentToken) {
                case VALUE_NUMBER_INT:
                    if (jp.getCurrentName().equals("id")) {
                        id = jp.getIntValue();
                    }
                    break;
                case VALUE_STRING:
                    switch (jp.getCurrentName()) {
                        case "name":
                            name = jp.getText();
                            break;
                        default:
                            break;
                    }
                    break;
                default:
                    break;
            }
        }
        return new Employee(id, name);
    }
}

// Employee class
@JsonDeserialize(using = CustomDeserializer.class)
class Employee {
    private int id;
    private String name;
    
    public Employee(int id, String name) {
        this.id = id;
        this.name = name;
    }
    
    public int getId() { return id; }
    public String getName() { return name; }
    
    @Override
    public String toString() {
        return "ID: " + this.id + "\nName: " + this.name;
    }
}

ผลลัพธ์ (Output)

ID: 115
Name: Adithya

คำอธิบาย

CustomDeserializer อ่าน JSON token ทีละตัว (streaming API) และสร้าง Employee object เอง โดยไม่ให้ Jackson map ฟิลด์อัตโนมัติ เหมาะสำหรับกรณีที่ JSON structure ไม่ตรงกับ Java class structure หรือต้องการ validation/transformation ระหว่าง deserialize

กรณีการใช้งาน (Use Cases)

  • JSON มีโครงสร้างต่างจาก Java class (field name ต่างกัน, nested structure)
  • ต้องการ validation หรือ transformation ข้อมูลระหว่าง deserialize
  • ต้องการจัดการ polymorphic types
  • ต้องการ parse วันที่/เวลาในรูปแบบเฉพาะ
  • ต้องการ ignore unknown fields แบบเงื่อนไข

สรุป

@JsonDeserialize ร่วมกับ custom deserializer ให้ความยืดหยุ่นสูงสุดในการควบคุมกระบวนการ deserialize เหมาะสำหรับกรณีซับซ้อนที่ default mapping ไม่เพียงพอ