使用gson中的自定义typeadapter,jsonwriter添加对象 [英] adding an object using a custom typeadapter, jsonwriter in gson

查看:442
本文介绍了使用gson中的自定义typeadapter,jsonwriter添加对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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};



$ b

如果我为此写了一个类型适配器 - 你会 / em>写函数看起来像:

  public void write(JsonWriter out,Pair pair)
{
out.beginObject();
out.name(first);
out.value(pair.first); //不能这样做
out.name(second);
out.value(pair.second); //或者这个
out.endObject();





$ b

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



我有点困惑?当然这是最常见的用例?大多数自定义序列化程序将用于T或T树的奇怪列表或其他东西,而且您真的不知道列表中的内容,除此之外它还是从T继承的...因此您需要能够将序列化?



无论如何 - 如果有人能告诉我如何编写上述函数,我真的很感激它!

解决方案

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

  public class PairSerializer实现JsonSerializer<对> {

public PairSerializer(){
super();

$ b @Override
public JsonElement serialize(final对值,final类型,
final JsonSerializationContext上下文){
final JsonObject jsonObj = new JsonObject ();
jsonObj.add(first,context.serialize(value.getFirst()));
jsonObj.add(second,context.serialize(value.getSecond()));

返回jsonObj;


$ / code>

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

  //使用适配器
final Gson gson = new GsonBuilder()。registerTypeAdapter(Pair.class,
new PairAdapter())。create();
$ b $ //使用序列化程序
final Gson gson = new GsonBuilder()。registerTypeAdapter(Pair.class,
new PairSerializer())。create();

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

 公共类PairAdapter扩展了TypeAdapter< Pair> {
final Gson embedded = new Gson();

public PairAdapter(){
super();

$ b @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();
}
}


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.

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

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 want the write function to look like:

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 idea the 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?

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?

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

解决方案

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

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:

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

这篇关于使用gson中的自定义typeadapter,jsonwriter添加对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