简体   繁体   English

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

[英]Convert JSON String to generic object in JAVA (with GSON)

I have an Api that returns JSON. 我有一个返回JSON的Api。 The response is in some format that can fit into an object called ApiResult and contains a Context <T> and an int Code. 响应采用某种格式,可以放入名为ApiResult的对象中,并包含Context <T>和int Code。

ApiResult is declared in a generic way, eg ApiResult<SomeObject> ApiResult以通用方式声明,例如ApiResult<SomeObject>

I would like to know how to get GSON to convert the incoming JSON String to ApiResult<T> 我想知道如何让GSON将传入的JSON字符串转换为ApiResult<T>

So far I have: 到目前为止,我有:

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

But this still returns converts the Context to a LinkedHashMap instead (which I assume its what GSON falls back to) 但是这仍然会返回将Context转换为LinkedHashMap(我假设它是GSON回退的)

You have to know what T is going to be. 你必须知道T会是什么。 The incoming JSON is fundamentally just text. 传入的JSON基本上只是文本。 GSON has no idea what object you want it to become. GSON不知道你希望它成为什么对象。 If there's something in that JSON that you can clue off of to create your T instance, you can do something like this: 如果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 );
      }
    }
}

I'm using a field "_class" to decide what my X needs to be and instantiating it via reflection (similar to PomPom's example). 我正在使用字段“_class”来决定我的X需要什么,并通过反射实例化它(类似于PomPom的例子)。 You probably don't have such an obvious field, but there has to be some way for you to look at the JsonElement and decide based on what's itn it what type of X it should be. 你可能没有这么明显的领域,但是你必须有一些方法来查看JsonElement,并根据它应该是什么类型的X来决定它。

This code is a hacked version of something similar I did with GSON a while back, see line 184+ at: https://github.com/chriskessel/MyHex/blob/master/src/kessel/hex/domain/GameItem.java 这段代码是类似我之前用GSON做的类似的黑客版本,请参阅第184+行: https//github.com/chriskessel/MyHex/blob/master/src/kessel/hex/domain/GameItem.java

My solution is using org.json and Jackson 我的解决方案是使用org.json和Jackson

Below are the methods to wrap a json object into an array, to convert an object to into a list and to convert json string to a type. 下面是将json对象包装到数组中,将对象转换为列表以及将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);

You have to provide Gson the type of T . 你必须为Gson提供T As gson doesn't know what adapter should be applied, it simply return a data structure. 由于gson不知道应该应用什么适配器,它只是返回一个数据结构。

Your have to provide the generic, like : 你必须提供通用,如:

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

If type of T is only known at runtime, I use something tricky : 如果只在运行时知道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);
  }

Your call would be (but replacing String.class with a variable) : 你的调用将是(但用一个变量替换String.class ):

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

I use JacksonJson library, quite similar to GSon. 我使用JacksonJson库,与GSon非常相似。 It's possible to convert json string to some generic type object this way: 可以通过这种方式将json字符串转换为某些泛型类型对象:

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

Maybe this is correct way with GSON in your case: 在您的情况下,使用GSON可能这是正确的方法:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM