GsonBuilder排除策略在A类toString调用时未生效问题咨询
问题原因
你遇到的情况本质是Gson序列化对象的逻辑和toString方法的触发时机完全无关:
- 调用A的
toString时,你用的是默认Gson实例序列化整个A对象,Gson会直接通过反射遍历A的字段(包括b对应的B实例),读取B的所有字段值生成JSON——这个过程根本不会调用B类自己的toString方法,自然也就不会用到B里定义的排除策略。 - 只有当你直接调用
b.toString()时,才会触发B里带排除策略的Gson实例,这时候才会跳过d字段。
全局生效的解决方案
因为你要让B的d字段在所有序列化场景都被排除,且不想用transient,可以用以下几种方式:
1. 全局共享带排除策略的Gson实例
创建一个全局Gson实例,把B的排除策略注册进去,所有需要序列化的地方(包括A和其他使用B的类的toString)都用这个实例:
// 放在公共工具类中的全局Gson实例 public class GsonUtils { public static final Gson GSON_INSTANCE = new GsonBuilder() .setExclusionStrategies(new BExclusionStrategy()) .create(); static class BExclusionStrategy implements ExclusionStrategy { @Override public boolean shouldSkipClass(Class<?> arg0) { return false; } @Override public boolean shouldSkipField(FieldAttributes attr) { return attr.getName().equals("d") && attr.getDeclaringClass() == B.class; } } }
然后修改A和B的toString方法:
// A类的toString @Override public String toString() { return GsonUtils.GSON_INSTANCE.toJson(this); } // B类的toString也改用全局实例,确保所有场景一致 @Override public String toString() { return GsonUtils.GSON_INSTANCE.toJson(this); }
2. 使用@Expose注解配合Gson配置
如果想用注解方式,需要注意两个关键点:
- 给B类中需要保留的字段加上
@Expose注解,不需要的(比如d)不加; - 全局Gson实例必须配置
excludeFieldsWithoutExposeAnnotation(),这样Gson只会序列化带@Expose的字段。
// 修改B类 public class B implements Serializable { @Expose int c; byte[] d; // 不加@Expose,会被自动排除 // 其他代码... } // 全局Gson实例 public class GsonUtils { public static final Gson GSON_INSTANCE = new GsonBuilder() .excludeFieldsWithoutExposeAnnotation() .create(); }
你之前尝试这个方法无效,大概率是因为没给需要保留的字段(比如c)加@Expose,或者使用的是默认Gson实例(默认不识别该配置)。
3. 自定义TypeAdapter处理B类
给B类写一个自定义TypeAdapter,手动控制序列化时的字段输出,灵活性最高:
public class BTypeAdapter extends TypeAdapter<B> { @Override public void write(JsonWriter out, B value) throws IOException { out.beginObject(); out.name("c").value(value.c); // 不写入d字段 out.endObject(); } @Override public B read(JsonReader in) throws IOException { // 反序列化逻辑按需实现,这里示例跳过d字段 B b = new B(); in.beginObject(); while (in.hasNext()) { switch (in.nextName()) { case "c": b.c = in.nextInt(); break; case "d": in.nextString(); // 跳过d字段的反序列化 break; } } in.endObject(); return b; } }
注册到全局Gson实例:
public class GsonUtils { public static final Gson GSON_INSTANCE = new GsonBuilder() .registerTypeAdapter(B.class, new BTypeAdapter()) .create(); }
内容的提问来源于stack exchange,提问作者iuhztr tzhjzuk
相关产品推荐
相关产品推荐

