Java 传递基类类型的引用时,JSON仅序列化基类字段
我正在使用图书馆。当给Gson的对象是基类类型时,要求Gson仅序列化基类字段的干净/惯用方法是什么?请注意,这与类似问题(例如)不同,类似问题询问如何始终排除特定字段。在我的用例中,我只希望在通过基类类型化引用向Gson库传递派生类对象时排除继承的类字段。否则,也就是说,如果Gson库通过派生类类型的引用传递了派生类对象,那么我希望字段出现在序列化中 如下:Java 传递基类类型的引用时,JSON仅序列化基类字段,java,json,gson,Java,Json,Gson,我正在使用图书馆。当给Gson的对象是基类类型时,要求Gson仅序列化基类字段的干净/惯用方法是什么?请注意,这与类似问题(例如)不同,类似问题询问如何始终排除特定字段。在我的用例中,我只希望在通过基类类型化引用向Gson库传递派生类对象时排除继承的类字段。否则,也就是说,如果Gson库通过派生类类型的引用传递了派生类对象,那么我希望字段出现在序列化中 如下: import com.google.gson.Gson; import com.google.gson.GsonBuilder; cl
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()
-这很有用。它被调用,其中包含有关在其中声明字段的类的信息。如果未在基类中声明字段,则返回falseGson用户手册中似乎没有直接的配置。但有一点值得一试: 您可以使用Gson序列化程序来使用动态。在这里,“动态”策略意味着每次您需要序列化一个类
Foo
,您都需要一个配置了OnlyFieldsFor
startegy的Gson实例
是一个接口,指定了两种方法:
shouldSkipClass()
-使用此选项筛选出不需要的类shouldSkipField()
-这很有用。它被调用,其中包含有关在其中声明字段的类的信息。如果未在基类中声明字段,则返回falseTypeAdapter
实现驱动。这种类型的适配器需要考虑
话虽如此,您唯一需要的是从中获取字段的最具体类型:
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
无法将类型参数考虑到此类场景中