ObjectMapper好用的对象转json的方式

一、前言

Jackson和Fastjson都是比较出名的JSON解析库,SpringMVC默认使用的是Jackson,而且在企业项目中也大多使用的是Jackson,感觉还是很有必要熟悉Jackson的基本使用的。

1. 引入Jackson

如果只是简单的Java代码,不使用Spring Boot的话,直接引入Jackson。

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

如果是使用了SpringBoot的项目,引入spring-boot-starter-web就会自动引入Jackson。

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

二、ObjectMapper


我们使用Jackson等工具时,最常见的场景就是JSON的序列化和反序列化。而Jackson最常用的的就是ObjectMapper, 它提供了丰富的方法。

1. 创建ObjectMapper
如果是普通Java项目,则new一个ObjectMapper。

private ObjectMapper mapper = new ObjectMapper();


2.如果是使用Spring项目,则自动注入ObjectMapper。

@Autowired
private ObjectMapper objectMapper;

2. 序列化
假设有一个Java类:Student。

2.1 Java对象 转 JSON

Student student = getStudent();
String studentStr = mapper.writeValueAsString(student);


2.2 Java List 转 JSON

List<Student> studentList= getStudentList();
String studentListStr = mapper.writeValueAsString(studentList);


2.3 Java Map 转 JSON

Map<String, Object> studentMap = new HashMap<>();
studentMap.put("id", "1");
studentMap.put("name", "亚瑟");
studentMap.put("age", 33);

String studentJsonStr = mapper.writeValueAsString(studentMap);


2.4 美化输出格式
在调writeValueAsString之前先调writerWithDefaultPrettyPrinter

String studentStr = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(student);


2.5 序列化结果写文件

mapper.writeValue(new File(OBJECT_FILE_PATH_FOR_WRITE_FROM_SRC), student);


3. 反序列化
3.1 JSON 转 Java对象

String studentStr = getStudentString();
Student student = mapper.readValue(studentStr, Student.class);



3.2 JSON 转 Java List

List<Student> studentList1 = mapper.readValue(studentListStr , new TypeReference<>() {});
或者
List<Student> studentList2 = Arrays.asList(mapper.readValue(studentListStr, Student[].class));



3.3 JSON 转 Java Map

HashMap studentMap = mapper.readValue(studentStr, HashMap.class);


3.4 JSON File 转 Java对象

File file = new File(OBJECT_FILE_PATH_FROM_SRC);
Student student = mapper.readValue(file, Student.class);



3.5 JSON Reader 转 Java对象

File file = new File(OBJECT_FILE_PATH_FROM_SRC);
Reader reader = new java.io.FileReader(file);
Student student = mapper.readValue(reader, Student.class);



3.6 JSON InputStream 转 Java对象

InputStream inputStream = new FileInputStream(OBJECT_FILE_PATH_FROM_SRC);
Student student = mapper.readValue(inputStream, Student.class);



3.7 JSON Byte Array 转 Java对象

Student student = mapper.readValue(studentStr.getBytes(StandardCharsets.UTF_8), Student.class);



3.8 JSON via URL 转 Java对象

URL url = new URL("file:" + OBJECT_FILE_PATH_FROM_SRC);
Student student6 = mapper.readValue(url, Student.class);



三、Jackson注解
1. 序列化/反序列化都生效注解
1.1 @JsonIgnore
工作中一般会修饰Java类的属性上,无论序列化还是反序列化,Jackson都会忽略这个属性。
举个例子:@JsonIgnore修饰id属性

@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentTestForJsonIgnore {

    @JsonIgnore
    private String id;

    private String name;
    
    //注意得用Integer,而不能用int
    private Integer age;
}


序列化:

StudentTestForJsonIgnore stu = new StudentTestForJsonIgnore("1", "亚瑟", 30);
String stuStr = mapper.writeValueAsString(stu);
System.out.println(stuStr);


打印序列化结果: 忽略了id

{"name":"亚瑟","age":30}


反序列化:

String stuFullStr = "{\"id\":\"1\",\"name\":\"亚瑟\",\"age\":30}";
StudentTestForJsonIgnore stu2 = mapper.readValue(stuFullStr, StudentTestForJsonIgnore.class);
System.out.println(stu2.toString());


打印反序列化结果: 忽略了id

StudentTestForJsonIgnore(id=null, name=亚瑟, age=30)


1.2 @JsonIgnoreProperties
@JsonIgnoreProperties的作用和@JsonIgnore类似,但是@JsonIgnoreProperties修饰在Java类上,它可设置忽略多个属性,且可以设置ignoreUnknown = true,反序列化时,忽略在JSON中存在,但在Java类中不存在的字段,而不报异常。
举个例子:@JsonIgnoreProperties设置了"id", “age”,且设ignoreUnknown = true

