将不同格式的JSON字符串反序列化到同一Java类的实例
使用Jackson将不同格式的JSON字符串反序列化到同一Java类实例的最佳方法是什么 例如,我有从不同来源获取的用户信息: 格式1:将不同格式的JSON字符串反序列化到同一Java类的实例,java,json,jackson,deserialization,Java,Json,Jackson,Deserialization,使用Jackson将不同格式的JSON字符串反序列化到同一Java类实例的最佳方法是什么 例如,我有从不同来源获取的用户信息: 格式1: "user" : { "name" : "John", "age" : 21, "email" : "john@mail.com", "location" : "NYC" } 格式2: { "user" : "John", "mail" : "john@mail.com", "age" : "21" }
"user" : {
"name" : "John",
"age" : 21,
"email" : "john@mail.com",
"location" : "NYC"
}
格式2:
{
"user" : "John",
"mail" : "john@mail.com",
"age" : "21"
}
格式3:
{
"who" : "John",
"contacts" : "john@mail.com",
"age" : 21
}
我想将所有这些字符串反序列化为以下类的实例:
public class User {
public String name;
public String email;
public int age;
}
也许有一种方法可以通过映射而不是注释来定义从JSON字段到Java字段的映射?对于第一部分,无论
“user”:
是否应该是JSON字符串的一部分,您都可以使用Java中的普通字符串操作来操作它
对于第二部分,关于将mail
映射到email
等等,您可以使用setter
public class User {
public String name;
public String email;
public int age;
public void setMail(String value) {
this.email = value;
}
}
这里的
setMail
-方法将被Jackson检测到,并将为示例2中的mail
属性调用。您可以为您想要的所有映射(联系人、用户、联系人)添加此类集合方法。直接将源数据反序列化为单一目标格式可能会很快变得有点麻烦且容易出错。我建议为不同的源代码格式定义单独的类,实现一个指定getUser()
方法的接口。此方法将生成所需的目标格式
这样,您就可以在一个类中拥有特定于不同提供程序的所有代码,并且在需要时可以轻松添加新的提供程序。我已经翻阅了Jackson文档并找到了两种解决方案 这是我的Java类:
public class User {
protected String name;
protected String email;
protected int age;
public void setName(String name) {
this.name = name;
}
public void setEmail(String email) {
this.email = email;
}
public void setAge(int age) {
this.age = age;
}
public String toString() {
return name + ": [ " + email + ", " + age + " ]";
}
}
第一个解决方案是创建自定义属性命名策略:
public class MappingPropertyNamingStrategy extends PropertyNamingStrategy {
Map<String, String> nameMap = new HashMap<String, String>();
public void setMap(Map<String, String> map) {
nameMap = map;
}
@Override
public String nameForGetterMethod(MapperConfig<?> cfg,
AnnotatedMethod method,
String defaultName) {
return mapName(defaultName);
}
@Override
public String nameForSetterMethod(MapperConfig<?> cfg,
AnnotatedMethod method,
String defaultName) {
return mapName(defaultName);
}
@Override
public String nameForField(MapperConfig<?> cfg,
AnnotatedField field,
String defaultName) {
return mapName(defaultName);
}
protected String mapName(String name) {
if (nameMap.containsKey(name)) {
return nameMap.get(name);
} else {
return name;
}
}
}
然后只需将其与用户类关联:
mapper = new ObjectMapper();
mapper.addMixInAnnotations(User.class, FirstFormat.class);
Map<String, User> res = mapper.readValue(json1, new TypeReference<Map<String, User>>() {});
System.out.println(res.get("user"));
mapper = new ObjectMapper();
mapper.addMixInAnnotations(User.class, SecondFormat.class);
System.out.println(mapper.readValue(json2, new TypeReference<User>(){}));
mapper = new ObjectMapper();
mapper.addMixInAnnotations(User.class, ThirdFormat.class);
System.out.println(mapper.readValue(json3, new TypeReference<User>(){}));
mapper=newObjectMapper();
addMixinNotations(User.class,FirstFormat.class);
Map res=mapper.readValue(json1,newtypereference(){});
System.out.println(res.get(“用户”));
映射器=新的ObjectMapper();
addMixinNotations(User.class,SecondFormat.class);
System.out.println(mapper.readValue(json2,newtypereference(){}));
映射器=新的ObjectMapper();
addMixinNotations(User.class,ThirdFormat.class);
System.out.println(mapper.readValue(json3,newtypereference(){}));
我认为,mixin是最好的解决方案,因为它提供了更多的控制。您建议的方法看起来不错,但我担心如果出现更多不同的格式,我将不得不添加数十亿设置程序。:)@Filipp你能想出多少“邮件”、“姓名”和“年龄”的变体?目前我大约有5到6个组合。你已经描述了我当前的实现。我同意添加新的提供者很容易,但与字段名称映射的规范相比,它需要更多的工作。您所谓的“mixin”实际上被称为“annotations”。无论如何,挖得好!我很喜欢。
@JsonIgnoreProperties({"location"})
abstract class FirstFormat {
}
abstract class SecondFormat {
@JsonProperty("user")
public abstract void setName(String name);
@JsonProperty("mail")
public abstract void setEmail(String email);
public abstract void setAge(int age);
}
abstract class ThirdFormat {
@JsonProperty("who")
public abstract void setName(String name);
@JsonProperty("contacts")
public abstract void setEmail(String email);
public abstract void setAge(int age);
}
mapper = new ObjectMapper();
mapper.addMixInAnnotations(User.class, FirstFormat.class);
Map<String, User> res = mapper.readValue(json1, new TypeReference<Map<String, User>>() {});
System.out.println(res.get("user"));
mapper = new ObjectMapper();
mapper.addMixInAnnotations(User.class, SecondFormat.class);
System.out.println(mapper.readValue(json2, new TypeReference<User>(){}));
mapper = new ObjectMapper();
mapper.addMixInAnnotations(User.class, ThirdFormat.class);
System.out.println(mapper.readValue(json3, new TypeReference<User>(){}));