如何在Java中设置Bean的某个字段不被JSON化
在Java开发中,将对象序列化为JSON字符串(如使用Jackson、Gson等库)是常见操作,但有时我们希望Bean中的某些字段不参与JSON序列化——可能是敏感信息(如密码、身份证号)、临时计算字段,或是仅用于后端逻辑的内部状态,本文将介绍几种主流JSON库中实现字段不JSON化的方法,涵盖注解配置、自定义逻辑及场景化选择。
核心方法:使用JSON库的注解(推荐)
大多数JSON库都提供了注解式配置,通过在字段或方法上添加特定注解,即可控制该字段是否参与序列化,以下是主流库的具体实现:
Jackson(Spring Boot默认JSON库)
Jackson提供了@JsonIgnore和@JsonIgnoreProperties两种注解来实现字段排除。
(1)@JsonIgnore:作用于字段/方法
直接在字段或其对应的getter/setter方法上添加@JsonIgnore,该字段会被完全忽略,不参与序列化和反序列化。
示例:
import com.fasterxml.jackson.annotation.JsonIgnore;
public class User {
private String username;
private String password; // 敏感信息,不希望被JSON化
@JsonIgnore
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
// getter/setter for username...
}
序列化结果:
{
"username": "zhangsan"
}
`
`
#### (2)`@JsonIgnoreProperties`:作用于类
当需要忽略多个字段时,可在类上添加`@JsonIgnoreProperties`,通过`ignoreFields`属性指定要忽略的字段名(支持正则表达式)。
**示例:**
```java
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties({"password", "tempToken"})
public class User {
private String username;
private String password;
private String tempToken; // 临时token,不参与序列化
// getter/setter...
}
序列化结果同样会排除password和tempToken。
Gson(Google JSON库)
Gson通过@Expose注解控制字段可见性,默认情况下所有字段都会参与序列化,只有添加@Expose的字段才会被处理,若要排除特定字段,可通过@Expose的serialize和deserialize属性,或使用transient关键字。
(1)@Expose:选择性暴露字段
在类上添加@Expose注解(需配合GsonBuilder使用),并通过serialize = false禁用序列化。
示例:
import com.google.gson.annotations.Expose;
public class User {
@Expose(serialize = false) // 序列化时忽略
private String password;
@Expose // 默认序列化和反序列化都参与
private String username;
// getter/setter...
}
使用GsonBuilder构建Gson实例:
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
User user = new User("zhangsan", "123456");
String json = gson.toJson(user); // 输出: {"username":"zhangsan"}
(2)transient关键字:基于JVM机制
通过transient修饰的字段,JVM会忽略其序列化机制(Gson、Jackson等均支持),但注意:transient仅对基于JVM的序列化(如ObjectOutputStream)生效,JSON库是额外实现的,需确保库支持对transient字段的忽略。
示例:
public class User {
private String username;
private transient String password; // transient修饰的字段会被忽略
// getter/setter...
}
使用Gson或Jackson序列化时,password字段会被自动排除。
Fastjson(阿里巴巴JSON库)
Fastjson通过@JSONField注解的serialize属性控制字段是否序列化。
示例:
import com.alibaba.fastjson.annotation.JSONField;
public class User {
private String username;
@JSONField(serialize = false) // 序列化时忽略
private String password;
// getter/setter...
}
序列化结果:
{
"username": "zhangsan"
}
进阶方案:自定义序列化逻辑
当注解无法满足复杂需求(如动态判断字段是否序列化)时,可通过自定义序列化器实现。
Jackson自定义序列化器
继承StdSerializer类,重写serialize方法,在方法中决定是否写入字段。
示例:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.io.IOException;
public class User {
private String username;
private String password;
@JsonSerialize(using = PasswordSerializer.class) // 指定自定义序列化器
public String getPassword() {
return password;
}
// getter/setter...
}
// 自定义密码序列化器
class PasswordSerializer extends JsonSerializer<String> {
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException {
// 不写入字段,实现忽略
gen.writeFieldName("password"); // 可选:写入字段名但值为null
gen.writeNull();
}
}
序列化结果:
{
"username": "zhangsan",
"password": null
}
若需完全忽略字段,可在serialize方法中不调用gen.writeFieldName和gen.writeObject。
Gson自定义类型适配器
实现JsonSerializer接口,在serialize方法中控制输出。
示例:
import com.google.gson.*;
import java.lang.reflect.Type;
public class User {
private String username;
private String password;
// getter/setter...
}
// 自定义User序列化器
class UserSerializer implements JsonSerializer<User> {
@Override
public JsonElement serialize(User user, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("username", user.getUsername());
// 不添加password字段,实现忽略
return jsonObject;
}
}
使用方式:
Gson gson = new GsonBuilder().registerTypeAdapter(User.class, new UserSerializer()).create();
User user = new User("zhangsan", "123456");
String json = gson.toJson(user); // 输出: {"username":"zhangsan"}
场景化选择:如何确定使用哪种方法?
| 场景 | 推荐方法 | 优点 | 注意事项 |
|---|---|---|---|
| 简单字段排除(固定字段) | 注解(@JsonIgnore、@Expose、@JSONField) |
配置简洁,代码侵入性低 | 确保JSON库支持对应注解 |
| 多字段批量排除 | 类级别注解(@JsonIgnoreProperties) |
集中管理,避免重复注解 | 字段名需准确,拼写错误会导致忽略失效 |
| 动态控制字段序列化(如根据权限) | 自定义序列化器 | 灵活性高,可运行时判断 | 代码量稍大,需处理序列化逻辑 |
| 基于JVM通用序列化兼容 | transient关键字 |
无需依赖JSON库,对多库通用 | 仅对支持transient的JSON库有效 |
注意事项
- 注解生效条件:使用注解时,需确保JSON库的依赖和配置正确(如Jackson需启用
default-property-inclusion,Gson需用GsonBuilder配置@Expose)。 - 反序列化一致性:若字段被排除序列化,反序列化时也应避免依赖该字段(或通过
@JsonIgnore同时控制反序列化),否则可能导致数据不一致。 - 敏感信息保护:除排除字段外,敏感数据还应加密存储,避免仅依赖JSON序列化机制。
在Java Bean中设置字段不被JSON化,核心思路是“通过配置或代码逻辑控制序列化行为”,对于固定字段的排除,注解式配置(如Jackson的@JsonIgnore、Gson的@Expose)是最简洁的方式;对于动态或复杂场景,自定义序列化器能提供更灵活的控制,根据项目使用的JSON库和具体需求选择合适的方法,即可高效实现字段过滤。



还没有评论,来说两句吧...