Jackson基础教程

前言

目前解析Json的工具包有,Gson,FastJson,Jackson,Json-lib。综合来看,Jackson的性能较优,稳定性也比较高,而且spring-boot-starter-web默认会引入Jackson包。因此介绍一下Jackson的使用。

Jackson目前有2个版本
1.x版本包名为org.codehaus.jackson
2.x版本包名为com.fasterxml.jackson

使用

在pom中加入如下依赖即可。

<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-core</artifactId>
	<version>2.9.2</version>
</dependency>

<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-databind</artifactId>
	<version>2.9.2</version>
</dependency>

<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-annotations</artifactId>
	<version>2.9.2</version>
</dependency>

前文说过,当使用spring-boot-starter-web模块时,会默认引入Jackson包,不必在pom中再次引入上面依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

序列化

将java对象序列化成json,@Data注解是用lombok插件来自动生成get和set方法

@Data
public class Student {

    /** 名字 */
    private String name;
    /** 年龄 */
    private Integer age;
    /** 头像 */
    private String profileImageUrl;
}

将常用的方法封装成一个常用的工具类,如下所示,有2个好处

  1. ObjectMapper 类只会生成一个,节省空间
  2. 可以定义统一的配置(后面细说)
@Slf4j
public class JsonUtil {

    private static ObjectMapper objectMapper = new ObjectMapper();
    
    /** 将对象转为string */
    public static <T> String obj2String(T obj){

        if(obj == null){
            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;
        }
    }

}

先简单介绍一下封装的工具类

1. 将对象转为json

public static <T> String obj2String(T obj){

	if(obj == null){
		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;
	}
}

各种类型均可

@Test
public void obj2String() throws Exception {

	Student student = new Student();
	student.setAge(10);
	student.setName("name");
	student.setProfileImageUrl("link");
	String result = JsonUtil.obj2String(student);
	// {"name":"name","age":10,"profileImageUrl":"link"}
	System.out.println(result);

	Map<String, List<Integer>> map = new HashMap<>();
	map.put("a", Arrays.asList(1, 2, 3));
	map.put("b", Arrays.asList(1, 2, 3));
	String result1 = JsonUtil.obj2String(map);
	// {"a":[1,2,3],"b":[1,2,3]}
	System.out.println(result1);
}

2. 将对象转为json,并格式化的输出

public static <T> String obj2StringPretty(T obj){
	if(obj == null){
		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;
	}
}
@Test
public void obj2StringPretty() throws Exception {
	Student student = new Student();
	student.setAge(10);
	student.setName("name");
	student.setProfileImageUrl("link");
	String result = JsonUtil.obj2StringPretty(student);

	/*
	{
		"name" : "name",
		"age" : 10,
		"profileImageUrl" : "link"
	}
	*/
	System.out.println(result);

	Map<String, List<Integer>> map = new HashMap<>();
	map.put("a", Arrays.asList(1, 2, 3));
	map.put("b", Arrays.asList(1, 2, 3));
	String result1 = JsonUtil.obj2StringPretty(map);

	/*
	{
		"a" : [ 1, 2, 3 ],
		"b" : [ 1, 2, 3 ]
	}
	*/
	System.out.println(result1);
}

反序列化

将json转为java对象

方式1

public static <T> T string2Obj(String str, Class<T> clazz){
	if(StringUtils.isEmpty(str) || clazz == null){
		return null;
	}

	try {
		return clazz.equals(String.class)? (T)str : objectMapper.readValue(str, clazz);
	} catch (Exception e) {
		log.warn("Parse String to Object error",e);
		return null;
	}
}

基本数据类型的转换

@Test
public void string2Obj() throws Exception {
	String str = "{\"name\":\"name\",\"age\":10,\"profileImageUrl\":\"link\"}";
	Student student = JsonUtil.string2Obj(str, Student.class);
	// Student(name=name, age=10, profileImageUrl=link)
	System.out.println(student);
}

各种复杂类型的转换,示例1

@Test
public void string2Obj1() throws Exception {

	Student student1 = new Student();
	student1.setAge(10);
	student1.setName("name1");
	student1.setProfileImageUrl("link1");

	Student student2 = new Student();
	student2.setAge(20);
	student2.setName("name2");
	student2.setProfileImageUrl("link2");

	List<Student> studentList = new ArrayList<>();
	studentList.add(student1);
	studentList.add(student2);
	String result = JsonUtil.obj2String(studentList);
	// [{"name":"name1","age":10,"profileImageUrl":"link1"},{"name":"name2","age":20,"profileImageUrl":"link2"}]
	System.out.println(result);

	List<Student> finalList = JsonUtil.string2Obj(result, List.class);
	// [{name=name1, age=10, profileImageUrl=link1}, {name=name2, age=20, profileImageUrl=link2}]
	System.out.println(finalList);
}

