如果无法更改类声明,则如何在序列化时或多或少全局更改结果Json? [英] How to change resulting Json when serializing, more or less globally, if class declarations can not be changed?

查看:125
本文介绍了如果无法更改类声明,则如何在序列化时或多或少全局更改结果Json?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设:

  • 您需要传递一堆 Java对象-例如-传递给某些API
  • 您不愿意或不能更改这些对象的声明
  • 不幸的是,API需要在那些对象中未声明的内容
  • there is a bunch of Java objects that you need to pass - for example - to some API
  • you are not willing or can not change declaration for those objects
  • unfortunately API requires something that is not declared in those objects

作为一个例子(受问题的启发),有一个简单的类:

As an example (inspired by this question) there is a simple class:

@Getter
@RequiredArgsConstructor
public class Login {
    private final String username, password; 
}

但是,API需要JSON,例如:

However, API expects JSON like:

{
  "username": "uname",
  "password": "pword",
  "version": 1
}

此问题同样适用于所有其他99个类:那些还需要在序列化JSON中将字段version设置为1.

and this same problem applies to all other 99 classes: those need also field version with value 1 in serialized JSON.

有些解决方案需要底层字符串操作或添加大量样板代码,但是用GSON处理此问题的通用方法是什么?

There are some solutions that require either low level string manipulation or adding lots of boilerplate code but what would be the generic way to deal with this issue with GSON?

推荐答案

首先,要让Gson序列化(或反序列化)一堆具有相同类型的最佳方法的不同类型的对象避免注册大量适配器或更改类声明是为了利用TypeAdapterFactory.

Firstly, to have Gson to serialize (or to deserialize) bunch of different types of objects having same type of adapting the best way to avoid registering lots of adapters or altering class declarations is to make benefit of TypeAdapterFactory.

它本身并不绑定到任何TypeClass,而是根据类型决定当Gson撞到某个要序列化(或反序列化)的对象时要返回哪个TypeAdapter.使用TypeAdaterFactory可以使代码免于注册许多TypeAdapter.

It is not itself bound to any Type or Class but decides per type which TypeAdapter to return when Gson bumps into some object to serialize (or deserialize). Using TypeAdaterFactory frees code from registering lots of TypeAdapters.

其次,自然地,为了避免创建许多TypeAdapter,解决方案是在可能的情况下将通用类型设置为TypeAdapter.

Secondly and naturally, to avoid creating many TypeAdapters the solution is to make a generic type of TypeAdapter whenever possible.

在有疑问的情况下从通用TypeAdapter开始,可能像这样:

Starting from the generic TypeAdapter in questions case it might be like:

@RequiredArgsConstructor
private class GenericTypeAdapter<T> extends TypeAdapter<T> {

    // typeToken is needed when deserializing
    private final TypeToken<T> typeToken;
    private final Gson gson = new GsonBuilder().setPrettyPrinting().create();

    @Override
    public void write(JsonWriter out, T value) throws IOException {
        // Altering could be done with some low level string manipulation
        // but JsonObject makes altering object more safe.
        // Feel free to comment for better way to instantiate it,
        // this is just for an example.
        JsonObject jsonObject = gson.fromJson(gson.toJson(value)
                            ,JsonElement.class).getAsJsonObject();
        // alter jsonObject in any way needed,
        // here is only added version information
        jsonObject.addProperty("version", 1);
        out.jsonValue(gson.toJson(jsonObject));
    }

    @Override
    public T read(JsonReader in) throws IOException {
        // maybe needless to mention but mention still:
        // here it is possible to init object in a way 
        // that provided JSON solely does not make possible
        return gson.fromJson(in, typeToken.getType());
    }
}

然后TypeAdapterFactory.这很简单,但是请注意示例代码中的注释.如前所述,TypeAdapterFactory负责为每个对象返回正确的TypeAdapter.尽管它打算适用于组合类型,但可能并不适用于所有类型.最简单的TypeAdapterFactory:

Then the TypeAdapterFactory. It is quite simple but pay attention to the comments in example code. As mentioned before TypeAdapterFactory is responsible of returning correct TypeAdapter per object. Although it is meant to apply to a bunch of types it might not be meant to apply to all the types. Most simple TypeAdapterFactory:

public class GenericTypeAdapterFactory implements TypeAdapterFactory {
    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        // here should be checked if the passed type needs any custom 
        // adapter and if it needs then decide  which adapter to return
        // or in case of no customization needed return null for default
        // adapter.
        // decision can be made for example by
        // * type itself
        // * package name
        // * if type implements / extends some super type
        return new GenericTypeAdapter<>(type);
    }       
}

用法将简单地是:

Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(new GenericTypeAdapterFactory())
    .setPrettyPrinting()
    .create()

注意:我本来是为此问题准备此答案的,但由于后来出现了我是基于Kotlin(?)的人,我觉得创建一个更通用的Java处理Q& A感觉更好.

Note: I prepared this answer originally to this question but since it later appeared to be Kotlin(?) based I felt better to create a more generic Q&A dealt with Java.

这篇关于如果无法更改类声明,则如何在序列化时或多或少全局更改结果Json?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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