【问题标题】:Gson: Instantiate Interface from Json StringGson:从 Json 字符串实例化接口
【发布时间】:2016-08-02 00:51:19
【问题描述】:

我正在使用Gson 反序列化一些由http 标头传入的json 字符串(实际上是jwt)。 json 包含:

[
    {"authority":"a1"},
    {"authority":"a2"},
    {"authority":"a3"},
             .
             .
             .
    {"authority":"a4"},
]

JsonElement。 我希望将上述部分反序列化到字段中(在某些类中):

Set<GrantedAuthority> authorities

GrantedAuthority 是 Spring 的一个接口,它有一个实现 SimpleGrantedAuthoritySimpleGrantedAuthority 有一个接受字符串的构造函数:

public SimpleGrantedAuthority(String au) {this.au = au}

为了反序列化json,我需要Gson知道接口GrantedAuthority的实现类。我正在尝试:

public class GrantedAuthorityInstanceCreator implements InstanceCreator<GrantedAuthority> {
    @Override
    public GrantedAuthority createInstance(Type type) {
        // no such constructor
        GrantedAuthority ga = new SimpleGrantedAuthority();
        return ga;
    }
}

但由于SimpleGrantedAuthority 没有无参数构造函数,我需要为构造函数提供一个参数。我怎样才能做到这一点?

【问题讨论】:

  • 描述与标题有何关系?你想达到什么目的?
  • @waltersu 我想将 json 字符串反序列化到该字段中,但它是一个接口类型,我不知道如何编程 gson 以使用实现 SimpleGrantedAuthority 实例化该接口
  • 为什么不将它们反序列化为SimpleGrantedAuthority,自己创建Set&lt;GrantedAuthority&gt;,放入集合中呢?
  • @waltersu json 字符串还有很多其他字段,Set&lt;GrantedAuthority&gt; 也只是我想反序列化成的类的一个字段。我不认为我可以先反序列化其他字段然后组成Set&lt;GrantedAuthority&gt; 字段,因为只有一个构造函数可以实例化所有字段。

标签: java json gson


【解决方案1】:

InstanceCreator 不起作用。根据gson-user-guide。你有 3 个选择:

选项 1:使用 Gson 的解析器 API(低级流解析器或 DOM 解析器 JsonParser)解析数组元素,然后对每个数组元素使用 Gson.fromJson()。这是首选方法。这是一个演示如何执行此操作的示例。

选项 2:为 Collection.class 注册一个类型适配器,该适配器查看每个数组成员并将它们映射到适当的对象。这种方法的缺点是它会搞砸 Gson 中其他集合类型的反序列化。

选项 3:为 MyCollectionMemberType 注册一个类型适配器并将 fromJson 与 Collection 一起使用 仅当数组显示为顶级元素或您可以将保存集合的字段类型更改为 Collection 类型时,此方法才实用。

你说

我希望将上述部分反序列化到字段中(在某个类中):

因此,假设“某个类”是MyClassauthorities 是您的 json 字符串的 MyClass 的一个字段(MyClass 中还有其他字段)。下面是使用方法“选项 3”的示例代码:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.util.Set;

public class Test2 {
  public static void main(String[] args) throws Exception {
    String json = "{ authorities: [\n" +
        "    {\"authority\":\"a1\"},\n" +
        "    {\"authority\":\"a2\"},\n" +
        "    {\"authority\":\"a3\"},\n" +
        "    {\"authority\":\"a4\"}\n" +
        "]}";

    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeHierarchyAdapter(GrantedAuthority.class, new GrantedAuthorityTypeAdaptor());
    Gson gson = gsonBuilder.create();

    MyClass obj1 = gson.fromJson(json, MyClass.class);
    for (GrantedAuthority au : obj1.authorities) {
      SimpleGrantedAuthority sgau = (SimpleGrantedAuthority) au;
      System.out.println(sgau.authority);
    }
  }
}


class MyClass {
  Set<GrantedAuthority> authorities;

  // other fields
}


interface GrantedAuthority {
}

class SimpleGrantedAuthority implements GrantedAuthority {
  final String authority;

  public SimpleGrantedAuthority(String au) {
    this.authority = au;
  }
}

class GrantedAuthorityTypeAdaptor extends TypeAdapter<GrantedAuthority> {
  @Override
  public void write(JsonWriter out, GrantedAuthority value) throws IOException {
    new Gson().getAdapter(SimpleGrantedAuthority.class).write(out, (SimpleGrantedAuthority) value);
  }

  @Override
  public GrantedAuthority read(JsonReader in) throws IOException {
    return new Gson().getAdapter(SimpleGrantedAuthority.class).read(in);
  }
}

方法是使用SimpleGrantedAuthorityAdaptor 作为GrantedAuthority 的适配器。

为了不弄乱其他代码,GsonBuilder 应该只在这里使用。您应该在其他代码中创建一个新的GsonBuilder

【讨论】:

  • 我在SimpleGrantedAuthority 中为authority 获得了NullPointerException。似乎该字段为空。需要注意的一件事是我使用了JsonElementjsonElement = gson.toJsonTree(body.get("key")) 然后gson.fromJson(jsonElement, Myclass.class)body.get("key") 实际上返回一个 HashMap,我可以用它来实例化 Myclass。这有点复杂,因为传递给我的令牌实际上是一个 JWT 令牌,我需要先解密它,这会产生一个 HashMap。
猜你喜欢
  • 1970-01-01
  • 2015-08-29
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
  • 1970-01-01
  • 2013-01-18
  • 1970-01-01
  • 2023-03-18
相关资源
最近更新 更多