在Java项目中使用Jackson处理对象序列化时,POJO中未赋值的null字段默认会被转换为JSON的null值输出,这会导致生成的JSON冗余,部分场景下还会不符合下游系统的解析要求。我们可以通过多种方式实现null字段的排除。

通过@JsonInclude注解实现字段级排除
@JsonInclude是Jackson提供的注解,可直接标注在POJO类或具体字段上,指定序列化时包含的规则。当设置值为JsonInclude.Include.NON_NULL时,就会排除值为null的字段。
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
// 标注在类上,对该类所有字段生效
@JsonInclude(JsonInclude.Include.NON_NULL)
class User {
private String name;
private Integer age;
private String email;
// 省略getter、setter方法
public User(String name, Integer age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
}
public class JacksonDemo {
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
// email字段为null,序列化时会被排除
User user = new User("张三", 20, null);
String json = objectMapper.writeValueAsString(user);
System.out.println(json); // 输出:{"name":"张三","age":20}
}
}
如果只需要排除某个特定字段,也可以把@JsonInclude注解直接加在该字段上,其他字段不受此规则影响。
配置全局ObjectMapper排除所有null字段
如果项目中所有POJO的序列化都需要排除null字段,逐个添加注解会比较繁琐,此时可以配置全局的ObjectMapper,统一设置序列化规则。
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
class User {
private String name;
private Integer age;
private String email;
// 省略getter、setter方法
public User(String name, Integer age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
}
public class JacksonDemo {
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
// 全局配置:序列化时排除null值
objectMapper.setSerializationInclusion(com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL);
// 可选配置:忽略未知属性,避免反序列化报错
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
User user = new User("李四", null, null);
String json = objectMapper.writeValueAsString(user);
System.out.println(json); // 输出:{"name":"李四"}
}
}
自定义序列化器实现更灵活的排除规则
如果默认的排除规则无法满足需求,比如需要排除空字符串或者特定默认值,我们可以自定义序列化器,重写序列化逻辑。
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.io.IOException;
// 自定义序列化器,排除null值的String类型字段
class CustomNullSerializer extends JsonSerializer<String> {
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
// 如果值为null,不写入该字段
if (value != null) {
gen.writeString(value);
}
}
}
class Product {
private String productName;
@JsonSerialize(using = CustomNullSerializer.class)
private String description;
private Double price;
// 省略getter、setter方法
public Product(String productName, String description, Double price) {
this.productName = productName;
this.description = description;
this.price = price;
}
}
public class JacksonDemo {
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
// description字段为null,会被自定义序列化器排除
Product product = new Product("手机", null, 2999.99);
String json = objectMapper.writeValueAsString(product);
System.out.println(json); // 输出:{"productName":"手机","price":2999.99}
}
}
不同方案的选择建议
如果只有少数几个POJO需要排除null字段,优先使用@JsonInclude注解,配置简单且针对性强。如果是全项目统一规则,全局配置ObjectMapper效率更高,减少重复代码。如果排除规则比较特殊,比如需要同时排除null和空字符串,自定义序列化器可以实现更灵活的逻辑。
需要注意的是,全局配置ObjectMapper时,如果项目中已经存在其他自定义的ObjectMapper实例,需要确保配置生效,避免不同实例的规则冲突。另外,@JsonInclude注解的优先级高于全局配置,如果某个类单独标注了注解,会以注解的规则为准。