Fastjson泛型数据转JSON及还原,保留原始类型

1、问题

最近有个需求,数据是保存在一个Map<String, Object>中,使用Fastjson转为json字符串后保存到数据库,要用的时候从数据库取出来然后还原。
示例代码如下

package com.moss.json;

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import com.alibaba.fastjson.JSON;
import com.moss.mysql.entity.AppUser;

public class JsonTest {
    private static Map<String, Object> localMap = new HashMap<>();

    public static void main(String[] args) {
        AppUser user = new AppUser();
        user.setUserId(System.currentTimeMillis());
        user.setLoginIp("127.0.0.1");
        user.setUserName("管理员");
        user.setEmail("admin@126.com");
        user.setNickName("moss");
        user.setDelFlag("0");
        user.setDeptId(System.currentTimeMillis());
        user.setSex("0");
        user.setLoginDate(new Timestamp(System.currentTimeMillis()));
        user.setPassword("123456");
        user.setPhonenumber("13522659887");

        Map<String, Object> extMap = new HashMap<>();
        extMap.put("serialNo", UUID.randomUUID().toString());
        extMap.put("user", user);
        extMap.put("total", 100);

		// 序列化
        String json = JSON.toJSONString(extMap);
        System.out.println("Json = " + json);

		// 反序列化
        localMap = JSON.parseObject(json);
        for (Map.Entry<String, Object> e : localMap.entrySet()) {
            System.out.println(e.getKey() + " = " + e.getValue() + ", type = " + e.getValue().getClass());
        }

        AppUser appUser = get("user");
        System.out.println("appUser = " + appUser);
    }

    public static <T> T get(String key) {
        return (T) localMap.get(key);
    }
}

运行结果

Json = {"total":100,"user":{"delFlag":"0","deptId":1625713027348,"email":"admin@126.com","loginDate":1625713027349,"loginIp":"127.0.0.1","nickName":"moss","password":"123456","phonenumber":"13522659887","sex":"0","userId":1625713027348,"userName":"管理员"},"serialNo":"c82f8649-78ad-4758-9a13-7b5613d24e5a"}
total = 100, type = class java.lang.Integer
user = {"password":"123456","nickName":"moss","loginIp":"127.0.0.1","sex":"0","deptId":1625713027348,"phonenumber":"13522659887","loginDate":1625713027349,"delFlag":"0","userName":"管理员","userId":1625713027348,"email":"admin@126.com"}, type = class com.alibaba.fastjson.JSONObject
serialNo = c82f8649-78ad-4758-9a13-7b5613d24e5a, type = class java.lang.String
Exception in thread "main" java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to com.moss.mysql.entity.AppUser
	at com.moss.json.JsonTest.main(JsonTest.java:41)

结果分析
从上面可以看到AppUser对象在转为JSON字符串后的类型变成了com.alibaba.fastjson.JSONObject对象,在最后取出来就发生了ClassCastException异常了

怎么办呢。。。。。。。。。。。。。。
网上找了一堆,并没有找到解决方法,最后找了官方文档,发现了可以这样搞

// 其它不变,这里序列化时,加上SerializerFeature.WriteClassName,保留原始类型
String json = JSON.toJSONString(extMap, SerializerFeature.WriteClassName);
System.out.println("Json = " + json);

// 反序列化时加上TypeReference转成原始类型
localMap = JSON.parseObject(json, new TypeReference<Map<String, Object>>(){});

再次运行,发现转换后的json带上了原始类型了,如"@type":“com.moss.mysql.entity.AppUser”,但是。。。com.alibaba.fastjson.JSONException: autoType is not support又是什么鬼,还是不行,继续挖。。。

Json = {"@type":"java.util.HashMap","total":100,"user":{"@type":"com.moss.mysql.entity.AppUser","delFlag":"0","deptId":1625713550766,"email":"admin@126.com","loginDate":1625713550766,"loginIp":"127.0.0.1","nickName":"moss","password":"123456","phonenumber":"13522659887","sex":"0","userId":1625713550765,"userName":"管理员"},"serialNo":"df414adf-35e3-49dd-bbf7-b2b7ae6b962d"}
Exception in thread "main" com.alibaba.fastjson.JSONException: autoType is not support. com.moss.mysql.entity.AppUser
	at com.alibaba.fastjson.parser.ParserConfig.checkAutoType(ParserConfig.java:1466)
	at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:333)
	at com.alibaba.fastjson.parser.DefaultJSONParser.parse(DefaultJSONParser.java:1401)
	at com.alibaba.fastjson.parser.deserializer.JavaObjectDeserializer.deserialze(JavaObjectDeserializer.java:46)
	at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:688)
	at com.alibaba.fastjson.parser.deserializer.MapDeserializer.parseMap(MapDeserializer.java:198)
	at com.alibaba.fastjson.parser.deserializer.MapDeserializer.deserialze(MapDeserializer.java:65)
	at com.alibaba.fastjson.parser.deserializer.MapDeserializer.deserialze(MapDeserializer.java:43)
	at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:688)
	at com.alibaba.fastjson.JSON.parseObject(JSON.java:396)
	at com.alibaba.fastjson.JSON.parseObject(JSON.java:364)
	at com.alibaba.fastjson.JSON.parseObject(JSON.java:278)
	at com.moss.json.JsonTest.main(JsonTest.java:38)

