Java中解析键不固定的JSON遇阻,如何用mapper.readValue()处理?
处理Java中动态键的JSON解析问题
嘿,这个场景我太熟悉了——当JSON里的键是动态不固定的时候,确实没法直接用预定义的POJO配合mapper.readValue()来解析。不过Jackson库本身提供了好几种灵活的解决方案,我给你分享几个最常用的:
方案1:用Map<String, List<String>>直接接收
因为你的JSON结构是字符串键对应字符串列表,直接用泛型Map就能完美匹配。这里要注意用TypeReference来指定泛型类型,避免Jackson把列表解析成非预期的类型:
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.List; import java.util.Map; public class JsonParser { public static void main(String[] args) throws Exception { String json = "{ \"-5\": [ \"15:D1_CHANNEL_ID_SK\", \"23:D1_CALL_BEGIN_DATE\", \"87:D1_CELL_ID\" ], \"-4\": [ \"31:I_RECHARGE_AMOUNT\", \"59:I_INBUNDLED_UNIT\", \"60:I_DAY_NIGHT_FLAG\", \"53:PD_UPSELL_PACK_ID\", \"146:AON\" ] }"; ObjectMapper mapper = new ObjectMapper(); // 用TypeReference明确泛型类型 Map<String, List<String>> dynamicMap = mapper.readValue(json, new TypeReference<Map<String, List<String>>>() {}); // 遍历处理每个键值对 for (Map.Entry<String, List<String>> entry : dynamicMap.entrySet()) { String key = entry.getKey(); List<String> values = entry.getValue(); System.out.printf("键:%s,对应的值列表:%s%n", key, values); } } }
方案2:用JsonNode灵活遍历解析
如果不需要把整个JSON转成Java对象,只是需要读取或处理特定内容,JsonNode会更灵活,它相当于JSON的树形结构表示:
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class JsonNodeParser { public static void main(String[] args) throws Exception { String json = "{ \"-5\": [ \"15:D1_CHANNEL_ID_SK\", \"23:D1_CALL_BEGIN_DATE\", \"87:D1_CELL_ID\" ], \"-4\": [ \"31:I_RECHARGE_AMOUNT\", \"59:I_INBUNDLED_UNIT\", \"60:I_DAY_NIGHT_FLAG\", \"53:PD_UPSELL_PACK_ID\", \"146:AON\" ] }"; ObjectMapper mapper = new ObjectMapper(); JsonNode rootNode = mapper.readTree(json); // 遍历所有动态键 Iterator<String> fieldNames = rootNode.fieldNames(); while (fieldNames.hasNext()) { String key = fieldNames.next(); JsonNode valueNode = rootNode.get(key); // 确保值是数组类型,再转成列表 if (valueNode.isArray()) { List<String> values = new ArrayList<>(); for (JsonNode item : valueNode) { values.add(item.asText()); } System.out.printf("键:%s,对应的值列表:%s%n", key, values); } } } }
方案3:结合@JsonAnySetter注解封装成实体类
如果你的JSON除了这些动态键,还有其他固定字段,或者想把动态键的逻辑封装到实体类里,可以用@JsonAnySetter注解来统一处理动态键:
import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.HashMap; import java.util.List; import java.util.Map; public class DynamicData { // 用Map存储所有动态键值对 private Map<String, List<String>> dynamicFields = new HashMap<>(); // 注解标记:所有未匹配到固定字段的键都会调用这个方法 @JsonAnySetter public void setDynamicField(String key, List<String> value) { dynamicFields.put(key, value); } public Map<String, List<String>> getDynamicFields() { return dynamicFields; } public static void main(String[] args) throws Exception { String json = "{ \"-5\": [ \"15:D1_CHANNEL_ID_SK\", \"23:D1_CALL_BEGIN_DATE\", \"87:D1_CELL_ID\" ], \"-4\": [ \"31:I_RECHARGE_AMOUNT\", \"59:I_INBUNDLED_UNIT\", \"60:I_DAY_NIGHT_FLAG\", \"53:PD_UPSELL_PACK_ID\", \"146:AON\" ] }"; ObjectMapper mapper = new ObjectMapper(); DynamicData data = mapper.readValue(json, DynamicData.class); // 从实体类中获取动态字段 Map<String, List<String>> fields = data.getDynamicFields(); fields.forEach((key, values) -> System.out.printf("键:%s,对应的值列表:%s%n", key, values)); } }
小提示
- 确保你已经引入了Jackson的核心依赖(比如
jackson-databind),如果用Maven的话,在pom.xml里添加对应的依赖即可。 - 这些方案都能完美处理你给出的JSON结构,你可以根据自己的业务场景选择最适合的一种。
内容的提问来源于stack exchange,提问作者Arun Jose
相关产品推荐
相关产品推荐

