SpringBoot JSON序列化自定义对象研究

  • 1. 问题描述
    • 1.1 工程代码
    • 1.2 测试
  • 2. 问题分析
    • 2.1 初步分析结论
    • 2.2 实验验证结论
    • 2.3 问题拓展
  • 3. 结论

摘要(干货):在使用SpringBoot中通过RestController返回自定义对象时,虽然SpringBoot会将自定义的类自动转换为JSON对象并返回给客户端。在转换过程中,Spring Boot会调用自定义类中所有的getXXX方法(XXX为任意名字),如果该方法返回值不为void,那么XXX将作为该自定义的类成员返回给客户端,而该类成员的值即为getXXX方法的返回值。如果类中未出现满足条件的方法,将会抛异常。

最近在工作中需要用到Kubernetes官方提供的client-Java来操作Kubetnetes集群。但是写bug的过程,遇到了Spring Boot巨大的坑(也可能是自己太菜了。。),自己在解决过程中,逐渐总结了一个知识点,同时也是易犯的点,特此记录并分享。

1. 问题描述

1.1 工程代码

首先看一下我demo工程的部分代码(为了能够说明问题,我自己搭建了一个简单的SpringBoot工程)。
代码中涉及到几个类主要有;

  1. ReturnVO — 自定义的通用返回类,主要用于返回数据
  2. TestController — 自定义的Rest Controller,主要用于处理请求。
  3. MyData — 自定义的数据类,会序列化为JSON对象,并返回给客户端。

  • 首先我在pom文件中引入了几个常见的依赖(都是些常规依赖,可忽略)
    <dependencies>
<!--        引入SpringBoot web-starter的依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.6.4</version></dependency>
<!--        引入lombok工具--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.22</version></dependency></dependencies>
  • 代码中编写了自定义的一个返回类(ReturnVO),代码如下:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@AllArgsConstructor
@NoArgsConstructor
@Data
public class ReturnVO {private int code;   // 返回码private String message; // 返回的messageprivate Object data;  // 返回的数据
}
  • 代码中中的自定义类代码如下(MyData):
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MyData {// 该类中有2个成员变量分别为 name, addressprivate String name;private String address;public String getdemo(){return "hello world";}
}
  • 代码中的Controller类(TestController)如下
@RestController
public class TestController {@PostMapping("/test")public ReturnVO test(){ReturnVO result = new ReturnVO();MyData data = new MyData();result.setCode(200);result.setMessage("success");result.setData(data);return result;}
}

1.2 测试

将Spring Boot代码运行,我们使用postman发送POST请求对代码进行测试。我们可以看到如下返回值:

{"code": 200,"message": "success","data": {"name": null,"address": null,"demo": "hello world"}
}

可以看到,服务端返回值中增加了一个名字为demo的属性,但是我们的MyData类病没有该成员,是Spring Boot给我们自动加上了这个成员。

2. 问题分析

2.1 初步分析结论

出现了1.2中的情况,虽然没有看Spring boot的源代码,但是初步形成一下结论

  1. Spring Boot在将Java类转换为JSON对象时,是通过读取属性值的get方法来获取属性值的,如果未出现某个成员变量的get方法,那么该类成员将不会出现在JSON对象中。
  2. Spring Boot在将Java类转换为JSON对象时,会读取所有以getXXX命名的成员方法(前提是该方法名的返回值不能为void),并将XXX作为JSON的属性,方法的返回值作为该属性的属性值,处理完成后返回给请求端。

2.2 实验验证结论

首先,我们来验证2.1章节中的第一个结论。