复杂类型的转换,示例2

@Test
public void string2Obj2() throws Exception {

	Map<String, List<Integer>> testMap = new HashMap<>();
	testMap.put("1", Arrays.asList(1, 2, 3));
	testMap.put("2", Arrays.asList(2, 3, 4));
	
	String result = JsonUtil.obj2String(testMap);
	// {"1":[1,2,3],"2":[2,3,4]}
	System.out.println(result);

	Map<String, List<Integer>> finalMap = JsonUtil.string2Obj(result, Map.class);
	// {1=[1, 2, 3], 2=[2, 3, 4]}
	System.out.println(finalMap);
}

到现在为止,你可以用这3个函数进行序列化和反序列化操作

/** 将对象转为json */
public static <T> String obj2String(T obj) 

/** 将对象转为json,并格式化显示 */
public static <T> String obj2StringPretty(T obj)

/** 将json转为对象 */
public static <T> T string2Obj(String str, Class<T> clazz)

可能你还看过其他类型的解析方式,如下所示,但是没有必要,上面3个函数完全能满足你的需求,我这里演示一下

方式2

public static <T> T string2Obj(String str, TypeReference<T> typeReference){
	if(StringUtils.isEmpty(str) || typeReference == null){
		return null;
	}
	try {
		return (T)(typeReference.getType().equals(String.class)? str : objectMapper.readValue(str,typeReference));
	} catch (Exception e) {
		log.warn("Parse String to Object error",e);
		return null;
	}
}
@Test
public void string2Obj3() throws Exception {

	Student student1 = new Student();
	student1.setAge(10);
	student1.setName("name1");
	student1.setProfileImageUrl("link1");

	Student student2 = new Student();
	student2.setAge(20);
	student2.setName("name2");
	student2.setProfileImageUrl("link2");

	List<Student> studentList = new ArrayList<>();
	studentList.add(student1);
	studentList.add(student2);
	String result = JsonUtil.obj2String(studentList);
	// [{"name":"name1","age":10,"profileImageUrl":"link1"},{"name":"name2","age":20,"profileImageUrl":"link2"}]
	System.out.println(result);

	List<Student> finalList = JsonUtil.string2Obj(result, new TypeReference<List<Student>>() {});
	// [{name=name1, age=10, profileImageUrl=link1}, {name=name2, age=20, profileImageUrl=link2}]
	System.out.println(finalList);
}

方式3

public static <T> T string2Obj(String str, Class<?> collectionClass, Class<?>... elementClasses){
	JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass,elementClasses);
	try {
		return objectMapper.readValue(str,javaType);
	} catch (Exception e) {
		log.warn("Parse String to Object error",e);
		return null;
	}
}
@Test
public void string2Obj4() throws Exception {

	Student student1 = new Student();
	student1.setAge(10);
	student1.setName("name1");
	student1.setProfileImageUrl("link1");

	Student student2 = new Student();
	student2.setAge(20);
	student2.setName("name2");
	student2.setProfileImageUrl("link2");

	List<Student> studentList = new ArrayList<>();
	studentList.add(student1);
	studentList.add(student2);
	String result = JsonUtil.obj2String(studentList);
	// [{"name":"name1","age":10,"profileImageUrl":"link1"},{"name":"name2","age":20,"profileImageUrl":"link2"}]
	System.out.println(result);

	List<Student> finalList = JsonUtil.string2Obj(result, List.class, Student.class);
	// [{name=name1, age=10, profileImageUrl=link1}, {name=name2, age=20, profileImageUrl=link2}]
	System.out.println(finalList);
}

常用注解及配置

@JsonIgnore忽略属性

@Data
public class Student {

    /** 名字 */
    private String name;
    /** 年龄 */
    private Integer age;
    /** 头像 */
    @JsonIgnore
    private String profileImageUrl;
}
@Test
public void jsonIgnore() throws Exception {
	Student student = new Student();
	student.setAge(10);
	student.setName("name");
	student.setProfileImageUrl("link");
	String result = JsonUtil.obj2String(student);
	// {"name":"name","age":10}
	System.out.println(result);

	String str = "{\"name\":\"name\",\"age\":10,\"profileImageUrl\":\"link\"}";
	Student student1 = JsonUtil.string2Obj(str, Student.class);
	// Student(name=name, age=10, profileImageUrl=null)
	System.out.println(student1);
}

