咨询自定义Jackson中valueToTree与treeToValue转换行为的方法
自定义Jackson实现非Bean类与JSON树的双向转换
不需要创建ObjectMapper子类并重写方法,Jackson提供了专门的扩展机制来实现非Bean类与JSON树(JsonNode)的双向转换,以下是具体方案:
方案一:自定义序列化/反序列化器(推荐)
Jackson的JsonSerializer和JsonDeserializer不仅支持对象与JSON字符串的转换,同样适用于对象与JsonNode的互转——因为valueToTree和treeToValue底层会调用对应的序列化/反序列化逻辑。
1. 实现自定义序列化器(对象转JsonNode)
针对你的非Bean类,继承JsonSerializer<T>并实现serialize方法,手动构建JsonNode结构:
public class MyNonBeanSerializer extends JsonSerializer<MyNonBean> { @Override public void serialize(MyNonBean value, JsonGenerator gen, SerializerProvider serializers) throws IOException { // 通过SerializerProvider获取TreeCodec来创建JsonNode ObjectNode node = serializers.getCodec().createObjectNode(); // 根据非Bean类的属性填充节点 node.put("customField", value.getCustomValue()); node.put("numericField", value.getNumericValue()); // 将构建好的JsonNode写入生成器 gen.writeTree(node); } }
2. 实现自定义反序列化器(JsonNode转对象)
继承JsonDeserializer<T>并实现deserialize方法,从JsonNode中提取数据构造非Bean对象:
public class MyNonBeanDeserializer extends JsonDeserializer<MyNonBean> { @Override public MyNonBean deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { // 读取JSON树 JsonNode node = p.readValueAsTree(); // 从节点中提取字段值 String customVal = node.get("customField").asText(); int numericVal = node.get("numericField").asInt(); // 构造非Bean对象(根据实际构造逻辑调整) return new MyNonBean(customVal, numericVal); } }
3. 注册到ObjectMapper
将自定义的序列化器/反序列化器通过SimpleModule注册到ObjectMapper:
ObjectMapper mapper = new ObjectMapper(); SimpleModule customModule = new SimpleModule(); customModule.addSerializer(MyNonBean.class, new MyNonBeanSerializer()); customModule.addDeserializer(MyNonBean.class, new MyNonBeanDeserializer()); mapper.registerModule(customModule);
4. 调用转换方法
注册完成后,直接使用ObjectMapper的原生方法即可完成互转:
// 对象转JSON树 MyNonBean obj = new MyNonBean("test", 123); JsonNode jsonTree = mapper.valueToTree(obj); // JSON树转对象 MyNonBean newObj = mapper.treeToValue(jsonTree, MyNonBean.class);
方案二:自定义TreeCodec(底层扩展)
如果需要更底层的控制,可以实现TreeCodec接口,它定义了对象与JsonNode转换的核心逻辑,然后将其设置到ObjectMapper:
public class CustomTreeCodec implements TreeCodec { // 实现readTree、writeTree、treeToValue、valueToTree等方法 @Override public JsonNode readTree(JsonParser p) throws IOException { // 自定义读取逻辑 return p.readValueAsTree(); } @Override public JsonGenerator writeTree(JsonNode tree, JsonGenerator gen) throws IOException { // 自定义写入逻辑 gen.writeTree(tree); return gen; } @Override public <T> T treeToValue(JsonNode tree, Class<T> valueType) throws IOException { // 自定义JsonNode转对象逻辑 if (valueType == MyNonBean.class) { String customVal = tree.get("customField").asText(); int numericVal = tree.get("numericField").asInt(); return (T) new MyNonBean(customVal, numericVal); } // 其他类型默认处理 throw new IllegalArgumentException("Unsupported type"); } @Override public JsonNode valueToTree(Object value) throws IllegalArgumentException { // 自定义对象转JsonNode逻辑 if (value instanceof MyNonBean) { MyNonBean obj = (MyNonBean) value; ObjectNode node = new ObjectNode(JsonNodeFactory.instance); node.put("customField", obj.getCustomValue()); node.put("numericField", obj.getNumericValue()); return node; } // 其他类型默认处理 throw new IllegalArgumentException("Unsupported type"); } } // 设置到ObjectMapper ObjectMapper mapper = new ObjectMapper(); mapper.setTreeCodec(new CustomTreeCodec());
这种方式需要实现接口的所有方法,灵活性更高但代码量更大,一般推荐方案一。
内容的提问来源于stack exchange,提问作者Harmon Nine
相关产品推荐
相关产品推荐