在 1.1章节的代码中,我们在MyIntOrString这个类的代码中,我们用了lombok自带的@Data注解,这个注解相当于@Setter和@Getter,为我们自动创建了类成员的set和get方法,为了验证我们2.1章节中的第一个结论,我们改写一下MyData类的代码,修改后如下:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.Setter;@Setter   // 将@Data注解替换为@Setter注解
@NoArgsConstructor
@AllArgsConstructor
public class MyData {private String name;private String address;public String getname(){ // name属性的get方法return "hello world";}
}

其他代码不用更改,我们重新运行代码,并对TestController进行测试,可以看到服务端返回如下信息:

{"code": 200,"message": "success","data": {"name": "hello world"}
}

通过上面的返回值我们可以看到,虽然address是My Data类的成员变量,但是因为类中没有定义它的get方法,因此在最终的返回结果中,并未出现该成员。印证了2.1中的结论。


接着,我们来验证2.1章节中的第2个结论

在 1.1章节的代码中,我们在MyIntOrString这个类的代码中,我们用了lombok自带的@Data注解,这个注解相当于@Setter和@Getter,为我们自动创建了类成员的set和get方法,为了验证我们2.1章节中的第一个结论,我们改写一下MyData类的代码,修改后如下:

@Setter
@NoArgsConstructor
@AllArgsConstructor
public class MyData {private String name;private String address;public String getdemo(){return "hello world";}public String getname(){return "user";}public int gettime(){return 2022;}public void getAge(){}
}

上面的代码中,我们增加个getdemo方法,gettime方法,getAge方法。其中getAge方法的返回值为空。工程中其他代码不变,我们重新运行代码,并对TestController进行测试。可以得到如下的返回结果:

{"code": 200,"message": "success","data": {"name": "user","demo": "hello world","time": 2022}
}

通过上面的返回值我们可以看到,MyData类中所有getXXX命名的方法会被读取,但是由于getAge方法返回值为空,并没有出现在返回的JSON对象中。印证了2.1中的结论。

2.3 问题拓展

我们将这个问题的结论继续拓展:假设该类中没有get方法,那么程序的运行结果会是怎样的呢? ,为了验证这个结论,我们将MyData类进行继续进行改造,改造后的代码如下:

@Setter
@NoArgsConstructor
@AllArgsConstructor
public class MyData {private String name;private String address;
}

重新运行代码,并对TestController进行测试,得出下面的结果:

{"timestamp": "2022-03-27T08:43:05.115+00:00","status": 500,"error": "Internal Server Error","path": "/test"
}

我们可以看到程序直接出错,查看程序输出的异常信息显示:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.sodalife.blog.eneity.MyData and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.sodalife.blog.eneity.ReturnVO["data"])at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) ~[jackson-databind-2.13.1.jar:2.13.1]at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1300) ~[jackson-databind-2.13.1.jar:2.13.1]at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:400) ~[jackson-databind-2.13.1.jar:2.13.1]at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:46) ~[jackson-databind-2.13.1.jar:2.13.1]at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:29) ~[jackson-databind-2.13.1.jar:2.13.1]at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.13.1.jar:2.13.1]

上述的错误提示告诉我们,没有用来创建BeanSerializer的serializer,进而我们可以推断,get方法是必须存在的,否则程序将会出现异常。

3. 结论

通过问题的描述与分析,我们可以初步形成一下结论:

在使用SpringBoot中返回自定义对象时,虽然SpringBoot会将自定义的类自动转换为JSON对象并返回给客户端。在转换过程中,Spring Boot会调用自定义类中所有的getXXX方法(XXX为任意名字),如果该方法返回值不为void,那么XXX将作为该自定义的类成员返回给客户端,而该类成员的值即为getXXX方法的返回值。如果类中未出现满足任何满足条件的get方法,将会抛出异常。