@Data
@AllArgsConstructor
@NoArgsConstructor
@JsonIgnoreProperties(value = {"id", "age"}, ignoreUnknown = true)
public class StudentTestForJsonIgnoreProperties {

    private String id;

    private String name;

    private Integer age;
}



序列化:

StudentTestForJsonIgnoreProperties stu = new StudentTestForJsonIgnoreProperties("1", "亚瑟", 30);
String stuStr = mapper.writeValueAsString(stu);
System.out.println(stuStr);


打印序列化结果: 忽略了"id", "age"这2个属性

{"name":"亚瑟"}


反序列化:

String stuFullStr = "{\"id\":\"1\",\"name\":\"亚瑟\",\"age\":30, \"nickName\":\"Yase\"}";    
StudentTestForJsonIgnoreProperties stu2 = mapper.readValue(stuFullStr, StudentTestForJsonIgnoreProperties.class);
System.out.println(stu2.toString());


打印反序列化结果:

StudentTestForJsonIgnoreProperties(id=null, name=亚瑟, age=null)


1.3 @JsonIgnoreType
当其他类有该类作为属性时,该属性将被忽略。
举例:关于Student的类,添加了englishName属性。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentTestForJsonIgnoreType {

    private String id;

    private String name;

    private EnglishName englishName;

    private Integer age;
}


EnglishName 类定义如下,用@JsonIgnoreType修饰

@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreType
public class EnglishName {
    public String firstName;
    public String lastName;
}


序列化:

StudentTestForJsonIgnoreType stu = new StudentTestForJsonIgnoreType("1", "亚瑟", new EnglishName("Ya", "SE"), 30);
String stuStr = mapper.writeValueAsString(stu);
System.out.println(stuStr);


打印序列化结果: 忽略了englishName属性

{"id":"1","name":"亚瑟","age":30}


反序列化:

String stuFullStr = "{\"id\":\"1\",\"name\":\"亚瑟\",\"age\":30, \"englishName\":{\"firstName\":\"Ya\",\"lastName\":\"SE\"}}";
StudentTestForJsonIgnoreType stu2 = mapper.readValue(stuFullStr, StudentTestForJsonIgnoreType.class);
System.out.println(stu2.toString());



打印反序列化结果:

StudentTestForJsonIgnoreType(id=1, name=亚瑟, englishName=null, age=30)


1.4 @JsonProperty
如果JSON中字段名和Java类中的属性名不一致时,可以用@JsonProperty修饰在属性上。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentTestForJsonProperty {

    private String id;

    @JsonProperty("studentName")
    private String name;

    private Integer age;
}


序列化:

StudentTestForJsonProperty stu = new StudentTestForJsonProperty("1", "亚瑟", 30);
String stuStr = mapper.writeValueAsString(stu);
System.out.println(stuStr);



打印序列化结果: studentName代替了name

{"id":"1","age":30,"studentName":"亚瑟"}


反序列化:

String stuFullStr = "{\"id\":\"1\",\"studentName\":\"亚瑟\",\"age\":30}";
StudentTestForJsonProperty stu2 = mapper.readValue(stuFullStr, StudentTestForJsonProperty.class);
System.out.println(stu2.toString());


打印反序列化结果: studentName的值赋值给了name属性

StudentTestForJsonProperty(id=1, name=亚瑟, age=30)


1.5 @JsonAnyGetter和@JsonAnySetter
@JsonAnyGetter
1.方法是非静态,没有参数的,方法名随意
2.方法返回值必须是Map类型
3.在一个实体类中仅仅用在一个方法上
4.序列化的时候json字段的key就是返回Map的key,value就是Map的value

@JsonAnySetter
1.用在非静态方法上,注解的方法必须有两个参数,第一个是json字段中的key,第二个是value,方法名随意
2.也可以用在Map对象属性上面,建议用在Map对象属性上面
3.反序列化的时候将对应不上的字段全部放到Map里面

1.5.1 非嵌套的otherAttributes

@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentTestForJsonGetSet {

    private String id;

    private String name;

    private Integer age;

    private Map<String, Object> otherAttributes = new HashMap<>();

    @JsonAnyGetter
    public Map<String, Object> getOtherAttributes() {
        return this.otherAttributes;
    }

    @JsonAnySetter
    public void setOtherAttributes(String name, Object value) {
        this.otherAttributes.put(name, value);
    }
}
public static void main(String[] args) throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();
    Map<String, Object> otherAttributes = new HashMap<>();
    otherAttributes.put("what", "1");
    StudentTestForJsonGetSet stu = new StudentTestForJsonGetSet("1", "亚瑟", 30, otherAttributes);
    //序列化
    String stuStr = mapper.writeValueAsString(stu);
    System.out.println(stuStr);
    //反序列化
    String stuFullStr = "{\"id\":\"1\",\"studentName\":\"亚瑟\",\"age\":30,\"what\":\"1\"}";
    StudentTestForJsonGetSet stu2 = mapper.readValue(stuFullStr, StudentTestForJsonGetSet.class);
    System.out.println(stu2.toString());
}

