当前位置: 首页 > 知识库问答 >
问题:

向GSON注册多个适配器不起作用

满博
2023-03-14

我在向我的GsonBuilder注册多个TypeAdapter时遇到问题。似乎只有一个会开火,而第二个永远不会被考虑。如果我单独使用每一个,它似乎工作得很好。但我需要他们一起工作,而且似乎我做错了什么。此外,我目前正在使用GSON v2。2.4.

Zip对象简单表单:

public class Zip {

  private String zipCode;
  private String city;
  private String state;

  public Zip(){}                                            
}

拉链系列:

public class ZipSerializer implements JsonSerializer<Zip>{

    @Override
    public JsonElement serialize(Zip obj, Type type, JsonSerializationContext jsc) {
        Gson gson = new Gson();
        JsonObject jObj = (JsonObject)gson.toJsonTree(obj);
        jObj.remove("state");        
        return jObj;
    }

}

简单形式:

public class JsonResponse {

    private String jsonrpc = "2.0"; 
    private Object result = null;
    private String id = null;

    public JsonResponse(){}

}

JsonResponseSerializer:

public class JsonResponseSerializer implements JsonSerializer<JsonResponse> {

    @Override
    public JsonElement serialize(JsonResponse obj, Type type, JsonSerializationContext jsc) {
        Gson gson = new Gson();
        JsonObject jObj = (JsonObject)gson.toJsonTree(obj);
        jObj.remove("id");

        return jObj;
    }

}

测试示例:

public class Test {

    public static void main(String[] args) {
        Zip zip = new Zip();
        zip.setCity("testcity");
        zip.setState("OH");
        zip.setZipCode("12345");

        JsonResponse resp = new JsonResponse();
        resp.setId("1");
        resp.setResult(zip);
        resp.setJsonrpc("2.0");

        Gson gson1 = new GsonBuilder()
        .registerTypeAdapter(JsonResponse.class, new JsonResponseSerializer())
        .registerTypeAdapter(Zip.class, new ZipSerializer())
        .setPrettyPrinting()
        .create();


        String json = gson1.toJson(resp);
        System.out.println(json);               

    }

}

输出:

{
  "jsonrpc": "2.0",
  "result": {
    "zipCode": "12345",
    "city": "testcity",
    "state": "OH"
  }
}

预期输出:(注意ZipSerializer没有发射)

{
  "jsonrpc": "2.0",
  "result": {
    "zipCode": "12345",
    "city": "testcity"
  }
}

我简化了这个测试用例。我知道我可以在这个例子中使用排除策略来实现结果,但真正的问题要复杂得多,这是我描述和复制问题的最佳方式。

谢谢

我设法用TypeAdapter为一个对象中的一个变量(多个变量中的一个)读取Gson定制seralizer,这对我帮助很大。

我创建了一个基本customTypeAdapterFactory,然后为每个需要特殊序列化的类扩展它。

定制类型适配器工厂

public abstract class CustomizedTypeAdapterFactory<C> implements TypeAdapterFactory {

    private final Class<C> customizedClass;

    public CustomizedTypeAdapterFactory(Class<C> customizedClass) {
        this.customizedClass = customizedClass;
    }

    @SuppressWarnings("unchecked") // we use a runtime check to guarantee that 'C' and 'T' are equal
    public final <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        return type.getRawType() == customizedClass
                ? (TypeAdapter<T>) customizeMyClassAdapter(gson, (TypeToken<C>) type)
                : null;
    }

    private TypeAdapter<C> customizeMyClassAdapter(Gson gson, TypeToken<C> type) {
        final TypeAdapter<C> delegate = gson.getDelegateAdapter(this, type);
        final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);

        return new TypeAdapter<C>() {

            @Override public void write(JsonWriter out, C value) throws IOException {               
                JsonElement tree = delegate.toJsonTree(value);
                beforeWrite(value, tree);
                elementAdapter.write(out, tree);
            }


            @Override public C read(JsonReader in) throws IOException {
                JsonElement tree = elementAdapter.read(in);
                afterRead(tree);
                return delegate.fromJsonTree(tree);
            }
        };
    }

    /**
    * Override this to muck with {@code toSerialize} before it is written to
    * the outgoing JSON stream.
    */
    protected void beforeWrite(C source, JsonElement toSerialize) {
    }

    /**
    * Override this to muck with {@code deserialized} before it parsed into
    * the application type.
    */
    protected void afterRead(JsonElement deserialized) {
    }
}

