Parse Json thành object dựa vào type

Bài viết này mình sẽ hướng dẫn cách để parse từ json thành object dựa vào type. Vì đôi khi json của chúng ta sẽ có nhiều dạng, và bạn muốn parse ra object dựa vào dạng, ví dụ json dạng A thì parse ra object A còn json dạng B thì parse ra object

Bài viết này mình sẽ hướng dẫn cách để parse từ json thành object dựa vào type. Vì đôi khi json của chúng ta sẽ có nhiều dạng, và bạn muốn parse ra object dựa vào dạng, ví dụ json dạng A thì parse ra object A còn json dạng B thì parse ra object B.

1. Miêu tả project

Tưởng tượng chúng ta là một là quản lí dân cư ở 1 khu vực. Ở khu vực chúng ta có 2 dạng dân cư, một là học sinh, 2 là người trưởng thành (người đã đi làm), mỗi dạng dân cư có những property riêng và chúng ta muốn lưu những properties này dưới dạng json trong database. Khi lấy data dạng json này lên, ta muốn application của chúng ta dựa vào type (học sinh hoặc người đi làm) để parse json này ra những object cần thiết và xử lí tiếp.

2. Tạo project

Chúng ta vào trang https://start.spring.io/ và tạo project spring boot
image.png

Chúng ta sẽ sử dụng in-memory database h2 cho project.

3. Config project

3.1 Project structure

image.png

3.2 Những files cần tạo

  • Config application.properties:

        spring.datasource.url=jdbc:h2:mem:demojsonmapping
        spring.datasource.driverClassName=org.h2.Driver
        spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
        spring.jpa.defer-datasource-initialization=true
        
    
  • Tạo file schema.sql và data.sql

    • schema.sql:
      DROP TABLE IF EXISTS resident;
      
      CREATE TABLE resident (id INT AUTO_INCREMENT  PRIMARY KEY,
        name VARCHAR(250) NOT NULL,
        address VARCHAR(250) NOT NULL,
        metadata VARCHAR(10000) NOT NULL
      );

    metadata là column để lưu những properties của resident

    • data.sql:
      INSERT INTO
       resident (name, address, metadata)
        VALUES
      ('Thanh', 'Ho Chi Minh', '{"type": "student", "mode" : "active", "classNumber": 10}'),
      ('Bao', 'Gia Lai', '{"type": "mature", "mode" : "active", "maritalStatus": "single"}');
  • Resident entity:

    @Getter@Setter@EntitypublicclassResident{@Id@GeneratedValue(strategy =GenerationType.IDENTITY)privateint id;privateString name;privateString address;privateString metadata;}
  • Metadata interface: đây là 1 interface chung cho metadata của những resident (học sinh và người trưởng thành)

    @JsonSubTypes({@JsonSubTypes.Type(StudentMetadata.class),@JsonSubTypes.Type(MatureMetadata.class)})@JsonTypeInfo(
         use =JsonTypeInfo.Id.NAME,
         include =JsonTypeInfo.As.PROPERTY,
         property ="type")publicinterfaceMetadata{StringgetMode();}

@JsonSubTypes: ở đây mình sẽ define ra những class có thể được parse ra của json metadata, cụ thể ở đây có StudentMetadata class và MatureMetadata class.

@JsonTypeInfo: chứa những thông tin cho việc serialization và deserialization JSON, chúng ta sẽ dựa vào property “type” để xác định nó thuộc vào object nào.
Cả 2 class metadata đểu có chung thuộc tính mode nên chúng ta sẽ để 1 abstract method getMode trong interface Metadata.

  • StudentMetadata:
    @JsonTypeName("student")@Getter@Setter@ToStringpublicclassStudentMetadataimplementsMetadata{privateString mode;privateint classNumber;}

@JsonTypeName: logical name của type này, dùng để xác định khi parse từ json sang object

  • MatureMetadata:

    @JsonTypeName("mature")@Getter@Setter@ToStringpublicclassMatureMetadataimplementsMetadata{privateString mode;privateString maritalStatus;}
  • StudentRepository:

    @RepositorypublicinterfaceResidentRepositoryextendsJpaRepository<Resident,Integer>{}
  • StudentController:

    @RestController@RequestMapping("/residents")@RequiredArgsConstructor@Slf4jpublicclassResidentController{privatefinalResidentRepository residentRepository;@GetMapping("/metadata/{id}")publicvoidprintMetadataOfStudent(@PathVariableint id)throwsJsonProcessingException{Resident resident = residentRepository.getById(id);Metadata metadata =newObjectMapper().readerFor(Metadata.class).readValue(resident.getMetadata());if(metadata.getClass().equals(StudentMetadata.class)){StudentMetadata studentMetadata =(StudentMetadata)metadata;
                    log.info("This is a student");
                    log.info("Student metadata: {}", studentMetadata);}elseif(metadata.getClass().equals(MatureMetadata.class)){MatureMetadata matureMetadata =(MatureMetadata)metadata;
                    log.info("This is a mature person");
                    log.info("Mature metadata: {}", matureMetadata);}else{
                    log.info("No matching resident");}}}

Chúng ta sẽ parse từ json string ra Metadata object. Sau đó chúng ta sẽ compare class đó với StudentMetadata hoặc MatureMetadata rồi parse ra thành những object và chúng ta sẽ lấy được những property cần thiết. Ở đây mình sẽ log ra những thông tin của metadata này.

4. Test

  • Run project
  • Gọi postman với id = 1 và check log
    • image.png
    • image.png
  • Gọi postman với id = 2 và check log
    • image.png
    • image.png

5. References

Nguồn: viblo.asia

Bài viết liên quan

9 Mẹo lập trình Web “ẩn mình” giúp tiết kiệm hàng giờ đồng hồ

Hầu hết các lập trình viên (kể cả những người giỏi) đều tốn thời gian x

Can GPT-4o Generate Images? All You Need to Know about GPT-4o-image

OpenAI‘s GPT-4o, introduced on March 25, 2025, has revolutionized the way we create visual con

Khi nào nên dùng main, section, article, header, footer, và aside trong HTML5

HTML5 đã giới thiệu các thẻ ngữ nghĩa giúp cấu trúc nội dung web một cách có

So sánh Webhook và API: Khi nào nên sử dụng?

Trong lĩnh vực công nghệ thông tin và phát triển phần mềm, Webhook và API là hai th