You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jackson JSON反序列化:将子节点列表转换为POJO列表

Solution for Deserializing subnode into List in Custom Deserializer

Got it, let's break down how to implement this properly. Since you're already extending StdDeserializer<MyObject>, you can use Jackson's built-in tools to convert the subnode array into a list of your Subnode POJOs cleanly.

Step-by-Step Implementation

Here's a complete example of your custom deserializer, along with the supporting POJOs:

First, your Subnode and MyObject classes (assuming they have standard getters/setters or use Jackson's annotations for field access):

public class Subnode {
    private String snProperty1;
    private String snProperty2;
    // ... add other properties as needed
    
    // Default constructor required for Jackson deserialization
    public Subnode() {}
    
    // Add getters and setters for all properties
    public String getSnProperty1() { return snProperty1; }
    public void setSnProperty1(String snProperty1) { this.snProperty1 = snProperty1; }
    
    public String getSnProperty2() { return snProperty2; }
    public void setSnProperty2(String snProperty2) { this.snProperty2 = snProperty2; }
}

public class MyObject {
    private String property1;
    private List<Subnode> subnodeList;
    // ... add other top-level properties as needed
    
    public MyObject() {}
    
    // Getters and setters
    public String getProperty1() { return property1; }
    public void setProperty1(String property1) { this.property1 = property1; }
    
    public List<Subnode> getSubnodeList() { return subnodeList; }
    public void setSubnodeList(List<Subnode> subnodeList) { this.subnodeList = subnodeList; }
}

Now the custom deserializer implementation:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.type.CollectionType;

import java.io.IOException;
import java.util.List;

public class MyObjectDeserializer extends StdDeserializer<MyObject> {

    // Default constructor required for Jackson
    public MyObjectDeserializer() {
        this(null);
    }

    public MyObjectDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public MyObject deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        // 1. Read the entire JSON structure into a JsonNode for navigation
        JsonNode rootNode = p.getCodec().readTree(p);
        
        // 2. Initialize your target MyObject instance
        MyObject myObject = new MyObject();
        
        // 3. Handle top-level properties like property1
        if (rootNode.has("property1")) {
            myObject.setProperty1(rootNode.get("property1").asText());
        }
        
        // 4. Convert the subnode array to List<Subnode>
        if (rootNode.has("subnode")) {
            JsonNode subnodeArray = rootNode.get("subnode");
            if (subnodeArray.isArray()) {
                // Create a typed reference for List<Subnode> so Jackson knows the generic type
                CollectionType listType = ctxt.getTypeFactory()
                        .constructCollectionType(List.class, Subnode.class);
                
                // Use the deserialization context to parse the array into the list
                List<Subnode> subnodeList = ctxt.readValue(subnodeArray.traverse(p.getCodec()), listType);
                myObject.setSubnodeList(subnodeList);
            } else {
                // Optional: Handle non-array cases (return empty list or throw error)
                throw new IOException("Expected 'subnode' to be a JSON array");
            }
        } else {
            // Optional: Handle missing subnode (e.g., set empty list instead of throwing)
            myObject.setSubnodeList(List.of());
        }
        
        // 5. Add handling for other top-level properties here
        // ...
        
        return myObject;
    }
}

Key Details Explained

  • Reading the JSON Tree: p.getCodec().readTree(p) gives you a navigable JsonNode representing the entire input JSON, making it easy to access nested nodes like subnode.
  • Generic Type Handling: Using ctxt.getTypeFactory().constructCollectionType(...) tells Jackson exactly what type of list we want to deserialize into (critical for generic types like List<Subnode>).
  • Reusing Configurations: subnodeArray.traverse(p.getCodec()) ensures we use the same ObjectMapper instance from the current deserialization context, preserving any custom configurations (like date formats or other deserializers) you've set up.
  • Flexible Error Handling: The checks for subnode existence and array type let you handle edge cases gracefully—you can adjust this to return an empty list instead of throwing an exception if that fits your use case better.

Registering the Deserializer

To make Jackson use your custom deserializer, you have two options:

  1. Annotation-based: Add @JsonDeserialize to your MyObject class:
@JsonDeserialize(using = MyObjectDeserializer.class)
public class MyObject {
    // ... existing code
}
  1. ObjectMapper configuration: Register the deserializer directly on your ObjectMapper:
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(MyObject.class, new MyObjectDeserializer());
mapper.registerModule(module);

内容的提问来源于stack exchange,提问作者geco17

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:04:47