JSON字符串和对象(泛型)互转并解决json对象⾸字母⼩写⽂章⽬录
1 JSON解析问题
1.1 User实体
⾸先假设有⼀个实体对象user:
private Integer UserId;
private  Integer getUserId (){
return UserId;
}
private Integer setUserId(Integer UserId){
UserId = UserId;
}
⽤的是com.alibaba.fastjson.JSON的包,⽤的是toJSON⽅法
1.2 转换为JSON对象后⾸字母⼩写
在实体对象的每个get⽅法上添加@JSONField(name=“UserId”)
就可以有效避免,⾸字母⼩写的问题
@JSONField(name="UserId")
private  Integer getUserId (){
return UserId;
}
1.3 json对象或json字符串与实体互转
1.3.1 实体转json对象或字符串
User u =new User ();
u.setUserId(123);
//转换为json对象
JSON jsonObject = JSON(u);
//转换为json字符串
String jsonString = JSONString(u);
得到的结果是⼀样的,只是类型不同⽽已
jsonObject:{"UserId":123}
jsonString:{"UserId":"123"}
1.3.2 json对象或json字符串转换为实体对象
//把json对象转换为实体对象
User userObject =JavaObject(jsonObject,User.class);
/
/把json字符串转换为实体对象
User userString = JSON.parseObject(jsonString,User.class);
如果不想建⽴实体对象,⽽只想从JSON对象中获取某⼀个字段可以这样操作:
//解析字符串
//第⼀个参数是json字符串,第⼆个参数是实体类
JSONObject json =JSON.JSONString(u));
String userId=(("UserId");
System.out.println(userId);
注意:实体bean⾥⾯需要重写写toString⽅法才能直接输出对象⾥⾯的每个属性。
1.4 Gson来解析和反解析json对象
1.4.1 解析普通对象
Gson是由Google提供的效率功能更强⼤
User u =new User ();
u.setUserId(123);
object toGson gson =new Gson();
//把对象转换为json字符串
String userString = Json(u);
System.out.println(userString);
//把json字符串转换为实体bean对象
User user = gson.fromJson(userString,User.class);
System.out.println(user);
得到的结果:
{"userId":123}
User [userId=123]
1.4.2 解析泛型对象
有如下泛型对象:
@Data
public class PageList<T>{
public List<T> body;
}
注意:必须引⽤构建⾕歌的TypeToken对象
Gson gson =new Gson();
Type type =new TypeToken<PageList<User>>(){}.getType();
/
/此处的result是要解析的字符串
PageList<User> pageList = gson.fromJson(result, type);
1.5 JSONObject来解析和反解析
注意:如果⽤的是阿⾥的json类的话,JSONObject是JSON的⼦类
1.5.1 转为json对象或json字符串
User u =new User ();
u.setUserId(123);
//json对象
System.out.JSON(u));
//json字符串
System.out.JSONString(u));
得到的结果:
jsonObject:{"UserId":123}
jsonString:{"UserId":"123"}
1.5.2 反解析实体对象
1.5.
2.1 反解析普通实体对象
//把json对象转换为实体对象
//第⼀个参数是JSON对象,第⼆个对象是要解析的实体类
User userObject =JavaObject((JSON(u),User.class);
System.out.println(userObject);
//得到的结果
User{UserId=123}
//解析字符串
//第⼀个参数是json字符串,第⼆个参数是实体类
User userObject2 =JSON.JSONString(u),User.class);
System.out.println(userObject2);
//得到的结果
User{UserId=123}
如果不想建⽴实体对象,⽽只想从JSONObject对象中获取某⼀个字段可以这样操作:
//解析字符串
//第⼀个参数是json字符串,第⼆个参数是实体类
JSONObject json =JSONObejct.JSONString(u));
String userId=(("UserId");
System.out.println(userId);
1.5.
2.2 反解析泛型实体对象
使⽤TypeReference对象获得解析泛型对象
有如下泛型对象:
@Data
public class PageList<T>{
public List<T> body;
}
可以使⽤如下⽅法解析:
/
/此处的result是json字符串
Result<PageList<User> result = JSONObject.parseObject(result,new TypeReference<Result<PageList<User>>>(){});
1.6 JSON引⽤和重复引⽤
简单说,重复引⽤就是⼀个集合/对象中的多个元素/属性同时引⽤同⼀对象,循环引⽤就是集合/对象中的多个元素/属性存在相互引⽤导致循环
1.6.1 重复引⽤
List<User> list =new ArrayList<>();
User user=new User();
list.add(user);
list.add(user);
System.out.JSONString(list));
//得到的结果
[{"userId":"12"},{"$ref":"$[0]"}]
对于这个问题可以关闭json的引⽤检测:
把JSONString(list)⾥⾯添加SerializerFeature.DisableCircularReferenceDetect,如:
1.6.2 循环引⽤
// 循环引⽤的特殊情况,⾃引⽤
Map<String,Object> map =new HashMap<>();
map.put("map",map);
//
// map1引⽤了map2,⽽map2⼜引⽤map1,导致循环引⽤
Map<String,Object> map1 =new HashMap<>();
Map<String,Object> map2 =new HashMap<>();
map1.put("map",map2);
map2.put("map",map1);
对于循环引⽤,不能关闭json的引⽤检测,不然会报错java.lang.StackOverflowError,对于循环引⽤,最好的解决办法还是养成良好编程习惯2 Fastjson源码分析对象⾸字母问题
2.1 问题引⼊
使⽤FastJson, 在输出下⾯⼀段Json的时候出现此问题, 期望是⼤写但是fastJson将值⾃动⾸字母变成⼩写了
{"code":0,"message":"","result":{"facts":{"ip":{"aCUN_ONE_MIN":0,"aCUN_TEN_MIN":0}},"level":0}}
2.2 源码分析
查询后发现fastjson内部做Bean转换时会使⽤到 com.alibaba.fastjson.util.TypeUtils, 核⼼代码如下, 在
类加载的时候会去读取环境变量fastjsonpatibleWithJavaBean, 不到则使⽤默认值false,将会导致⾸字母⼩写
public static boolean compatibleWithJavaBean =false;
static{
try{
String prop = Property("fastjsonpatibleWithJavaBean");
if("true".equals(prop)){
compatibleWithJavaBean =true;
}else if("false".equals(prop)){
compatibleWithJavaBean =false;
}
}catch(Throwable ex){
// skip        }
}
public static List<FieldInfo>computeGetters(Class<?> clazz, Map<String, String> aliasMap,boolean sorted){
String propertyName;
if(Character.isUpperCase(c3)){
if(compatibleWithJavaBean){
propertyName = Introspector.decapitalize(methodName.substring(3));
}else{
propertyName = LowerCase(methodName.charAt(3))+ methodName.substring(4);
}
}else if(c3 =='_'){
propertyName = methodName.substring(4);
}else if(c3 =='f'){
propertyName = methodName.substring(3);
}else{
continue;
}}
2.3 解决⽅法
解决⽅案:
1. 如果项⽬由多个模块且为分布式部署, 则可考虑使⽤设置System.property
2. ⼀般只是极少数的代码出现此情况, 那么建议直接在单例Service初始化时, 在静态块中直接改变TypeUtils的变量值, 如果⽤Spring的话
可以使⽤InitializingBean进⾏处理
TypeUtilspatibleWithJavaBean =true;
3. 此变量是public的注意要在⼀个地⽅进⾏改动, 避免线程安全问题

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。