SpringBoot将自定义对象转JSON对象问题研究相关推荐

  1. jsp 将java对象转json对象 (自定义EL函数)

    功能:在 jsp 页面将 java对象 转换为 json对象 (使用自定义EL函数实现) 步骤: 1. 创建 JSP EL 工具类 2. 创建 tld 文件 3. 配置 web.xml 文件 4. 完 ...

  2. js中自定义对象、json对象、json字符串、普通js对象 --js学习那本书上的

    4.7 自定义对象 JS除了内置对象之外,还允许我们程序自己定义属于我们自己的对象,在JS中自定义对象的方式有2种:通过构造器创建对象,通过初始化器创建对象. 4.7.1 构造器创建对象(原生JS对象 ...

  3. js中自定义对象、json对象、json字符串、普通js对象

    4.7 自定义对象 JS除了内置对象之外,还允许我们程序自己定义属于我们自己的对象,在JS中自定义对象的方式有2种:通过构造器创建对象,通过初始化器创建对象. 4.7.1 构造器创建对象(原生JS对象 ...

  4. JavaScript对象、JSON对象、JSON字符串的区别

    一.首先看下什么是JSON JSON:JavaScript Object Natation,JavaScript对象的表现形式,已经发展成一种轻量级的数据交换格式. JavaScript对象的表现形式 ...

  5. java 视图对象转换,使用spring boot开发时java对象和Json对象转换的问题_JavaScript_网络编程...

    将java对象转换为on对象,市面上有很多第三方jar包,如下: jackson(最常用) com.fasterxml.jackson.core jackson-databind 2.11.2 gso ...

  6. json字符串转换成json对象,json对象转换成字符串,值转换成字符串,字符串转成值...

    json字符串转换成json对象,json对象转换成字符串,值转换成字符串,字符串转成值 原文:json字符串转换成json对象,json对象转换成字符串,值转换成字符串,字符串转成值 主要内容: 一 ...

  7. Java对象转换为Json对象

    前言 曾几何时,XML是程序员的宠儿,是数据传输.API.AJAX应用等方面的不二选择,但自从JSON横空出世后,或者你会发觉你身边就有很多人开始抛弃XML,在他们的心目中,JSON已经完全取代了XM ...

  8. java对象和json对象之间互相转换

    2019独角兽企业重金招聘Python工程师标准>>> import java.util.ArrayList; import java.util.Collection; import ...

  9. jquery:字符串转json对象,json对象转字符串

    jquery:字符串转json对象,json对象转字符串 JSON字符串: var str = '{ "name": "cxh", "sex" ...

  10. java对象与json对象间的相互转换的方法

    String json=JSON.toJSONString(user);//关键 1.简单的解析json字符串 首先将json字符串转换为json对象,然后再解析json对象,过程如下. 1 JSON ...

最新文章

  1. SOLID面向对象模式浅析
  2. 按键的c语言代码表,各种按键模式的扫描
  3. 复习java基础第二天(异常处理)
  4. python3.82版本安装_CentOS7下安装Python3和Python2并存
  5. C++ 类里面,函数占用存储空间问题
  6. c#控制台应用程序,如何实现隐藏DOS窗口
  7. 特征工程的宝典-《Feature Engineering for Machine Learning》翻译及代码实现
  8. c++11-template template Parameter
  9. 对qps、tps、pv、uv的理解
  10. Jmeter BeanShell采样器提取接口响应并传递(三)
  11. 基于T4模板的文档生成
  12. android消息提示方法自定义,Android自定义消息提示容器
  13. 国内外php主流开源cms汇总
  14. vmware安装win10并使用xshell成功连接及虚拟机中win10设置静态ip
  15. 「python爬虫之路day9」:实战之使用正则表达式爬取抓狂网,古诗文网信息
  16. 代码解读四 文件名“Ano_AttCtrl.c”
  17. zookeeper和kafka的SASL认证以及生产实践
  18. 在线 - 支持word上传的富文本编辑器
  19. 多文件在线压缩并下载
  20. Speedoffice(PPT)如何设置幻灯片大小

热门文章

  1. linux解锁root
  2. Invalid default: public abstract java.lang.Class org.mybatis.spring.annotation.MapperScan.factoryBe
  3. 10X单细胞空间联合分析之SPOTlight进阶版
  4. 6种java垃圾回收算法_Java垃圾回收算法
  5. 编程命名规则:驼峰命名法和匈牙利命名法
  6. “简单”和“勤奋”就是只围绕团队的理念和目标去工作,而不会因为其他的问题或内耗来分散团队的力量和注意力。为此,管理者要为团队创造一个积极向上、团队合作、充满激情的工作氛围。...
  7. 关于MongoDB连接字符串URI格式
  8. 2021年全球无线宽带收入大约5631.4百万美元,预计2028年达到11770百万美元,2022至2028期间,年复合增长率CAGR为12.0%
  9. createcompatibledc(createcompatibledc 刷新不闪屏)
  10. 基于web的圆通快递物流管理系统