json转换反序列化,一个属性对应多个key
背景
在一次遇到的情况下。es中存放的一个文档中。有一列的属性是json字段。但是这个json字段的key中有两种不同的格式。举个例子:json的内容如下:
{
"userName" : "xiaoming",
"userAge" : 18,
"userAddress" : "北京"
}
{
"name" : "xiaohua",
"age" : 19,
"address" : "西安"
}
这两种不同key的对应的内容是相同的,现在有一个user类,想要在这样的json字符串传过来时候转换为对应的bean。
解决方案
1、@JSONField注解
首先在网上找到的是这个注解,该注解可以作用在类中的属性或者getset方法上。像是这样:
import com.alibaba.fastjson2.annotation.JSONField;
public class User {
@JSONField(name = "userName")
private String name;
@JSONField(name = "userAge")
private int age;
@JSONField(name = "userAddress")
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
转换的例子如下:
import com.alibaba.fastjson.JSON;
public class JSONTest {
public static void main(String[] args) {
String json1 = "{\n" +
"\t\"userName\" : \"xiaoming\",\n" +
"\t\"userAge\" : 18,\n" +
"\t\"userAddress\" : \"北京\"\n" +
"}";
String json2 = "{\n" +
"\t\"name\" : \"xiaohua\",\n" +
"\t\"age\" : 19,\n" +
"\t\"address\" : \"西安\"\n" +
"}";
User user1 = JSON.parseObject(json1, User.class);
User user2 = JSON.parseObject(json2, User.class);
}
}
可是结果并没有完成背景中的需求。它只是相当于一个别名转换,name和userName中取得了userName。最后结果还是取了我们指定的userNmae。
想要解决我们上述的需求,还需要对json和java对象的序列化和反序列化探究一下。我们知道,反序列化生成一个java对象,而在java中,对象的创建有2种方式:
通过构造器new一个
clone一个已存在的实例
前者通过构造器创建,会默认执行构造器中定义的初始化逻辑,后者通过内存复制不会走初始化方法但需要实现Cloneable接口。那么Json反序列化使用的是哪种方式呢?当然是第一种,去克隆一个还不是需要一个生成的对象吗?
现在我们知道是通过构造器生成对象了,那么JSON.parseObject是怎么去做的呢,稍微看一下源码:
方法的入口为:json.parseobject(string text, class clazz);
进来以后调用parseobject(string text, class clazz, feature… features) 方法,f7向下走,发现最后调用到了BeanUtil类中,经过对class的反射。它取到了一个field属性。结果就为我们的“userName”。
那么我们可以确定,它还是去通过属性名去寻找json中的key了,之后通过key再寻找到value。
回到我们上面的想法,它既然是通过构造器去完成反序列化,那么我们在构造器和属性加入这个需要的属性不就可以了吗。
2、直接在属性上添加
直接上代码:
public class User {
private String name;
private String userName;
private int age;
private int userAge;
private String address;
private String userAddress;
public User(String name, String userName, int age, int userAge, String address, String userAddress) {
this.name = name;
this.userName = userName;
this.age = age;
this.userAge = userAge;
this.address = address;
this.userAddress = userAddress;
}
public User(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
}
看一下转换结果,是可以转换成功的。但是user1的name为空,userName为真实值了。
我们可以做这样一个操作。因为属性一般是私有的,而调用它的时候是通过getset方法。想要获得一个user的name,这样做:通过对get方法的调整,可以让userName也指向name。
public class User {
private String name;
private String userName;
private int age;
private int userAge;
private String address;
private String userAddress;
public User(String name, String userName, int age, int userAge, String address, String userAddress) {
this.name = name;
this.userName = userName;
this.age = age;
this.userAge = userAge;
this.address = address;
this.userAddress = userAddress;
}
public User(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
public String getName() {
return name != null ? name : userName;
}
public int getAge() {
return age != 0 ? age : userAge;
}
public String getAddress() {
return address != null ? address : userAddress;
}
}
结果如下:
package com.yq.demo.test;
import com.alibaba.fastjson.JSON;
public class JSONTest {
public static void main(String[] args) {
String json1 = "{\n" +
"\t\"userName\" : \"xiaoming\",\n" +
"\t\"userAge\" : 18,\n" +
"\t\"userAddress\" : \"北京\"\n" +
"}";
String json2 = "{\n" +
"\t\"name\" : \"xiaohua\",\n" +
"\t\"age\" : 19,\n" +
"\t\"address\" : \"西安\"\n" +
"}";
User user1 = JSON.parseObject(json1, User.class);
User user2 = JSON.parseObject(json2, User.class);
System.out.println(user1.getName());
System.out.println(user2.getName());
System.out.println(user1.getAge());
System.out.println(user2.getAge());
System.out.println(user1.getAddress());
System.out.println(user2.getAddress());
}
}
xiaoming
xiaohua
18
19
北京
西安
对get方法的操作目的达成。这样的操作也可以改构造器进行实现,如下:
public class User {
private String name;
private String userName;
private int age;
private int userAge;
private String address;
private String userAddress;
//主要是这里
public User(String name, String userName, int age, int userAge, String address, String userAddress) {
this.name = name != null ? name : userName;
this.age = age != 0 ? age : userAge;
this.address = address != null ? address : userAddress;
}
public User(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
public String getName() {
return name != null ? name : userName;
}
public int getAge() {
return age != 0 ? age : userAge;
}
public String getAddress() {
return address != null ? address : userAddress;
}
}
结论更是满足要求,nice!!!:
3、定义两个类去反序列化
开始也想过定义两个类,取不同的属性名去通过判断反序列化。因为想要反序列化必须找到对应的属性名。这个读者可以自行尝试。
4、补充一下jackson
fastjson可能因为漏洞问题不常用到了,现在大部分用jackson。当然也支持上述的做法,毕竟是操作自己定义的类,想怎么做就怎么做🤣🤣🤣。补充的是jack的序列化方法:当然不能一直new,正式场合下需要有一个工具类去做。
以及jackson的一些注解使用:
链接: jackson使用
链接: jackson注解使用