Java 传递基类类型的引用时,JSON仅序列化基类字段

Java 传递基类类型的引用时,JSON仅序列化基类字段,java,json,gson,Java,Json,Gson,我正在使用图书馆。当给Gson的对象是基类类型时,要求Gson仅序列化基类字段的干净/惯用方法是什么?请注意,这与类似问题(例如)不同,类似问题询问如何始终排除特定字段。在我的用例中,我只希望在通过基类类型化引用向Gson库传递派生类对象时排除继承的类字段。否则,也就是说,如果Gson库通过派生类类型的引用传递了派生类对象,那么我希望字段出现在序列化中 如下: import com.google.gson.Gson; import com.google.gson.GsonBuilder; cl

我正在使用图书馆。当给Gson的对象是基类类型时,要求Gson仅序列化基类字段的干净/惯用方法是什么?请注意,这与类似问题(例如)不同,类似问题询问如何始终排除特定字段。在我的用例中,我只希望在通过基类类型化引用向Gson库传递派生类对象时排除继承的类字段。否则,也就是说,如果Gson库通过派生类类型的引用传递了派生类对象,那么我希望字段出现在序列化中

如下:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

class A {
    public int a;
    public A(final int a) {
        this.a = a;
    }
}

class B extends A {
    public int b;

    public B(final int a, final int b) {
        super(a);
        this.b = b;
    }

}

public class Main {

    public static void main(String args[]) {

        final A a = new B(42, 142);
        final Gson gson = new GsonBuilder().serializeNulls().create();

        System.out.printf("%s\n", gson.toJson(a));
    }
}
上述印刷品:

{"t":{"b":142,"a":42}}
{“b”:142,“a”:42}

我正在寻找一种干净的方式使其打印:

{“a”:42}

但是,如果使用以下代码:

final B b = new B(42, 142);
。。。然后我希望
gson.toJson(b)
确实返回:

{“b”:142,“a”:42}

有没有一个干净的方法来实现这一点

更新 建议使用
toJson(o,A.class)
,这在本例中确实有效。然而,这种方法似乎不能很好地扩展到泛型。例如:

class A {
    public int a;
    public A(final int a) {
        this.a = a;
    }
}

class B extends A {
    public int b;

    public B(final int a, final int b) {
        super(a);
        this.b = b;
    }
}

class Holder<T> {
    public final T t;

    public Holder(final T t) {
        this.t = t;
    }
}

final A a = new B(42, 142);
final Holder<A> holder = new Holder<A>(a);
final Gson gson = new GsonBuilder().serializeNulls().create();

final Type TYPE= new TypeToken<Holder<A>>() {}.getType();
System.out.printf("%s\n", gson.toJson(holder, TYPE));

Gson用户手册中似乎没有直接的配置。但有一点值得一试:

您可以使用Gson序列化程序来使用动态。在这里,“动态”策略意味着每次您需要序列化一个类
Foo
,您都需要一个配置了
OnlyFieldsFor
startegy的Gson实例

是一个接口,指定了两种方法:

  • shouldSkipClass()
    -使用此选项筛选出不需要的类

  • shouldSkipField()
    -这很有用。它被调用,其中包含有关在其中声明字段的类的信息。如果未在基类中声明字段,则返回false


  • Gson用户手册中似乎没有直接的配置。但有一点值得一试:

    您可以使用Gson序列化程序来使用动态。在这里,“动态”策略意味着每次您需要序列化一个类
    Foo
    ,您都需要一个配置了
    OnlyFieldsFor
    startegy的Gson实例

    是一个接口,指定了两种方法:

  • shouldSkipClass()
    -使用此选项筛选出不需要的类

  • shouldSkipField()
    -这很有用。它被调用,其中包含有关在其中声明字段的类的信息。如果未在基类中声明字段,则返回false

  • 有没有一个干净的方法来实现这一点

    您不需要排除策略,尽管它们足够灵活,可以覆盖这样的场景。数据包类的序列化和反序列化由中的
    TypeAdapter
    实现驱动。这种类型的适配器需要考虑

    话虽如此,您唯一需要的是从中获取字段的最具体类型:

    final Object o=newb(42142);
    System.out.println(gson.toJson(o,A.class));
    
    它对您不起作用的原因是您的代码指定了最具体的类,就像您对上面的代码使用
    gson.toJson(o,o.getClass())
    gson.toJson(o,B.class)
    一样

    泛型类型问题 对于这种情况,
    ReflectTypeAdapterFactory
    恐怕无法将类型参数考虑在内。 不确定
    getRuntimeTypeIfMoreSpecific
    方法到底做了什么,以及它的原始用途是什么,但它将
    A
    类型“转换”为具体的
    B
    类型,因为类的
    type instanceof Class
    检查允许使用
    type=value.getClass()来检查字段类型。
    看起来您必须为这种情况实施一种变通方法:

    .registerTypeAdapterFactory(新的TypeAdapterFactory(){
    @凌驾
    公共类型适配器创建(Gson Gson、TypeToken TypeToken){
    最终类>类型适配器=新类型适配器读取(中的最终JsonReader)
    抛出IOException{
    对象t=null;
    in.beginObject();
    while(在.hasNext()中){
    最终字符串名称=in.nextName();
    交换机(名称){
    案例“t”:
    t=valueTypeAdapter.read(输入);
    打破
    违约:
    //什么也不做;
    打破
    }
    }
    in.endObject();
    归还新持有人(t);
    }
    }.nullSafe();
    @抑制警告(“未选中”)
    最终类型适配器castTypeAdapter=(TypeAdapter)TypeAdapter;
    返回类型适配器;
    }
    })
    
    不幸的是,在您的
    Gson
    实例中使用此类型适配器会使
    @SerializedName
    @JsonAdapter
    和其他很酷的东西不可用,并且会使它坚持硬编码字段名。 这可能是一个Gson错误

    有没有一个干净的方法来实现这一点

    您不需要排除策略,尽管它们足够灵活,可以覆盖这样的场景。数据包类的序列化和反序列化由中的
    TypeAdapter
    实现驱动。这种类型的适配器需要考虑

    话虽如此,您唯一需要的是从中获取字段的最具体类型:

    final Object o=newb(42142);
    System.out.println(gson.toJson(o,A.class));
    
    它对您不起作用的原因是您的代码指定了最具体的类,就像您对上面的代码使用
    gson.toJson(o,o.getClass())
    gson.toJson(o,B.class)
    一样

    泛型类型问题 很抱歉,
    ReflectTypeAdapterFactory
    无法将类型参数考虑到此类场景中