@JsonProperty

当Json的属性值和Java的属性值不一样时,会映射失败,用这个注解指定映射关系,在属性上用这个注解,则序列化和反序列化都会用这个值。如果序列化和反序列化的属性不一致,可以在get方法或者set方法上用这个注解,set方法影响反序列化,get方法影响序列化。

去掉@Data注解

public class Student {

    /** 名字 */
    private String name;
    /** 年龄 */
    private Integer age;
    /** 头像 */
    private String profileImageUrl;

    @JsonProperty("getImage")
    public String getProfileImageUrl() {
        return profileImageUrl;
    }

    @JsonProperty("setImage")
    public void setProfileImageUrl(String profileImageUrl) {
        this.profileImageUrl = profileImageUrl;
    }

}
@Test
public void jsonProperty() throws Exception {

	String str = "{\"name\":\"name\",\"age\":10,\"setImage\":\"link\"}";
	Student student1 = JsonUtil.string2Obj(str, Student.class);
	// name
	System.out.println(student1.getName());
	// 10
	System.out.println(student1.getAge());
	// link
	System.out.println(student1.getProfileImageUrl());
	// {"name":"name","age":10,"getImage":"link"}
	System.out.println(JsonUtil.obj2String(student1));
}

@JsonFormat

日期格式化注解,不再演示

@JsonIgnoreProperties(ignoreUnknown = true)

如果json字符串中的属性个数小于java对象中的属性个数,可以顺利转换,java中多的那个属性为null
如果json字符串中出现java对象中没有的属性,则在将json转换为java对象时会报错:Unrecognized field, not marked as ignorable

解决方法1:
在目标对象的类级别上添加注解:@JsonIgnoreProperties(ignoreUnknown = true)

解决方法2:

@Slf4j
public class JsonUtil {

    private static ObjectMapper objectMapper = new ObjectMapper();

    static {
        //忽略 在json字符串中存在,但是在java对象中不存在对应属性的情况。防止错误
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

}

这样就不用在目标类上加@JsonIgnoreProperties属性了,体现了全局配置的优势,配置项很多,包括格式化显示日期等,不再详细介绍,百度配置即可

用Tree Mode方式解析JSON

除了将json转为对象外,还可以用Tree Mode方式解析JSON,全程无脑操作,除了一些特别复杂的JSON,或者只取JSON中的一部分,千万不要用这种二B方式解析JSON。正确的方式是将JSON直接转为对象。我这里演示一下解析的方式

{
    "name": "zhansan", 
    "age": 100, 
    "schools": [
        {
            "name": "tsinghua", 
            "location": "beijing"
        }, 
        {
            "name": "pku", 
            "location": "beijing"
        }
    ]
}
@Test
public void parseJson() throws Exception {
	String jsonStr = "{\"name\":\"zhansan\",\"age\":100,\"schools\":[{\"name\":\"tsinghua\",\"location\":\"beijing\"},{\"name\":\"pku\",\"location\":\"beijing\"}]}";

	ObjectMapper objectMapper = new ObjectMapper();
	JsonNode jsonNode = objectMapper.readTree(jsonStr);

	String name = jsonNode.get("name").asText();
	int age = jsonNode.get("age").asInt();
	// name is zhansan age is 100
	System.out.println("name is " + name + " age is " + age);

	JsonNode schoolsNode = jsonNode.get("schools");
	for (int i = 0; i < schoolsNode.size(); i++) {
		String schooleName = schoolsNode.get(i).get("name").asText();
		String schooleLocation = schoolsNode.get(i).get("location").asText();
		// schooleName is tsinghua schooleLocation is beijing
		// schooleName is pku schooleLocation is beijing
		System.out.println("schooleName is " + schooleName + " schooleLocation is " + schooleLocation);
	}
}

参考博客

[1]http://tutorials.jenkov.com/java-json/jackson-objectmapper.html#jackson-objectmapper-example
[2]https://blog.csdn.net/hi_kevin/article/details/36639571
[3]https://blog.csdn.net/chszs/article/details/49519209
[4]https://blog.csdn.net/u013253310/article/details/51576737
对象和json相互转换需要注意的事项
[5]http://www.cnblogs.com/jinlin/p/10300964.html

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java识堂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值