简体   繁体   English

GSON JsonObject 和 LinkedTreeMap

[英]GSON JsonObject and LinkedTreeMap

I noticed there wasn't an easy all-inclusive (POJO-free) way to convert (in GSON) a JsonArray to a List .我注意到没有一种简单的包罗万象(无 POJO)的方法来将(在 GSON 中) JsonArray转换为List I found an example that uses a TypeToken and when I tried to use move this to a generic method (I'm a little hazy on my Java Generics), I found some odd behavior where JsonObject and LinkedTreeMap were confused.我发现了一个使用TypeToken的示例,当我尝试使用将其移动到通用方法时(我对 Java 泛型有点模糊),我发现了一些奇怪的行为,其中JsonObjectLinkedTreeMap被混淆了。 See example below:请参见下面的示例:

public <T> List<T> jsonArrayToList(JsonArray array, Class<T> clazz) {
    Gson GSON = new Gson();
    Type listType = new TypeToken<List<T>>() {}.getType();
    return GSON.fromJson(array,listType);
}

@Test
public void testGson() {
    Gson GSON = new Gson();
    String jsonString = "[ {key:\"foo\",value:\"bar\"}, {key:\"shoe\",value:\"car\"} ]";
    JsonArray testArray = new JsonParser().parse(jsonString).getAsJsonArray();
    Type listType = new TypeToken<List<JsonObject>>() {}.getType();
    List<JsonObject> goodList = GSON.fromJson(testArray,listType);
    List<JsonObject> badList = jsonArrayToList(testArray, JsonObject.class);    // Actually a list of LinkedTreeMap?

    System.out.println( goodList );     // [{"key":"foo","value":"bar"}, {"key":"shoe","value":"car"}]
    System.out.println( badList );      // [{key=foo, value=bar}, {key=shoe, value=car}]

    try {
        long shoeCount = goodList.stream().filter(o -> o.get("key").getAsString().startsWith("sh")).count();
        System.out.println( shoeCount );    // 1
    } catch (Exception e) { System.out.println( e.getMessage() ); }

    try {
        long shoeCount = badList.stream().filter(o -> o.get("key").getAsString().startsWith("sh")).count();
        System.out.println( shoeCount );
    } catch (Exception e) {
        System.out.println(e.getMessage()); // com.google.gson.internal.LinkedTreeMap cannot be cast to com.google.gson.JsonObject
    }
}

I'm just curious why this occurs and/or if the generic method is incorrect.我只是好奇为什么会发生这种情况和/或通用方法是否不正确。

As explained in the comments , due to Java type erasure, the TypeToken<List<T>> is actually a TypeToken<List<Object>> at runtime, regardless of what value T has.评论中所述,由于 Java 类型擦除, TypeToken<List<T>>在运行时实际上是一个TypeToken<List<Object>> ,无论T的值是多少。 When Gson is told to deserialize as Object it uses a Java type corresponding to the JSON data, for your JSON object that is java.util.Map (with Gson's implementation LinkedTreeMap ).当Gson被告知要进行Object ,它使用的Java类型对应于LinkedTreeMap数据,用于您的java.util.Map .

In general you should therefore never use any type variables when creating a TypeToken (unfortunately Gson itself does not prevent this usage).因此,通常在创建TypeToken时永远不要使用任何类型变量(不幸的是,Gson 本身并不能阻止这种用法)。

For your specific use case you can use the method TypeToken.getParameterized .对于您的特定用例,您可以使用方法TypeToken.getParameterized With that you can create parameterized types with type arguments specified at runtime.有了它,您可以创建在运行时指定类型 arguments 的参数化类型。 This comes at the cost of missing type safety at compile time, so you have to make sure to provide the correct number of arguments to getParameterized depending on the generic type (eg Map<K, V> requires two type arguments) and that they do not validate the type bounds of the type variable.这是以编译时缺少类型安全为代价的,因此您必须确保根据泛型类型(例如Map<K, V>需要两个类型参数)向getParameterized提供正确数量的 arguments 并且它们确实如此不验证类型变量的类型边界。

Here is how you could use it in your method jsonArrayToList :以下是如何在方法jsonArrayToList中使用它:

public <T> List<T> jsonArrayToList(JsonArray array, Class<T> clazz) {
    Gson GSON = new Gson();
    Type listType = TypeToken.getParameterized​(List.class, clazz).getType();
    return GSON.fromJson(array,listType);
}

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

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