Process finished with exit code 1

继续找了一遍,发现需要打开autoType功能,开启的方法有2种

// 1、JVM启动参数
-Dfastjson.parser.autoTypeSupport=true
// 2、代码中设置
ParserConfig.getGlobalInstance().setAutoTypeSupport(true); 

2、最终解决代码

官方文档:https://github.com/alibaba/fastjson/wiki/enable_autotype

package com.moss.json;

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.moss.mysql.entity.AppUser;

public class JsonTest {
    private static Map<String, Object> localMap = new HashMap<>();

	// 1、开启AutoTypeSupport
    static {
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
    }

    public static void main(String[] args) {
        AppUser user = new AppUser();
        user.setUserId(System.currentTimeMillis());
        user.setLoginIp("127.0.0.1");
        user.setUserName("管理员");
        user.setEmail("admin@126.com");
        user.setNickName("moss");
        user.setDelFlag("0");
        user.setDeptId(System.currentTimeMillis());
        user.setSex("0");
        user.setLoginDate(new Timestamp(System.currentTimeMillis()));
        user.setPassword("123456");
        user.setPhonenumber("13522659887");

        Map<String, Object> extMap = new HashMap<>();
        extMap.put("serialNo", UUID.randomUUID().toString());
        extMap.put("user", user);
        extMap.put("total", 100);

		// 2、序列化为JSON时,增加SerializerFeature.WriteClassName,保留数据原始类型
        String json = toJson(extMap);
        System.out.println("Json = " + json);

		// 3、反序列化时,用TypeReference指定原始类型
        localMap = toObject(json);
        for (Map.Entry<String, Object> e : localMap.entrySet()) {
            System.out.println(e.getKey() + " = " + e.getValue() + ", type = " + e.getValue().getClass());
        }

        AppUser appUser = get("user");
        System.out.println("appUser = " + appUser);
    }

    public static <T> T get(String key) {
        return (T) localMap.get(key);
    }

    /**
     * 转换为json
     * @param value
     * @return
     */
    public static String toJson(Object value) {
        if (Objects.isNull(value)) {
            return null;
        }
        return JSON.toJSONString(value, SerializerFeature.WriteClassName);
    }

    /**
     * 转换成java Object
     * @param jsonValue
     * @param <T>
     * @return
     */
    public static <T> T toObject(String jsonValue) {
        if (StringUtils.isEmpty(jsonValue)) {
            return null;
        }
        return JSON.parseObject(jsonValue, new TypeReference<T>(){});
    }
}

执行结果

Json = {"@type":"java.util.HashMap","total":100,"user":{"@type":"com.moss.mysql.entity.AppUser","delFlag":"0","deptId":1625714298279,"email":"admin@126.com","loginDate":1625714298279,"loginIp":"127.0.0.1","nickName":"moss","password":"123456","phonenumber":"13522659887","sex":"0","userId":1625714298279,"userName":"管理员"},"serialNo":"1e657959-2299-432d-82ed-87e7357e40e9"}
total = 100, type = class java.lang.Integer
user = AppUser{userId=1625714298279, deptId=1625714298279, userName=管理员, nickName=moss, userType=null, email=admin@126.com, phonenumber=13522659887, sex=0, avatar=null, password=123456, status=null, delFlag=0, loginIp=127.0.0.1, loginDate=2021-07-08 11:18:18.279, createBy=null, createTime=null, updateBy=null, updateTime=null, remark=null}, type = class com.moss.mysql.entity.AppUser
serialNo = 1e657959-2299-432d-82ed-87e7357e40e9, type = class java.lang.String
appUser = AppUser{userId=1625714298279, deptId=1625714298279, userName=管理员, nickName=moss, userType=null, email=admin@126.com, phonenumber=13522659887, sex=0, avatar=null, password=123456, status=null, delFlag=0, loginIp=127.0.0.1, loginDate=2021-07-08 11:18:18.279, createBy=null, createTime=null, updateBy=null, updateTime=null, remark=null}

Process finished with exit code 0

3、课外知识

添加autotype白名单,有三种方式
// 1、在代码中配置,如果有多个包名前缀,分多次addAccept
ParserConfig.getGlobalInstance().addAccept("com.moss.");
ParserConfig.getGlobalInstance().addAccept("com.husun.");

// 2、加上JVM启动参数,如果有多个包名前缀,用逗号隔开
-Dfastjson.parser.autoTypeAccept=com.moss.,com.husun.

// 3、通过类路径的fastjson.properties文件来配置,如果有多个包名前缀,用逗号隔开
fastjson.parser.autoTypeAccept=com.moss.,com.husun.
添加autotype黑名单,有三种方式
// 1、在代码中配置,如果有多个包名前缀,分多次addDeny
ParserConfig.getGlobalInstance().addDeny("com.moss.");
ParserConfig.getGlobalInstance().addDeny("com.husun.");

// 2、加上JVM启动参数,如果有多个包名前缀,用逗号隔开
-Dfastjson.parser.deny=com.moss.,com.husun.

// 3、通过类路径的fastjson.properties文件来配置,如果有多个包名前缀,用逗号隔开
fastjson.parser.deny=com.moss.,com.husun.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值