一尘不染

在gson中使用自定义typeadapter,jsonwriter添加对象

json

gson是一个很棒的图书馆-运作良好。有时我有自定义要求,并且可以制作和注册TypeAdapters和TypeAdaptorFactories-效果也很好。

但是令我困惑的是如何委托回json序列化…大多数时候,我需要使用它进行收集,但为了说明这一点-
假设我有一个配对类,gson显然会很高兴地序列化,但是出于某种原因我需要自己的自定义序列化程序。好吧…如果我是

public class Pair
{
    public final Object First;
    public final Object Second; 
    public Pair( Object first, Object second) {this.first = first; this.second = second};
}

如果我为此编写了一个类型适配器-您可能 希望 write函数如下所示:

public void write( JsonWriter out, Pair pair )
{
    out.beginObject();
    out.name( "first");
    out.value( pair.first );         // can't do this
    out.name( "second");
    out.value( pair.second);         // or this
    out.endObject();
}

因此,您可以看到问题-我 不知道 第一和第二的类型,也不知道它们如何序列化。我可以先使用gson.toJson进行序列化,然后再序列化-
但是,如果我将它们作为字符串添加到writer,它们将被转义。有一个gson.tojson函数需要一个值和一个writer-
但它也需要一个typetoken-我没有。我给人的印象是我打算从某个地方获得另一个类型适配器-
但是当我只拥有对象列表时,该从哪里得到呢?我只是获得对象的适配器?

我有点困惑吗?当然这是最常见的用例?大多数自定义序列化程序将用于T的奇怪列表或T的树或其他内容,并且您真的不知道列表中的内容,除了它继承自T
…因此,您需要能够将T委托给它。以某种方式进行序列化?

无论如何-如果有人可以告诉我如何编写上述功能,我将非常感谢!


阅读 616

收藏
2020-07-27

共1个答案

一尘不染

在这种情况下,最好使用a
JsonSerializer而不是a
TypeAdapter,原因很简单,因为序列化程序可以访问其序列化上下文:

public class PairSerializer implements JsonSerializer<Pair> {

    public PairSerializer() {
        super();
    }

    @Override
    public JsonElement serialize(final Pair value, final Type type,
            final JsonSerializationContext context) {
        final JsonObject jsonObj = new JsonObject();
        jsonObj.add("first", context.serialize(value.getFirst()));
        jsonObj.add("second", context.serialize(value.getSecond()));

        return jsonObj;
    }
}

上面的示例代码说明了如何将目标对象的序列化委派回主编组器。这样做的主要优点(除了避免复杂的解决方法)是,您仍然可以利用可能已经在主上下文中注册的其他类型的适配器和自定义序列化程序。请注意,序列化器和适配器的注册使用完全相同的代码:

// With adapter
final Gson gson = new GsonBuilder().registerTypeAdapter(Pair.class,
        new PairAdapter()).create();

// With serializer
final Gson gson = new GsonBuilder().registerTypeAdapter(Pair.class,
        new PairSerializer()).create();

如果发现需要使用适配器,则可以使用嵌入式Gson代理为您序列化Pair属性,其缺点是您无法访问在父Gson代理上进行的自定义注册:

public class PairAdapter extends TypeAdapter<Pair> {
    final Gson embedded = new Gson();

    public PairAdapter() {
        super();
    }

    @Override
    public void write(final JsonWriter out, final Pair value)
            throws IOException {
        out.beginObject();

        out.name("first");
        embedded.toJson(embedded.toJsonTree(value.getFirst()), out);

        out.name("second");
        embedded.toJson(embedded.toJsonTree(value.getSecond()), out);

        out.endObject();
    }

    @Override
    public Pair read(JsonReader in) throws IOException {
        throw new UnsupportedOperationException();
    }
}
2020-07-27