Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Java

Tầm quan trọng của @JsonView trong Jackson (Java)

Annotation @JsonView cho phép **dynamic include/exclude field** khi serialize/deserialize dựa trên **View class**. Cấu hình qua ObjectMapper.writerWithView().

Cú pháp

@Target({ANNOTATION_TYPE, METHOD, FIELD})
@Retention(RUNTIME)
public @interface JsonView {
    Class<?>[] value() default {};
}

Ví dụ: Public vs Internal View

import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonViewTest {
    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        
        // Public view - chỉ field có @JsonView(Public.class)
        String publicJson = mapper.writerWithView(Views.Public.class)
                                  .writeValueAsString(new Person());
        
        // Internal view - field Public + Internal (Internal extends Public)
        String internalJson = mapper.writerWithView(Views.Internal.class)
                                    .writeValueAsString(new Person());
        
        System.out.println("Public:  " + publicJson);
        System.out.println("Internal: " + internalJson);
    }
}

class Person {
    @JsonView(Views.Public.class)
    public long personId = 115;
    
    @JsonView(Views.Public.class)
    public String personName = "Raja Ramesh";
    
    @JsonView(Views.Internal.class)
    public String gender = "male";
}

class Views {
    static class Public {}
    static class Internal extends Public {} // Internal kế thừa Public → thấy cả 2
}

Output

Public:  {"personId":115,"personName":"Raja Ramesh"}
Internal: {"personId":115,"personName":"Raja Ramesh","gender":"male"}

Cơ chế kế thừa View

  • View class có thể **extends** view khác.
  • Sub-view **kế thừa** field của parent view.
  • Ví dụ: Internal extends Public → Internal thấy field Public + Internal.

Deserialize với View

// Chỉ deserialize field thuộc view Public
Person p = mapper.readerWithView(Views.Public.class)
                 .forType(Person.class)
                 .readValue(jsonString);

Use case thực tế

  • **API versioning**: v1 = Public view, v2 = Extended view.
  • **Role-based**: User view vs Admin view (Internal extends Public).
  • **Performance**: Tránh serialize field nặng (blob, large text) cho list view.
  • **DTO replacement**: Thay vì tạo nhiều DTO class, dùng 1 entity + multiple views.

Best Practice

  • Đặt View class là static inner class của entity hoặc package riêng.
  • Dùng interface thay vì class cho view (Jackson hỗ trợ cả hai).
  • Kết hợp với @JsonIgnore cho field không bao giờ serialize.
  • Disable MapperFeature.DEFAULT_VIEW_INCLUSION để field không có @JsonView bị exclude mặc định.