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注解使用

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值