虽然是出问题了,但是序列化并没有转为属性为null的对象,而是直接抛出异常
Exception in thread “main” com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class online.jvm.bean.User and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
复制代码
通过查询异常资料,解决掉这种异常需要在增加Jackson的序列化配置FAIL\_ON\_EMPTY\_BEANS,FAIL\_ON\_EMPTY\_BEANS这个配置表示如果某个bean序列化为空时不会异常失败
public static void main(String[] args) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(FAIL_ON_EMPTY_BEANS, false);
String request = objectMapper.writeValueAsString(new User("niu", 18));
System.out.println(request);
}
复制代码
这种就不会报错,而是返回序列化成空串,也就导致接受方为属性都为null
通过看自研RPC框架看到是有该FAIL\_ON\_EMPTY\_BEANS的配置
解决
--
再来分析一下原因,Jackson序列化时需要调用bean的getter方法
### 1、写上getter后再看下结果:
public class User {
private String name;
private Integer age;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public static void main(String[] args) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
String request = objectMapper.writeValueAsString(new User("niu", 18));
System.out.println(request);
// 输出正常 : {"name":"niu","age":18}
}
}
复制代码
### 2、或者把属性访问权限改为public
public class User {
public String name;
public Integer age;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
String request = objectMapper.writeValueAsString(new User("niu", 18));
System.out.println(request);
// 输出正常 : {"name":"niu","age":18}
}
}
复制代码
但是如果要求**不能暴露bean的属性**即使是getter也不行呢?
### 3、注解 `@JsonProperty`
这是就需要使用Jackson提供的注解 `@JsonProperty`
public class User {
@JsonProperty("userName")
private String name;
@JsonProperty
private Integer age;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
String request = objectMapper.writeValueAsString(new User("niu", 18));
System.out.println(request);
// {"userName":"niu","age":18}
}
}
复制代码
来看下注解`@JsonProperty`的源码注释
Marker annotation that can be used to define a non-static method as a “setter” or “getter” for a logical property (depending on its signature), or non-static object field to be used (serialized, deserialized) as a logical property.
复制代码
大体意思是注解如果**用在属性上**相当于为该属性**定义getter和setter**。
那如果既有getter又有`@JsonProperty`注解,以哪个为准呢?
public class User {
@JsonProperty("userName")
private String name;
@JsonProperty
private Integer age;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public static void main(String[] args) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
String request = objectMapper.writeValueAsString(new User("niu", 18));
System.out.println(request);
// {"age":18,"userName":"niu"}
}
}
复制代码
如果getter一个没有的属性,效果如何呢?
public class User {
@JsonProperty("userName")
private String name;
@JsonProperty
private Integer age;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName2() {
return name;
}
public static void main(String[] args) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
String request = objectMapper.writeValueAsString(new User("niu", 18));
System.out.println(request);
// {"age":18,"name2":"niu","userName":"niu"}
}
}
复制代码
**这说明如果有`@JsonProperty`注解,先以注解为准**
然后**利用反射找到对象类的所有get方法**,接下来去get,然后小写化,作为json的每个key值,而get方法的返回值作为value。接下来**再反射field**,添加到json中。
### 4、特殊情况
还有一种比较特殊的情况, getter方法由lombok生成,且属性的次首字母是大写:
@Getter
public class User {
@JsonProperty
private String nAme;
@JsonProperty
private Integer age;
public User(String name, Integer age) {
this.nAme = name;
this.age = age;
}
public static void main(String[] args) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
String request = objectMapper.writeValueAsString(new User("niu", 18));
System.out.println(request);
// {"nAme":"niu","age":18,"name":"niu"}
}
}
最后
面试是跳槽涨薪最直接有效的方式,马上金九银十来了,各位做好面试造飞机,工作拧螺丝的准备了吗?
掌握了这些知识点,面试时在候选人中又可以夺目不少,暴击9999点。机会都是留给有准备的人,只有充足的准备,才可能让自己可以在候选人中脱颖而出。
如果你需要这份完整版的面试笔记,只需你多多支持我这篇文章。
——对文章进行点赞+评论,关注我,然后再点击这里免费领取
User(“niu”, 18));
System.out.println(request);
// {"nAme":"niu","age":18,"name":"niu"}
}
}
最后
面试是跳槽涨薪最直接有效的方式,马上金九银十来了,各位做好面试造飞机,工作拧螺丝的准备了吗?
掌握了这些知识点,面试时在候选人中又可以夺目不少,暴击9999点。机会都是留给有准备的人,只有充足的准备,才可能让自己可以在候选人中脱颖而出。
如果你需要这份完整版的面试笔记,只需你多多支持我这篇文章。
——对文章进行点赞+评论,关注我,然后再点击这里免费领取
[外链图片转存中…(img-4bgv0xJZ-1628129948556)]