文章目录
首先给出我定义的对象类:
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Student implements Serializable {
private long id;
private String name;
private int age;
private String sex;
情况1:现在我有一个正常的序列化后的字符串(note:序列化字段均为java对象中的字段),需要将其反序列化为一个对象。
fastJson和jackJson的做法如下:
String json = "{\"name\": \"king\",\n"
+ "\"age\": 1,\n"
+ "\"sex\":\"1\"\n }";
Student student_jackJson = new ObjectMapper().readValue(json, Student.class);
Student student_fastJson = JSONObject.toJavaObject(JSONObject.parseObject(json), Student.class);
System.out.println("student_jackJson = " + student_jackJson);
System.out.println("student_fastJson = " + student_fastJson);
结果如下:
分析:可以发现对于该情况,fastJson和jackJson均会输出同样的结果。两者使用无异
情况2:当现在我有一个不正常的序列化后的字符串(note:存在序列化字段不在java对象字段中),需要将其反序列化为一个对象。
String json = "{\"name\": \"king\",\n"
+ "\"age\": 1,\n"
+ "\"color\": \"red\",\n"
+ "\"sex\":\"1\"\n }";
Student student_fastJson = JSONObject.toJavaObject(JSONObject.parseObject(json), Student.class);
Student student_jackJson = new ObjectMapper().readValue(json, Student.class);
System.out.println("student_jackJson = " + student_jackJson);
System.out.println("student_fastJson = " + student_fastJson);
结果:(报错)
分析:从报错信息来看,是jackJson解析错误,为了让大家看的更清楚和通透,下面我将每个反序列化的步骤try…catch一下,再跑一遍。
使用try…catch重试:
String json = "{\"name\": \"king\",\n"
+ "\"age\": 1,\n"
+ "\"color\": \"red\",\n"
+ "\"sex\":\"1\"\n }";
try {
Student student_fastJson = JSONObject.toJavaObject(JSONObject.parseObject(json), Student.class);
System.out.println("student_fastJson = " + student_fastJson);
} catch (Exception e) {
System.out.println("student_fastJson解析报错" + e);
}
try {
Student student_jackJson = new ObjectMapper().readValue(json, Student.class);
System.out.println("student_jackJson = " + student_jackJson);
} catch (Exception e) {
System.out.println("student_jackJson解析报错" + e);
}
结果如下图所示:可以看到fastJson输出了;但是jackJson报错了,不能识别color字段,没有标记为可忽略的
分析:jackJson不支持不存在的字段进行对象的反序列化,fastJson则会过滤掉该情况
解决:在java对象中写上注解@JsonIgnoreProperties(ignoreUnknown = true)即可
情况3:当现在我有一个不正常的序列化后的字符串(note:序列化字段在java对象字段中,但是大小写不一样),需要将其反序列化为一个对象。
String json = "{\"name\": \"king\",\n"
+ "\"Age\": 1,\n"
+ "\"color\": \"red\",\n"
+ "\"Sex\":\"1\"\n }";
try {
Student student_fastJson = JSONObject.toJavaObject(JSONObject.parseObject(json), Student.class);
System.out.println("student_fastJson = " + student_fastJson);
} catch (Exception e) {
System.out.println("student_fastJson解析报错" + e);
}
try {
Student student_jackJson = new ObjectMapper().readValue(json, Student.class);
System.out.println("student_jackJson = " + student_jackJson);
} catch (Exception e) {
System.out.println("student_jackJson解析报错" + e);
}
结果如下图所示:可以看到fastJson可以忽略大小写问题正常解析字段参数,而jackJson因大小写问题“age”和“sex”字段无法正常解析。
分析:fastJson会把大写转小写,而jackJson解析时时默认匹配大小写的。
源码分析如下:
fastJson:
核心方法是smartMatch。里面有两个重要的转换:fnv1a_64_lower、fnv1a_64_extract。
如果fnv1a_64_lower中得到的hashcode值不在对象生成的smartMatchHashArray中,再执行fnv1a_64_extract,判断所得的hashCode值是否在对象的smartMatchHashArray中。当找到值后,即可进行赋值操作。
fnv1a_64_lower:将大写转成小写
fnv1a_64_extract:将字段中的下划线和减号去掉,然后转成小写
jackJson:
核心方法是vanillaDeserialize,在该方法里会将传入序列化后的字段逐个遍历,并通过SettableBeanProperty prop = this._beanProperties.find(propName)去拿到字段的值。在下图中可以看到,jackJson默认不转换大小写。
jackJson忽略大小写的解决方式:设置忽略大小写
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES,true);//忽略大小写 默认为false
Student student_jackJson = objectMapper.readValue(json, Student.class);
System.out.println("student_jackJson = " + student_jackJson);
情况4:在情况3的条件下,将Student类的数字类型参数改为包装类
即:当现在我有一个不正常的序列化后的字符串(note:序列化字段在java对象字段中,但是大小写不一样),需要将其反序列化为一个对象。此时Student类为:
public class Student {
private Long id;
private String name;
private Integer age;
private String sex;
}
此时执行代码:
```java
String json = "{\"name\": \"king\",\n"
+ "\"Age\": 1,\n"
+ "\"color\": \"red\",\n"
+ "\"Sex\":\"1\"\n }";
try {
Student student_fastJson = JSONObject.toJavaObject(JSONObject.parseObject(json), Student.class);
System.out.println("student_fastJson = " + student_fastJson);
} catch (Exception e) {
System.out.println("student_fastJson解析报错" + e);
}
try {
Student student_jackJson = new ObjectMapper().readValue(json, Student.class);
System.out.println("student_jackJson = " + student_jackJson);
} catch (Exception e) {
System.out.println("student_jackJson解析报错" + e);
}
结果:
分析:因为数字包装类型的初始化值是null,而基本数据类型是0,因此有细微的差距。