如何通过Jackson序列化自定义TreeNodeLabel生成指定结构的JSONObject
如何将TreeNodeLabel对象转换为指定的嵌套JSON结构
你遇到的问题其实很典型:默认的Jackson注解没办法直接把children列表转换成以子节点name为键的嵌套结构,也没法自动把prop里的键值对直接平铺在当前节点下。要生成你想要的JSON格式,自定义序列化器是最直接的解决方案。
第一步:理解需求对应关系
先明确你的TreeNodeLabel结构和目标JSON的映射逻辑:
- 节点的
prop里的键值对 → 直接作为当前JSON对象的键值对 - 节点的
children列表 → 每个子节点以自身name为键,子节点的内容(包含它的prop和子节点)作为对应值 parent字段需要忽略,避免循环引用
第二步:自定义Jackson序列化器
写一个继承JsonSerializer<TreeNodeLabel>的类,手动控制序列化逻辑:
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; import java.util.Map; public class TreeNodeLabelSerializer extends JsonSerializer<TreeNodeLabel> { @Override public void serialize(TreeNodeLabel node, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeStartObject(); // 先写入当前节点prop中的所有键值对 if (node.getProp() != null) { for (Map.Entry<String, String> entry : node.getProp().entrySet()) { gen.writeStringField(entry.getKey(), entry.getValue()); } } // 递归处理子节点,以子节点name为键,序列化子节点内容 if (node.getChildren() != null && !node.getChildren().isEmpty()) { for (TreeNodeLabel child : node.getChildren()) { gen.writeFieldName(child.getName()); serialize(child, gen, serializers); } } gen.writeEndObject(); } }
第三步:修改TreeNodeLabel类配置
给你的类加上序列化器注解,并忽略parent字段防止循环引用:
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.annotation.JsonIgnore; import java.util.List; import java.util.Map; @JsonSerialize(using = TreeNodeLabelSerializer.class) public class TreeNodeLabel { @JsonIgnore TreeNodeLabel parent; List<TreeNodeLabel> children; Map<String, String> prop; String name; // 必须添加getter方法,序列化器需要访问这些字段 public TreeNodeLabel getParent() { return parent; } public void setParent(TreeNodeLabel parent) { this.parent = parent; } public List<TreeNodeLabel> getChildren() { return children; } public void setChildren(List<TreeNodeLabel> children) { this.children = children; } public Map<String, String> getProp() { return prop; } public void setProp(Map<String, String> prop) { this.prop = prop; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
第四步:测试序列化效果
用一个示例代码构建你的TreeNodeLabel结构,然后序列化:
import com.fasterxml.jackson.databind.ObjectMapper; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class LabelSerializerTest { public static void main(String[] args) throws Exception { // 构建login节点的errors子节点 Map<String, String> errorsProp = new HashMap<>(); errorsProp.put("loginRequired", "Email requis"); errorsProp.put("loginFormat", "Format de l'email incorrect"); TreeNodeLabel errorsNode = new TreeNodeLabel(); errorsNode.setName("errors"); errorsNode.setProp(errorsProp); // 构建login节点 Map<String, String> loginProp = new HashMap<>(); loginProp.put("login", "Me connecter"); loginProp.put("label", "Connectez-vous"); TreeNodeLabel loginNode = new TreeNodeLabel(); loginNode.setName("login"); loginNode.setProp(loginProp); loginNode.setChildren(List.of(errorsNode)); // 构建auth节点 Map<String, String> authProp = new HashMap<>(); authProp.put("myChallenges", "Visualiser vos défis"); authProp.put("myMessages", "Accéder à la messagerie"); TreeNodeLabel authNode = new TreeNodeLabel(); authNode.setName("auth"); authNode.setProp(authProp); authNode.setChildren(List.of(loginNode)); // 构建根data节点 TreeNodeLabel dataNode = new TreeNodeLabel(); dataNode.setName("data"); dataNode.setChildren(List.of(authNode)); // 序列化输出 ObjectMapper mapper = new ObjectMapper(); String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(dataNode); System.out.println(json); } }
运行这段代码,就能得到和你期望结构完全一致的JSON了。
内容的提问来源于stack exchange,提问作者Aléxis Bernard
相关产品推荐
相关产品推荐

