在 JAVA 中将 JSON 字符串转换为通用对象(使用 GSON)

2022-09-04 04:01:26

我有一个返回JSON的Api。响应采用某种格式,可以放入名为 ApiResult 的对象中,并包含 a 和 int 代码。Context <T>

ApiResult 以通用方式声明,例如ApiResult<SomeObject>

我想知道如何让GSON将传入的JSON字符串转换为ApiResult<T>

到目前为止,我有:

Type apiResultType = new TypeToken<ApiResult<T>>() { }.getType();
ApiResult<T> result = gson.fromJson(json, apiResultType);

但这仍然返回将上下文转换为LinkedHashMap(我假设它是GSON回退到的)


答案 1

你必须知道T会是什么。传入的 JSON 基本上只是文本。GSON不知道你想让它成为什么对象。如果该 JSON 中有一些内容可供您参考以创建 T 实例,则可以执行如下操作:

public static class MyJsonAdapter<X> implements JsonDeserializer<ApiResult<X>>
{
    public ApiResult<X> deserialize( JsonElement jsonElement, Type type, JsonDeserializationContext context )
      throws JsonParseException
    {
      String className = jsonElement.getAsJsonObject().get( "_class" ).getAsString();
      try
      {
        X myThing = context.deserialize( jsonElement, Class.forName( className ) );
        return new ApiResult<>(myThing);
      }
      catch ( ClassNotFoundException e )
      {
        throw new RuntimeException( e );
      }
    }
}

我使用一个字段“_class”来决定我的X需要是什么,并通过反射来实例化它(类似于PomPom的例子)。你可能没有这么明显的字段,但是必须有某种方式让你查看JsonElement,并根据它是什么来决定它应该是什么类型的X。

这段代码是一个被黑客入侵的版本,类似于我不久前对GSON所做的类似事情,请参阅第184 +行:https://github.com/chriskessel/MyHex/blob/master/src/kessel/hex/domain/GameItem.java


答案 2

您必须向 Gson 提供 .由于gson不知道应该应用什么适配器,因此它只是返回一个数据结构。T

您必须提供泛型,例如:

Type apiResultType = new TypeToken<ApiResult<String>>() { }.getType();

如果T的类型仅在运行时已知,则使用一些棘手的内容:

  static TypeToken<?> getGenToken(final Class<?> raw, final Class<?> gen) throws Exception {
    Constructor<ParameterizedTypeImpl> constr = ParameterizedTypeImpl.class.getDeclaredConstructor(Class.class, Type[].class, Type.class);
    constr.setAccessible(true);
    ParameterizedTypeImpl paramType = constr.newInstance(raw, new Type[] { gen }, null);

    return TypeToken.get(paramType);
  }

您的调用将是(但替换为变量):String.class

Type apiResultType = getGenToken(ApiResult.class, String.class);

推荐