从学习java开始,必然是要接触到序列化的,json序列化就是其中之一,而且是使用的比较频繁的一种序列化方式。自从某网站学习了Geely老师的课程后,决定把json序列化相关的知识做一次小的总结,并最终总结出JsonUtil工具类。
1.相关的jar依赖
<!--json序列化包-->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<!--日志包-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.26</version>
</dependency>
<!--lombok工具包-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
</dependency>
<!--工具包-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
2.对象序列化成json字符串
/**
* json工具类
* final修饰符是为了避免创建JsonUtil的子类
*/
@Slf4j
public final class JsonUtil {
/**
* 防止使用者直接new JsonUtil()
*/
private JsonUtil() {
}
private static ObjectMapper objectMapper = new ObjectMapper();
/**
* 注意以下配置,特别重要
*/
static {
//对象所有字段全部列入序列化
objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.ALWAYS);
/**
* 所有日期全部格式化成时间戳
* 因为即使指定了DateFormat,也不一定能满足所有的格式化情况,所以统一为时间戳,让使用者按需转换
*/
objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, true);
/**
* 忽略空Bean转json的错误
* 假设只是new方式创建对象,并且没有对里面的属性赋值,也要保证序列化的时候不报错
*/
objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
/**
* 忽略反序列化中json字符串中存在,但java对象中不存在的字段
*/
objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
/**
* 对象转换成json字符串
*
* @param obj
* @param <T>
* @return
*/
public static <T> String obj2String(T obj) {
if (Objects.isNull(obj)) {
return null;
}
try {
return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj);
} catch (Exception e) {
log.warn("Parse object to String error", e);
//即使序列化出错,也要保证程序走下去
return null;
}
}
/**
* 对象转json字符串(带美化效果)
*
* @param obj
* @param <T>
* @return
*/
public static <T> String obj2StringPretty(T obj) {
if (Objects.isNull(obj)) {
return null;
}
try {
return obj instanceof String ? (String) obj : objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
} catch (Exception e) {
log.warn("Parse object to String error", e);
//即使序列化出错,也要保证程序走下去
return null;
}
}
/**
* 主函数,用于测试
*
* @param args
*/
public static void main(String[] args) {
User user = new User("Zz", 26);
/**
* 普通序列化
*/
System.out.println(JsonUtil.obj2String(user));
/**
* 美化序列化
*/
System.out.println(JsonUtil.obj2StringPretty(user));
}
/**
* 实体类User
*/
@Data
@ToString
@AllArgsConstructor
public static class User {
public User() {
}
/**
* 名字
*/
private String name;
/**
* 年龄
*/
private int age;
}
}
上面主函数的测试结果:
{"name":"Zz","age":26}
//美化后的结果
{
"name" : "Zz",
"age" : 26
}
3.反序列化(json字符串转对象)
/**
* json字符串转简单对象
*
* @param json
* @param clazz
* @param <T>
* @return
*/
public static <T> T string2Obj(String json, Class<T> clazz) {
if (StringUtils.isEmpty(json) || Objects.isNull(clazz)) {
return null;
}
try {
return clazz.equals(String.class) ? (T) json : objectMapper.readValue(json, clazz);
} catch (Exception e) {
log.warn("Parse String to Object error", e);
//即使序列化出错,也要保证程序走下去
return null;
}
}
主函数测试:
/**
* 主函数,用于测试
*
* @param args
*/
public static void main(String[] args) {
/**
* 特意多加一个额外的字段:sex,
* 之所以还能正确序列化成功,
*是因为设置DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES=false
*/
String json = "{\"name\":\"Zz\",\"age\":26,\"sex\":\"男\"}";
User user = JsonUtil.string2Obj(json, User.class);
// User对象要重写toString()方法
System.out.println(user);
}
测试结果:
User(name=Zz, age=26)
4.复杂对象的反序列化
在平时开发中也是会遇到需要将字符串反序列化成类似List<User>的情况,如果使用上面的string2Obj()方法,Class参数是给List.class还是User.class,貌似只能给List.class才能让程序正确运行,但是得到的结果却不是我们预期的List<User>;所以,我们需要对string2Obj()方法做一次增强:
/**
* json字符串转复杂对象
*
* @param json
* @param typeReference 例如:new TypeReference<List<User>>(){}
* @param <T> 例如:List<User>
* @return
*/
public static <T> T string2Obj(String json, TypeReference<T> typeReference) {
if (StringUtils.isEmpty(json) || Objects.isNull(typeReference)) {
return null;
}
try {
return (T)(typeReference.getType().equals(String.class) ? (T) json : objectMapper.readValue(json, typeReference));
} catch (IOException e) {
log.warn("Parse String to Object error", e);
//即使序列化出错,也要保证程序走下去
return null;
}
}
/**
* json字符串转复杂对象
*
* @param json
* @param collectionClass 例如:List.class
* @param elementClasses 例如:User.class
* @param <T> 例如:List<User>
* @return
*/
public static <T> T string2Obj(String json, Class<?> collectionClass, Class<?>... elementClasses) {
if (StringUtils.isEmpty(json) || Objects.isNull(collectionClass) || Objects.isNull(elementClasses)) {
return null;
}
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
try {
return objectMapper.readValue(json, javaType);
} catch (IOException e) {
log.warn("Parse String to Object error", e);
//即使序列化出错,也要保证程序走下去
return null;
}
}
测试:
/**
* 主函数,用于测试
*
* @param args
*/
public static void main(String[] args) {
List<User> list = new ArrayList<>();
list.add(new User("Zz", 26));
list.add(new User("james", 30));
list.add(new User("kelly", 22));
list.add(new User("itachi", 20));
list.add(new User("naruto", 16));
//先做序列化
String json = JsonUtil.obj2String(list);
System.out.println("序列化结果:");
System.out.println(json);
//拿到序列化后的字符串再做反序列化
List<User> result1 = JsonUtil.string2Obj(json, new TypeReference<List<User>>(){});
System.out.println("反序列化结果1:");
System.out.println(result1);
//拿到序列化后的字符串再做反序列化
List<User> result2 = JsonUtil.string2Obj(json, List.class, User.class);
System.out.println("反序列化结果2:");
System.out.println(result2);
}
测试结果:
//序列化结果:
[{"name":"Zz","age":26},{"name":"james","age":30},{"name":"kelly","age":22},{"name":"itachi","age":20},{"name":"naruto","age":16}]
//反序列化结果:
[JsonMain.User(name=Zz, age=26), JsonMain.User(name=james, age=30), JsonMain.User(name=kelly, age=22), JsonMain.User(name=itachi, age=20), JsonMain.User(name=naruto, age=16)]
//反序列化结果:
[JsonMain.User(name=Zz, age=26), JsonMain.User(name=james, age=30), JsonMain.User(name=kelly, age=22), JsonMain.User(name=itachi, age=20), JsonMain.User(name=naruto, age=16)]
5.最终得到的产物JsonUtil
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.codehaus.jackson.type.JavaType;
import org.codehaus.jackson.type.TypeReference;
import java.util.Objects;
@Slf4j
public final class JsonUtil {
/**
* 防止使用者直接new JsonUtil()
*/
private JsonUtil() {
}
private static ObjectMapper objectMapper = new ObjectMapper();
static {
//对象所有字段全部列入序列化
objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.ALWAYS);
/**
* 所有日期全部格式化成时间戳
* 因为即使指定了DateFormat,也不一定能满足所有的格式化情况,所以统一为时间戳,让使用者按需转换
*/
objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, true);
/**
* 忽略空Bean转json的错误
* 假设只是new方式创建对象,并且没有对里面的属性赋值,也要保证序列化的时候不报错
*/
objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
/**
* 忽略反序列化中json字符串中存在,但java对象中不存在的字段
*/
objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
/**
* 对象转换成json字符串
*
* @param obj
* @param <T>
* @return
*/
public static <T> String obj2String(T obj) {
if (Objects.isNull(obj)) {
return null;
}
try {
return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj);
} catch (Exception e) {
log.warn("Parse object to String error", e);
//即使序列化出错,也要保证程序走下去
return null;
}
}
/**
* 对象转json字符串(带美化效果)
*
* @param obj
* @param <T>
* @return
*/
public static <T> String obj2StringPretty(T obj) {
if (Objects.isNull(obj)) {
return null;
}
try {
return obj instanceof String ? (String) obj : objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
} catch (Exception e) {
log.warn("Parse object to String error", e);
//即使序列化出错,也要保证程序走下去
return null;
}
}
/**
* json字符串转简单对象
*
* @param <T>
* @param json
* @param clazz
* @return
*/
public static <T> T string2Obj(String json, Class<T> clazz) {
if (StringUtils.isEmpty(json) || Objects.isNull(clazz)) {
return null;
}
try {
return clazz.equals(String.class) ? (T) json : objectMapper.readValue(json, clazz);
} catch (Exception e) {
log.warn("Parse String to Object error", e);
//即使序列化出错,也要保证程序走下去
return null;
}
}
/**
* json字符串转复杂对象
*
* @param json
* @param typeReference 例如:new TypeReference<List<User>>(){}
* @param <T> 例如:List<User>
* @return
*/
public static <T> T string2Obj(String json, TypeReference<T> typeReference) {
if (StringUtils.isEmpty(json) || Objects.isNull(typeReference)) {
return null;
}
try {
return (T)(typeReference.getType().equals(String.class) ? (T) json : objectMapper.readValue(json, typeReference));
} catch (Exception e) {
log.warn("Parse String to Object error", e);
//即使序列化出错,也要保证程序走下去
return null;
}
}
/**
* json字符串转复杂对象
*
* @param json
* @param collectionClass 例如:List.class
* @param elementClasses 例如:User.class
* @param <T> 例如:List<User>
* @return
*/
public static <T> T string2Obj(String json, Class<?> collectionClass, Class<?>... elementClasses) {
if (StringUtils.isEmpty(json) || Objects.isNull(collectionClass) || Objects.isNull(elementClasses)) {
return null;
}
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);
try {
return objectMapper.readValue(json, javaType);
} catch (Exception e) {
log.warn("Parse String to Object error", e);
//即使序列化出错,也要保证程序走下去
return null;
}
}
}
总结:这个JsonUtil在实际开发环境中经常会使用,小伙伴们可以直接将这个类使用的平时的开发当中。也特别感谢Geely老师,让我对json序列化操作有了更深的理解。
网友评论