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

tyky79it  于 2022-11-06  发布在  Java
关注(0)|答案(5)|浏览(253)

我有一个返回JSON的Api,响应的格式可以放入一个名为ApiResult的对象中,包含一个Context <T>和一个int代码。
ApiResult以泛型方式声明,例如ApiResult<SomeObject>
我想知道如何让GSON将传入的JSON字符串转换为ApiResult<T>
到目前为止我已经:

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

但这仍然返回将Context转换为LinkedHashMap(我假设这是GSON福尔斯回退)

ncgqoxb0

ncgqoxb01#

你必须知道T是什么。传入的JSON基本上只是文本。JSON不知道你想让它变成什么对象。如果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

myss37ts

myss37ts2#

你必须为Gson提供T类型,因为gson不知道应该应用什么适配器,它只返回一个数据结构。
您必须提供通用信息,例如:

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);
mum43rcc

mum43rcc3#

我的解决方案是使用org.json和Jackson

下面是将json对象 Package 成数组、将对象转换成列表以及将json字符串转换成类型的方法。

private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

public <T> List<T> parseJsonObjectsToList(JSONObject parentJson, String key, Class<T> clazz) throws IOException {

    Object childObject = parentJson.get(key);

    if(childObject == null) {
        return null;
    }

    if(childObject instanceof JSONArray) {

        JSONArray jsonArray = parentJson.getJSONArray(key);
        return getList(jsonArray.toString(), clazz);

    }

    JSONObject jsonObject = parentJson.getJSONObject(key);
    List<T> jsonList = new ArrayList<>();
    jsonList.add(getObject(jsonObject.toString(), clazz));

    return jsonList;
}

public <T> List<T> getList(String jsonStr, Class clazz) throws IOException {
    ObjectMapper objectMapper = OBJECT_MAPPER;
    TypeFactory typeFactory = objectMapper.getTypeFactory();
    return objectMapper.readValue(jsonStr, typeFactory.constructCollectionType(List.class, clazz));
}

public <T> T getObject(String jsonStr, Class<T> clazz) throws IOException {
    ObjectMapper objectMapper = OBJECT_MAPPER;
    return objectMapper.readValue(jsonStr, clazz);
}

// To call 
  parseJsonObjectsToList(creditReport, JSON_KEY, <YOU_CLASS>.class);
qyswt5oh

qyswt5oh4#

我使用的是JacksonJson库,与GSon非常相似。可以通过以下方式将json字符串转换为某个泛型类型的对象:

String data = getJsonString();
ObjectMapper mapper = new ObjectMapper();
List<AndroidPackage> packages = mapper.readValue(data, List.class);

也许这是正确的方式与GSON在您的情况:

ApiResult<T> result = gson.fromJson(json, ApiResult.class);
z4iuyo4d

z4iuyo4d5#

JSON到通用对象

public <T> T fromJson(String json, Class<T> clazz) {
    return new Gson().fromJson(json, clazz);
}

JSON到通用对象列表

public <T> List<T> fromJsonAsList(String json, Class<T[]> clazz) {
    return Arrays.asList(new Gson().fromJson(json, clazz));
}

相关问题