我开始使用Jackson ObjectMapper
从JSON String
解析为MongoDB BasicDBObject
。
在readValue
期间,我希望杰克逊用替代字符替换字段名称中的任何保留字符
在writeValue
期间,我希望杰克逊能够进行反向替换
这样做的原因是Mongo DB不支持.
或$
作为JSON中密钥名称的一部分,我有遗留数据我不太热衷转换,以便我可以坚持它没有特殊的字符映射..
我正在寻找正确的集成点,我可以覆盖readValue
期间生成的字段名称,以及将对象序列化回字符串时使用的集成点(writeValue
)
我已经查看了SimpleModule.addKeySerializer
和SimpleModule.addKeyDeserializer
,并实施了一个简单的映射。但是,这似乎只适用于我的嵌套JSON对象的第一级。任何嵌套对象似乎都没有正确映射其名称。
什么是正确的集成点来覆盖字段名称的映射方式?
答案 0 :(得分:1)
我应该在前言中提到我不是杰克逊的专家,但我看到两个可能的地方你可以整合这种功能:
第一种方法可能有点沉重,但您可以编写自定义serializer和deserializer (或多个。我在本例中使用了其中一种)处理你的密钥名称中的字符替换。
举个例子,我使用了一些JSON,里面有一些句号和美元符号,如下所示:
{\"username.\":\"testuser\",\"id\":\"12345\",\"$role\":{\"role\":\"admin\",\"roleId$\":\"999\"}}
并将取代"。"与" _"和" $"用" |",然后再回来。我不太确定如何进一步浓缩这个,所以请原谅长篇文章。
使用课程:
public class User {
private final String username;
private final String id;
private final RoleInfo role;
public User(String username, String id, RoleInfo role) {
this.username = username;
this.id = id;
this.role = role;
}
...getters omitted
}
public class RoleInfo {
private final String role;
private final String roleId;
public RoleInfo(String role, String roleId) {
this.role = role;
this.roleId = roleId;
}
...getters omitted
}
串行器/反序列化器(假设杰克逊的最新版本,您可能希望在本例中更加小心处理节点的方式):
public class MyCustomDeserializer extends JsonDeserializer<User> {
private final String period;
private final String dollarSign;
public MyCustomDeserializer(final String period, final String dollarSign){
this.period = period;
this.dollarSign = dollarSign;
}
@Override
public User deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
final TreeNode node = p.getCodec().readTree(p);
final TextNode roleNode = (TextNode) node.get(this.dollarSign + "role").get("role");
final TextNode roleIdNode = (TextNode) node.get(this.dollarSign + "role").get("roleId" + this.dollarSign);
final String roleName = roleNode.asText();
final String roleId = roleIdNode.asText();
final RoleInfo roleInfo = new RoleInfo(roleName, roleId);
final TextNode usernameNode = (TextNode) node.get("username" + period);
final TextNode idNode = (TextNode) node.get("id");
final String username = usernameNode.asText();
final String userId = idNode.asText();
final User user = new User(username, userId, roleInfo);
return user;
}
}
public class MyCustomSerializer extends JsonSerializer<User> {
private final String period;
private final String dollarSign;
public MyCustomSerializer(final String period, final String dollarSign) {
this.period = period;
this.dollarSign = dollarSign;
}
@Override
public void serialize(User user, JsonGenerator gen,
SerializerProvider serializers) throws IOException,
JsonProcessingException {
gen.writeStartObject();
gen.writeStringField("username" + this.period, user.getUsername());
gen.writeStringField("id", user.getId());
gen.writeFieldName(this.dollarSign + "role");
gen.writeStartObject();
gen.writeStringField("role", user.getRole().getRole());
gen.writeStringField("roleId" + this.dollarSign, user.getRole()
.getRoleId());
gen.writeEndObject();
gen.writeEndObject();
}
}
序列化和反序列化:
final String testJson = "{\"username.\":\"testuser\",\"id\":\"12345\",\"$role\":{\"role\":\"admin\",\"roleId$\":\"999\"}}";
final ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(User.class, new MyCustomDeserializer(".", "$"));
module.addSerializer(User.class, new MyCustomSerializer("_", "|"));
mapper.registerModule(module);
final User user = mapper.readValue(testJson, User.class);
printUser(user);
final String convertedJson = mapper.writeValueAsString(user);
System.out.println(convertedJson);
System.out.println("");
final ObjectMapper mapper2 = new ObjectMapper();
SimpleModule module2 = new SimpleModule();
module2.addDeserializer(User.class, new MyCustomDeserializer("_", "|"));
module2.addSerializer(User.class, new MyCustomSerializer(".", "$"));
mapper2.registerModule(module2);
final User user2 = mapper2.readValue(convertedJson, User.class);
printUser(user2);
final String json2 = mapper2.writeValueAsString(user);
System.out.println(json2);
产地:
12345
testuser
admin
999
{"username_":"testuser","id":"12345","|role":{"role":"admin","roleId|":"999"}}
12345
testuser
admin
999
{"username.":"testuser","id":"12345","$role":{"role":"admin","roleId$":"999"}}
正如我所说,这是非常沉重的,所以你也可以尝试创建一些POJO来为你做映射。我不确定是否有更优雅的方法使用各种json annotations and some POJOs来解决这个问题,但我没有看到在一个POJO中使用两组替换字符进行序列化和反序列化的方法这种方法。链接中的DRCB's approach为我生成了序列化的两个属性。
我想你也可以考虑在各自的注释中支持两组POJOS和每个保留字符,并在你从各种来源读/写时在它们之间进行转换。像(伪代码)的东西:
ClassA{
@JsonProperty("$user")
private String user;
}
ClassB{
@JsonProperty("#user")
private String user;
}
ClassA a = ClassA.from(classB);
或者您可以组合这两种方法并编写自定义序列化程序,并使用带有多个setter注释的POJO进行反序列化。我认为解决方案将根据您的JSON和POJO的复杂程度而有所不同。