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

如何处理JSON转Java时同一字段多数据类型的映射问题

处理JSON动态value字段的Java对象映射方案

问题背景

给定如下JSON结构,其中attributes下的value字段类型不固定,可能是字符串、数组、对象甚至嵌套属性结构:

{
  "dataBlock": [
    {
      "headingName": {
        "name": "Operational Information",
        "position": "1",
        "attributes": [
          {
            "name": "Brand",
            "position": "1",
            "value": [
              "A",
              "B"
            ]
          },
          {
            "name": "Data Model Id",
            "position": "2",
            "value": "000001"
          }
        ]
      }
    },
    {
      "headingName": {
        "name": "CRA",
        "position": "6",
        "attributes": [
          {
            "name": "Company",
            "position": "1",
            "value": "private_limited_company"
          },
          {
            "name": "Address",
            "position": "3",
            "value": {
              "line1": "AAA",
              "line2": "BBB",
              "line3": "CCC",
              "line4": "DDD",
              "postalCode": "AB XYZ",
              "countryCode": "GBR"
            }
          }
        ]
      }
    }
  ]
}

已编写基础映射类,但无法确定ComplianceAttribute中value字段的正确映射方式,现有基础代码如下:

MyService.java

@Slf4j
@Service
public class MyService {
    public MyResponse getCustomerDetails() {
        ObjectMapper mapper = new ObjectMapper();
        try {
            File file = getFile("classpath:data.json");
            if (file.exists()) {
                return mapper.readValue(file, MyResponse.class);
            }
        } catch (IOException e) {
            log.error(e.getMessage());
        }
        return null;
    }
}

MyResponse.java

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class MyResponse {
    private List<DataBlock> dataBlocks;
}

DataBlock.java

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class DataBlock {
    @JsonProperty("headingName")
    private ComplianceSection section;
}

ComplianceSection.java

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class ComplianceSection {
    private String name;
    private String position;
    private List<ComplianceAttribute> attributes;
}

解决方案

针对动态value字段,提供三种可行的映射方案,可根据业务需求选择:

方案1:直接使用Object类型(快速实现)

最简单的方式是将value字段定义为Object类型,Jackson会自动将JSON值转换为对应的Java类型(字符串→String,数组→List,对象→Map)。

修改ComplianceAttribute类:

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class ComplianceAttribute {
    private String name;
    private String position;
    private Object value;
}

优缺点:

  • 优点:实现简单,无需额外配置
  • 缺点:类型不安全,使用时需要强制转换,容易引发ClassCastException

方案2:使用Jackson的JsonNode类型(灵活且类型安全)

使用Jackson提供的JsonNode类型,它可以灵活处理任意JSON结构,并且提供了类型判断和取值的方法。

修改ComplianceAttribute类:

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class ComplianceAttribute {
    private String name;
    private String position;
    private JsonNode value;
}

使用示例:

// 假设获取到某个ComplianceAttribute实例
ComplianceAttribute attr = ...;
JsonNode value = attr.getValue();

// 判断类型并取值
if (value.isTextual()) {
    String strValue = value.asText();
} else if (value.isArray()) {
    List<String> arrayValue = new ArrayList<>();
    for (JsonNode node : value) {
        arrayValue.add(node.asText());
    }
} else if (value.isObject()) {
    String line1 = value.get("line1").asText();
    String postalCode = value.get("postalCode").asText();
}

优缺点:

  • 优点:类型安全,可灵活处理各种JSON结构,无需提前定义所有可能的POJO
  • 缺点:取值需要手动判断类型,代码相对繁琐

方案3:自定义反序列化器+通用值对象(适合复杂业务场景)

如果需要将不同类型的value映射为明确的Java类型,可以自定义反序列化器,根据JSON类型将value转换为对应的对象。

步骤1:定义通用值对象

创建一个包含所有可能类型的类:

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class AttributeValue {
    private String stringValue;
    private List<String> arrayValue;
    private Map<String, Object> objectValue;
}

步骤2:编写自定义反序列化器

public class AttributeValueDeserializer extends JsonDeserializer<AttributeValue> {
    @Override
    public AttributeValue deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonNode node = p.getCodec().readTree(p);
        AttributeValue value = new AttributeValue();
        if (node.isTextual()) {
            value.setStringValue(node.asText());
        } else if (node.isArray()) {
            List<String> array = new ArrayList<>();
            for (JsonNode item : node) {
                array.add(item.asText());
            }
            value.setArrayValue(array);
        } else if (node.isObject()) {
            Map<String, Object> map = new HashMap<>();
            Iterator<Map.Entry<String, JsonNode>> iter = node.fields();
            while (iter.hasNext()) {
                Map.Entry<String, JsonNode> entry = iter.next();
                map.put(entry.getKey(), entry.getValue().asText());
            }
            value.setObjectValue(map);
        }
        return value;
    }
}

步骤3:在ComplianceAttribute中使用该反序列化器

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class ComplianceAttribute {
    private String name;
    private String position;
    @JsonDeserialize(using = AttributeValueDeserializer.class)
    private AttributeValue value;
}

优缺点:

  • 优点:类型明确,业务代码可直接使用对应字段,无需强制转换
  • 缺点:需要编写额外的反序列化逻辑,维护成本较高

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 06:06:19