使用Jackson YAML库生成含User标识的YAML文件失败求助
问题:Jackson YAML生成格式不符,如何让每个对象前显示"User"?
我在用Jackson YAML库生成YAML文件时,没法得到预期格式。我要保存的是DataTest对象列表,相关代码如下:
DataTest类定义
@Data @NoArgsConstructor @AllArgsConstructor @JsonTypeName("User") @Builder public class DataTest { @JsonProperty("ID") private int userID; @JsonProperty("Name") private String userName; @JsonProperty("Address") private String streetAddress; @JsonProperty("City") private String theCity; }
注:该类使用Lombok简化代码,同时添加了Jackson注解。
DataList类定义(存放对象列表)
@JsonRootName(value = "ListOfUsers") public class DataList extends ArrayList<DataTest> { private static final long serialVersionUID = 7112953850878936075L; public DataList() { } // 其他构造方法 }
测试数据类SomeData
public class SomeData { public static String[] theNames = { "Jimmy Dean", "John Sheridan", "John Chriton", "James Kirk", "River Tan" }; public static String[] theAddresses = { "12 Riverview Drive", "233X Blue Sector", "2nd Room", "Captain's Quarters", "3rd Berth" }; public static String[] theCities = { "Greenview", "Babylon 5", "Moya the Ship", "USS Enterprise", "Serenity" }; }
生成YAML的ServiceIO类
public class ServiceIO { private static ServiceIO mySelf = null; private final ObjectMapper theMapper; private final File theFile; private ServiceIO() { theFile = new File("./files/users.yml"); theMapper = new ObjectMapper(new YAMLFactory().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER)) .enable(SerializationFeature.WRAP_ROOT_VALUE) .enable(DeserializationFeature.UNWRAP_ROOT_VALUE); } public void saveServices(DataList theInfo) { try { theMapper.writeValue(theFile,theInfo); } catch(Exception exe) { exe.printStackTrace(); } } public static ServiceIO getInstance() { if(mySelf == null) mySelf = new ServiceIO(); return(mySelf); } }
测试类YamlTest
public class YamlTest { public static void main(String[] args) { DataList list = new DataList(); for(int inc = 0; inc < 5; inc++) { DataTest test = DataTest.builder().userID(inc+1).userName(SomeData.theNames[inc]) .streetAddress(SomeData.theAddresses[inc]).theCity(SomeData.theCities[inc]) .build(); list.add(test); } ServiceIO service = ServiceIO.getInstance(); service.saveServices(list); } }
期望的YAML格式
ListOfUsers: - User: ID: 1 Name: "Jimmy Dean" Address: "12 Riverview Drive" City: "Greenview" - User: ID: 2 Name: "John Sheridan" Address: "233X Blue Sector" City: "Babylon 5" - User: ID: 3 Name: "John Chriton" Address: "2nd Room" City: "Moya the Ship" - User: ID: 4 Name: "James Kirk" Address: "Captain's Quarters" City: "USS Enterprise" - User: ID: 5 Name: "River Tan" Address: "3rd Berth" City: "Serenity"
实际生成的YAML格式
ListOfUsers: - ID: 1 Name: "Jimmy Dean" Address: "12 Riverview Drive" City: "Greenview" - ID: 2 Name: "John Sheridan" Address: "233X Blue Sector" City: "Babylon 5" - ID: 3 Name: "John Chriton" Address: "2nd Room" City: "Moya the Ship" - ID: 4 Name: "James Kirk" Address: "Captain's Quarters" City: "USS Enterprise" - ID: 5 Name: "River Tan" Address: "3rd Berth" City: "Serenity"
核心需求是每个DataTest对象前要有"User"行,但实际生成的内容里没有,请问哪里出错了?怎么调整才能得到预期格式?
解决办法
问题原因
你添加的@JsonTypeName("User")注解默认只在多态序列化场景下生效——也就是当DataTest对象被当作它的父类/接口类型序列化时,Jackson才会自动添加类型名称作为包装键。但现在你直接序列化DataTest对象,Jackson不会主动用"User"去包装它。
调整方案
给DataTest类添加@JsonTypeInfo注解,明确指定类型信息的包含方式为用对象包装,这样每个DataTest实例都会被"User"键包裹。
修改后的DataTest类代码:
@Data @NoArgsConstructor @AllArgsConstructor @JsonTypeName("User") @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT) @Builder public class DataTest { @JsonProperty("ID") private int userID; @JsonProperty("Name") private String userName; @JsonProperty("Address") private String streetAddress; @JsonProperty("City") private String theCity; }
验证效果
修改后重新运行测试类,生成的YAML就会和你预期的一致,每个DataTest对象都会被"User"节点包裹。
备选方案(无需多态支持时)
如果不需要多态序列化的特性,也可以手动给DataTest加一层包装类:
@Data public class UserWrapper { @JsonProperty("User") private DataTest data; }
然后把DataList改成ArrayList<UserWrapper>,在添加对象时把DataTest包装进UserWrapper里。不过这种方式不如用Jackson的类型注解简洁。
内容的提问来源于stack exchange,提问作者Factor Three
相关产品推荐
相关产品推荐

