Java使用Jackson序列化生成JSON格式不符合预期问题求助
问题原因
- 重复序列化:你先调用
writeValueAsString()将Post对象转为JSON字符串,随后又将该字符串作为参数传入writeValue()方法写入文件,相当于对字符串做了二次序列化,导致外层多了引号、内部引号被转义。 - Comment类不符合JavaBean序列化要求:输出中comments数组里是
Comment(id=1, user=Zoli...)这类toString()的输出,说明Jackson无法识别Comment类的属性,大概率是Comment类的私有属性没有提供public的getter方法,导致Jackson只能调用toString()输出内容。 - 输出结构不匹配:你期望的输出最外层是包含
posts数组的对象,当前代码直接序列化单个Post对象,自然没有外层的posts字段包裹。 - 枚举输出不符合要求:默认情况下Jackson会直接输出枚举常量的名称(大写),和你期望的小写自定义值不匹配。
解决方案
1. 调整实体类代码
确保Post、Comment类都为私有属性添加public getter方法,枚举类添加@JsonValue注解自定义输出值:
// Status枚举类 import com.fasterxml.jackson.annotation.JsonValue; public enum Status { IN_PROGRESS("in_progress"), DONE("done"); private final String desc; Status(String desc) { this.desc = desc; } // 序列化时直接返回desc字段的值 @JsonValue public String getDesc() { return desc; } }
// Comment类示例 public class Comment { private String id; private String user; private String date; private String description; // 此处省略所有setter方法,请保留原有setter // 必须添加以下getter方法供Jackson读取属性 public String getId() { return id; } public String getUser() { return user; } public String getDate() { return date; } public String getDescription() { return description; } }
// Post类示例 public class Post { private Integer id; private String title; private String user; private String date; private Status status; private String description; private List<Comment> comments; // 此处省略所有setter方法,请保留原有setter // 必须添加以下getter方法供Jackson读取属性 public Integer getId() { return id; } public String getTitle() { return title; } public String getUser() { return user; } public String getDate() { return date; } public Status getStatus() { return status; } public String getDescription() { return description; } public List<Comment> getComments() { return comments; } }
2. 调整主类序列化逻辑
构造符合预期的外层包裹结构,避免重复序列化:
import com.fasterxml.jackson.core.util.DefaultIndenter; import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class Main { public static void main(String[] args) throws IOException { List<Comment> comments = new ArrayList<>(); // 构造测试评论数据 Comment comm1 = new Comment(); comm1.setId("1"); comm1.setUser("Zoli"); comm1.setDate("22/09/2021"); comm1.setDescription("Very nice!"); comments.add(comm1); Comment comm2 = new Comment(); comm2.setId("2"); comm2.setUser("Krisz"); comm2.setDate("22/09/2021"); comm2.setDescription("Nice!"); comments.add(comm2); Comment comm3 = new Comment(); comm3.setId("3"); comm3.setUser("Csaba"); comm3.setDate("22/09/2021"); comm3.setDescription("Very good!"); comments.add(comm3); Comment comm4 = new Comment(); comm4.setId("4"); comm4.setUser("Márk"); comm4.setDate("22/09/2021"); comm4.setDescription("Good!"); comments.add(comm4); // 构造测试Post数据 Post post = new Post(); post.setId(1); post.setTitle("Example"); post.setUser("Ruben"); post.setDate("22/09/2021"); post.setStatus(Status.DONE); post.setDescription("Sample post"); post.setComments(comments); // 构造外层包裹对象,对应预期的posts数组结构 Map<String, List<Post>> result = new HashMap<>(); result.put("posts", List.of(post)); ObjectMapper objectMapper = new ObjectMapper(); // 配置格式化规则 DefaultPrettyPrinter printer = new DefaultPrettyPrinter(); printer.indentArraysWith(new DefaultIndenter()); // 直接序列化结果对象写入文件,不要二次序列化 objectMapper.writer(printer).writeValue(new File("car.json"), result); // 如果需要拿到序列化后的字符串,直接用result转换即可 String serialized = objectMapper.writer(printer).writeValueAsString(result); System.out.println(serialized); } }
修改后输出的JSON就会和你期望的格式完全一致。
内容的提问来源于stack exchange,提问作者Csabatron99
相关产品推荐
相关产品推荐

