使用Jackson将特定结构JSON对象解析为对象数组的问题
解决方案:Jackson解析动态"first:second"格式的JSON键
我之前也碰到过类似的动态键解析需求,给你两个实用的方案,看哪种更适配你的场景:
方案一:先转成Map再手动转换(快速直观)
这种方式不需要额外编写序列化逻辑,先把JSON解析成Map<String, Number>,再遍历处理每个键值对,手动拆分键并创建MyClass实例,非常适合快速验证需求。
代码示例:
首先调整你的MyClass(简化构造逻辑,更贴合手动创建场景):
private static class MyClass { String first; String second; Number value; public MyClass(String first, String second, Number value) { this.first = first; this.second = second; this.value = value; } // 可选:添加toString方便调试 @Override public String toString() { return "MyClass{" + "first='" + first + '\'' + ", second='" + second + '\'' + ", value=" + value + '}'; } }
然后执行解析逻辑:
import com.fasterxml.jackson.databind.ObjectMapper; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class JsonParserDemo { public static void main(String[] args) throws Exception { String json = "{ \"x:y\" : 1, \"x:z\" : 2, \"u:v\" : 3 }"; ObjectMapper mapper = new ObjectMapper(); // 第一步:将JSON解析为键值对Map Map<String, Number> jsonMap = mapper.readValue(json, Map.class); // 第二步:遍历Map,拆分键并转换为MyClass列表 List<MyClass> myClassList = jsonMap.entrySet().stream() .map(entry -> { // 按第一个":"分割,避免键中包含多个":"时出现异常 String[] parts = entry.getKey().split(":", 2); return new MyClass(parts[0], parts[1], entry.getValue()); }) .collect(Collectors.toList()); // 输出结果调试 myClassList.forEach(System.out::println); } }
方案二:自定义JsonDeserializer(优雅集成)
如果需要把JSON直接解析成List<MyClass>(或者包含该列表的自定义容器类),可以编写自定义反序列化器,让Jackson自动完成转换逻辑,更适合集成到现有序列化流程中。
代码示例:
首先创建自定义反序列化器:
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class MyClassListDeserializer extends JsonDeserializer<List<MyClass>> { @Override public List<MyClass> deserialize(JsonParser parser, DeserializationContext context) throws IOException { JsonNode rootNode = parser.getCodec().readTree(parser); List<MyClass> myClassList = new ArrayList<>(); // 遍历JSON对象的所有字段,逐个转换为MyClass实例 rootNode.fields().forEachRemaining(entry -> { String key = entry.getKey(); String[] parts = key.split(":", 2); Number value = entry.getValue().numberValue(); myClassList.add(new MyClass(parts[0], parts[1], value)); }); return myClassList; } }
然后使用这个反序列化器:
// 方式1:直接解析为List<MyClass> List<MyClass> myClassList = mapper.readValue(json, mapper.getTypeFactory().constructCollectionType(List.class, MyClass.class)); // 方式2:给自定义容器类添加注解(如果需要封装列表) // 比如: // public class MyContainer { // @JsonDeserialize(using = MyClassListDeserializer.class) // private List<MyClass> items; // // getter/setter方法 // } // 之后直接解析:MyContainer container = mapper.readValue(json, MyContainer.class);
注意事项
- 如果键中可能包含多个
:,一定要用split(":", 2)只分割第一个:,保证second部分保留完整的剩余内容。 - 如果你必须保留
MyClass中的@JsonCreator和@JsonProperty注解,可以在创建实例时调用对应的构造方法,比如把new MyClass(parts[0], parts[1], value)换成new MyClass(entry.getKey(), value),但需要在构造方法内部完成键的拆分逻辑。
内容的提问来源于stack exchange,提问作者Ironcache
相关产品推荐
相关产品推荐

