java 使用自定义类型适配器,gson 中的 jsonwriter 添加对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17005675/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 00:40:44  来源:igfitidea点击:

adding an object using a custom typeadapter, jsonwriter in gson

javajsongson

提问by Darren Oakey

gson is a great library - it works well. Sometimes I have custom requirements, and can make and register TypeAdapters and TypeAdaptorFactories - and that works well too.

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

What confuses me however, is how to delegate back into json serialization... Most of the time I need this for collections, but to illustrate the point - suppose I had a pair class, which gson would obviously serialize happily, but for some reason I needed my own custom serializer. Well... if my pair is

然而让我困惑的是,如何委托回 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};
}

If I wrote a type adapter for this - you would wantthe write function to look like:

如果我为此编写了一个类型适配器 - 你会希望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();
}

So you can see the problem - I have no ideathe type of first and second, nor how they are serialized. I can use gson.toJson to serialize first and second - but if I add them as a string to the writer, they will be escaped. There is a gson.tojson function that takes a value and a writer - but it also takes a typetoken - which I don't have. I sort of get the impression I'm meant to have another type adapter from somewhere - but when I just have a list of objects... where do I get that? do I just get the adapter for object?

所以你可以看到问题 - 我不知道第一个和第二个的类型,也不知道它们是如何序列化的。我可以使用 gson.toJson 来序列化第一个和第二个 - 但是如果我将它们作为字符串添加到编写器中,它们将被转义。有一个 gson.tojson 函数,它需要一个值和一个 writer - 但它也需要一个 typetoken - 我没有。我有点印象我打算从某个地方使用另一种类型的适配器 - 但是当我只有一个对象列表时......我从哪里得到它?我只是得到对象的适配器吗?

I'm a little confused? Surely this is the most common use case? Most custom serializers will be for a strange list of T or tree of T or something, and you really don't know what is in the list, beyond that it inherits from T... so you need to be able to delegate back the serialization in some way?

我有点困惑?这肯定是最常见的用例吗?大多数自定义序列化器将用于一个奇怪的 T 列表或 T 树之类的东西,你真的不知道列表中是什么,除此之外它继承自 T ......所以你需要能够委托回以某种方式序列化?

Anyway - if someone can tell me how to write the above function, I'd really appreciate it!

无论如何 - 如果有人能告诉我如何编写上述函数,我将不胜感激!

回答by Perception

In this case its better to use a JsonSerializeras opposed to a TypeAdapter, for the simple reason that serializers have access to their serialization context:

在这种情况下,最好使用 aJsonSerializer而不是 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;
    }
}

The above sample code illustrates how to delegate serialization of target objects back to the main marshaller. The main advantage of this (apart from avoiding complicated workarounds) is that you can still take advantage of other type adaptors and custom serializers that might have been registered in the main context. Note that registration of serializers and adapters use the exact same code:

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

// 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();

If you find that you need to stick with an adapter, then you can use an embedded Gson proxy to serialize the Pair properties for you, with the disadvantage that you lose access to custom registrations that you made on the parent Gson proxy:

如果您发现需要坚持使用适配器,那么您可以使用嵌入式 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();
    }
}

回答by Darren Oakey

actually that seemed to work - getting the adapter for object - using the typeadaptorfactory to discover a "json" method on an object, and having that store away the adaptor object. Seems astonishingly complex for what is such an obvious use case?

实际上这似乎有效 - 获取对象的适配器 - 使用 typeadaptorfactory 发现对象上的“json”方法,并将该方法存储在适配器对象上。对于如此明显的用例来说,似乎非常复杂?

eg:

例如:

public static @Nullable
TypeAdapter<ImmutableStack<?>> json(final Gson gson)
{
    final TypeAdapter<Object> adaptor = gson.getAdapter(Object.class);
    return new TypeAdapter<ImmutableStack<?>>()
    {
        @Override
        public ImmutableStack<?> read(@Nullable final JsonReader in) throws IOException
        {
            throw ProgramError.notImplementedYet();
        }
        @Override
        public void write(final JsonWriter out, final ImmutableStack<?> value) throws IOException
        {
            out.beginArray();
            for (final Object inner : value)
                adaptor.write(out, inner);
            out.endArray();
        }
    };
}

does anyone know a better way to do it?

有人知道更好的方法吗?