Jackson JSON反序列化:如何根据JSON值为对象成员赋值?
Jackson 特殊嵌套JSON反序列化实现方案
你的判断是对的,这种非固定键、数组内动态配对的JSON结构,没法直接通过简单的@JsonProperty注解映射,两种常用实现方式如下,按需选择即可。
方案1:树模型手动取值(快速实现)
不用额外编写自定义反序列化类,直接先将JSON解析为Jackson通用的JsonNode树结构,逐层遍历节点取值赋值,适合单次使用、逻辑简单的场景:
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; public class ParseTest { public static void main(String[] args) throws Exception { ObjectMapper mapper = new ObjectMapper(); // 替换为你的完整JSON字符串 String json = """ { "ContainerValues": [ { "ParentAttribute": "QuantityContained", "RowList": [ { "Values": [ {"Name": "Code", "ValuesByLocale": {"en-US": "GRM"}}, {"Name": "Value", "ValuesByLocale": {"en-US": "4.0"}} ] } ] } ] } """; JsonNode root = mapper.readTree(json); POJO pojo = new POJO(); for (JsonNode container : root.get("ContainerValues")) { // 按需加过滤条件,比如只处理QuantityContained类型的节点 if (!"QuantityContained".equals(container.path("ParentAttribute").asText())) { continue; } for (JsonNode row : container.path("RowList")) { String code = null; String matchValue = null; for (JsonNode valItem : row.path("Values")) { String itemName = valItem.path("Name").asText(); String enUsVal = valItem.path("ValuesByLocale").path("en-US").asText(); if ("Code".equals(itemName)) { code = enUsVal; } else if ("Value".equals(itemName)) { matchValue = enUsVal; } } if ("GRM".equals(code)) { pojo.grmValue = matchValue; // 如果只需要取第一个匹配项,在这里加break终止循环即可 } // 其他编码对应的字段可以在这里扩展判断,比如Code为KGM时赋值给kgmValue } } System.out.println(pojo.grmValue); // 输出4.0 } } class POJO { public String grmValue; }
方案2:自定义反序列化器(可复用)
如果这个POJO需要在多个接口、多处逻辑中反序列化,就编写独立的自定义反序列化器注册到Jackson,后续直接调用readValue就能自动完成映射,不需要重复写遍历逻辑:
首先编写反序列化器实现:
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 java.io.IOException; public class POJODeserializer extends StdDeserializer<POJO> { public POJODeserializer() { this(null); } public POJODeserializer(Class<?> vc) { super(vc); } @Override public POJO deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException { JsonNode root = parser.getCodec().readTree(parser); POJO pojo = new POJO(); for (JsonNode container : root.path("ContainerValues")) { for (JsonNode row : container.path("RowList")) { String code = null; String val = null; for (JsonNode item : row.path("Values")) { String name = item.path("Name").asText(); String localeVal = item.path("ValuesByLocale").path("en-US").asText(); if ("Code".equals(name)) { code = localeVal; } else if ("Value".equals(name)) { val = localeVal; } } if ("GRM".equals(code)) { pojo.grmValue = val; } } } return pojo; } }
注册反序列化器后使用:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; public class DeserializeDemo { public static void main(String[] args) throws Exception { ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addDeserializer(POJO.class, new POJODeserializer()); mapper.registerModule(module); // 直接读取JSON即可完成字段自动赋值 POJO pojo = mapper.readValue(你的JSON字符串, POJO.class); } }
注意点:
- 代码中用
path()方法取节点,相比get()可以避免节点不存在时抛出空指针,适配可能缺字段的非严格JSON结构- 如果需要支持其他语言,把硬编码的
en-US替换成你需要的语言标识即可- 如果存在多行GRM的记录,默认会取最后一次遍历到的值,需要取第一个值的话在赋值后加
break终止循环就行
内容的提问来源于stack exchange,提问作者user2563087
相关产品推荐
相关产品推荐