{"id":"1","name":"亚瑟","age":30,"what":"1"}
StudentTestForJsonGetSet(id=1, name=null, age=30, otherAttributes={what=1, studentName=亚瑟})



1.5.2 嵌套的otherAttributes
如果otherAttributes接收嵌套的JSON结构,则Map的Value是LinkedHashMap类型。

先准备数据

ObjectMapper mapper = new ObjectMapper();

Map<String, StudentTestForJsonGetSet> level2 = new HashMap<>();
StudentTestForJsonGetSet studentTestForJsonGetSet = new StudentTestForJsonGetSet();
studentTestForJsonGetSet.setId("1-1");
studentTestForJsonGetSet.setName("name-1-1");
studentTestForJsonGetSet.setAge(11);
level2.put("Key-1-1", studentTestForJsonGetSet);

Map<String, Object> level1 = new HashMap<>();
level1.put("Key-1", level2);

StudentTestForJsonGetSet stu = new StudentTestForJsonGetSet("1", "亚瑟", 30, level1);



序列化:

String stuStr = mapper.writeValueAsString(stu);
System.out.println(stuStr);

{"id":"1","name":"亚瑟","age":30,"Key-1":{"Key-1-1":{"id":"1-1","name":"name-1-1","age":11}}}


反序列化:

String stuFullStr = "{\"id\":\"1\",\"name\":\"亚瑟\",\"age\":30,\"Key-1\":{\"Key-1-1\":{\"id\":\"1-1\",\"name\":\"name-1-1\",\"age\":11}}}";
StudentTestForJsonGetSet stu2 = mapper.readValue(stuFullStr, StudentTestForJsonGetSet.class);
System.out.println(stu2.toString());


2. 仅序列化时生效注解
2.1 @JsonFormat
在序列化日期/时间值时指定格式。
下面@JsonFormat注解指定时间序列化后的格式。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class StudentTestForJsonFormat {

    private String id;

    private String name;

    private Integer age;

    //默认情况下,Date序列化为自1970年1月1日以来的毫秒数(long类型)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date time;
}



序列化:

StudentTestForJsonFormat stu = new StudentTestForJsonFormat("1", "亚瑟", 30, new Date());
String stuStr = mapper.writeValueAsString(stu);
System.out.println(stuStr);



打印序列化结果:

{"id":"1","name":"亚瑟","age":30,"time":"2022-03-28 17:21:26"}


反序列化:

String stuFullStr = "{\"id\":\"1\",\"name\":\"亚瑟\",\"age\":30,\"time\":\"2022-03-07 18:39:12\"}";
StudentTestForJsonFormat stu2 = mapper.readValue(stuFullStr, StudentTestForJsonFormat.class);
System.out.println(stu2.toString());


打印反序列化结果:

StudentTestForJsonFormat(id=1, name=亚瑟, age=30, time=Mon Mar 07 18:39:12 CST 2022)



2.2 @JsonInclude
@JsonInclude是非常重要的且常用的注解,它可以修饰在类名上或者属性上,但是一般为了更加细粒度的控制,都修饰在属性上。

类型    说明

  1. ALWAYS    这个是默认值,无论属性值是否为空,都参加序列化
  2. NON_NULL    属性值不是NULL,才参加序列化
  3. NON_ABSENT    NON_NULL的增强版,Optional类型不是null,且isPresent()为true,才参加序列化。 实际开发中并不建议在实体类定义Optional类型的属性,如果你非要用,一定要赋默认值,比如Optional.empty()。
  4. NON_EMPTY    属性值不是NULL,也不是"",如果是集合则isEmpty() = false,才参加序列化
  5. NON_DEFAULT    属性值为缺省值时不序列化,比如int类型=0,String类型=null,这样不参加序列化。 实际开发中不要在实体类中用基础类型(如int,float),要用Integer代替int,具体原因参考阿里巴巴Java开发手册。
  6. CUSTOM    结合注解JsonInclude.valueFilter和JsonInclude.contentFilter使用,这两个注解会指定一个Class,然后默认调用这个Class的空参构造方法,返回的对象eques属性值的话,序列化时就忽略。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值