ZipTypeAdapterFactory(这样做与Json响应TypeAdapterFactory)

public class ZipTypeAdapterFactory  extends CustomizedTypeAdapterFactory<Zip> {

    ZipTypeAdapterFactory() {
        super(Zip.class);
    }

    @Override
    protected void beforeWrite(Zip source, JsonElement toSerialize) {
        JsonObject obj = (JsonObject) toSerialize;
        obj.remove("state");
    }

}

测试代码:

Gson gson1 = new GsonBuilder()
        .registerTypeAdapterFactory(new JsonResponseTypeAdapterFactory())       
        .registerTypeAdapterFactory(new ZipTypeAdapterFactory())
        .setPrettyPrinting()
        .create();


        String json = gson1.toJson(resp);
        System.out.println(json);

谢谢大家的帮助。

共有1个答案

洪飞龙
2023-03-14

问题出在您的JsonResponseSerializer中。您创建一个新的Gson实例,然后在此新实例上未注册ZipSerializer。这就是为什么你的第二个序列化程序从未被调用。

如果您想实现委托和复杂的序列化,请查看TypeAdapterFactory

正如您所说,如果您只是想从序列化中筛选字段,请定义一个排除策略

 类似资料:
  • 我延长了 当我打电话的时候: 什么也没发生。 刷新视图的唯一方法是再次设置适配器(请参见此答案): 我对此解决方案有两个问题: 当我再次设置适配器时,我可以看到屏幕上有一个闪烁 listview返回第一个位置。 有什么想法吗?

  • 我已经创建了一个CDI(WELD)拦截器,它可以工作并拦截它应该拦截的内容。 其中MyInterceptorBinding是一个拦截器绑定: 我想将我的拦截器注入一个bean类,如下所示: 但是这个注入带来了一个错误: 我如何克服这个问题?问题是否与拦截器的事实有关?我应该使用CDI便携式扩展设施吗?如果是,如何解决?

  • 问题内容: 我正在尝试使用Spring Security,并且有一个用例,其中我想保护不同的登录页面和不同的URL集。 这是我的配置: 这些类是具有注释的另一个类的内部类。 的安全性工作正常,但所有页面均未得到保护,登录页面未发生任何重定向。我搜索了其他答案,但没有一个有效。 问题答案: 看一下: 1正常配置身份验证 2创建一个包含的实例,以指定应首先考虑的对象。 3 r指出这仅适用于以开头的 4

  • 我的客户机/服务器上的推送通知设备注册管理有一个小问题。 同样,这里的问题是,我有两个或更多的注册ID都可以工作(如果我旧的一个在尝试从服务器发布消息时不工作,这不会有问题,因为我可以简单地清理它)。

  • 我正在尝试在我的应用程序中设置Spring Security,它有3个组件: REST API(在v1路径下) 我想这样设置安全性: 用JWT令牌保护的REST API 使用HTTP basic保护管理员 无担保文件(公共资源) 我尝试在的单独实现中为这3个部分配置身份验证,结果如下所示: 对于REST API: 对于Spring管理员: 对于公共文件: 我的主要应用程序类如下所示: 当我运行应用

  • 问题内容: 我正在尝试使用Spring Security,并且有一个用例,其中我想保护不同的登录页面和不同的URL集。 这是我的配置: 这些类是具有注释的另一个类的内部类。 的安全性工作正常,但所有页面均未得到保护,登录页面未发生任何重定向。我搜索了其他答案,但没有一个有效。 问题答案: 看一下Spring Security Reference: 1正常配置身份验证 2创建一个包含的实例,以指定应