GSON JSON对象和链接树Map

svdrlsy4  于 2022-11-06  发布在  其他
关注(0)|答案(1)|浏览(266)

我注意到在GSON中没有一种简单的方法可以将JsonArray转换为List。我找到了一个使用TypeToken的例子,当我试图将其移动到泛型方法时(我对Java泛型有点模糊),我发现了一些奇怪的行为,其中JsonObjectLinkedTreeMap被混淆了。参见下面的例子:

  1. public <T> List<T> jsonArrayToList(JsonArray array, Class<T> clazz) {
  2. Gson GSON = new Gson();
  3. Type listType = new TypeToken<List<T>>() {}.getType();
  4. return GSON.fromJson(array,listType);
  5. }
  6. @Test
  7. public void testGson() {
  8. Gson GSON = new Gson();
  9. String jsonString = "[ {key:\"foo\",value:\"bar\"}, {key:\"shoe\",value:\"car\"} ]";
  10. JsonArray testArray = new JsonParser().parse(jsonString).getAsJsonArray();
  11. Type listType = new TypeToken<List<JsonObject>>() {}.getType();
  12. List<JsonObject> goodList = GSON.fromJson(testArray,listType);
  13. List<JsonObject> badList = jsonArrayToList(testArray, JsonObject.class); // Actually a list of LinkedTreeMap?
  14. System.out.println( goodList ); // [{"key":"foo","value":"bar"}, {"key":"shoe","value":"car"}]
  15. System.out.println( badList ); // [{key=foo, value=bar}, {key=shoe, value=car}]
  16. try {
  17. long shoeCount = goodList.stream().filter(o -> o.get("key").getAsString().startsWith("sh")).count();
  18. System.out.println( shoeCount ); // 1
  19. } catch (Exception e) { System.out.println( e.getMessage() ); }
  20. try {
  21. long shoeCount = badList.stream().filter(o -> o.get("key").getAsString().startsWith("sh")).count();
  22. System.out.println( shoeCount );
  23. } catch (Exception e) {
  24. System.out.println(e.getMessage()); // com.google.gson.internal.LinkedTreeMap cannot be cast to com.google.gson.JsonObject
  25. }
  26. }

我只是好奇为什么会发生这种情况和/或泛型方法是否不正确。

u3r8eeie

u3r8eeie1#

正如注解中所解释的,由于Java类型擦除,TypeToken<List<T>>在运行时实际上是TypeToken<List<Object>>,而不管T的值是什么。当Gson被告知反序列化为Object时,它使用与JSON数据对应的Java类型,对于JSON对象是java.util.Map(Gson的实现是LinkedTreeMap)。
因此,一般来说,在创建TypeToken时,你不应该使用任何类型变量(不幸的是,Gson本身并不阻止这种用法)。
对于您的特定用例,您可以使用TypeToken.getParameterized方法,通过该方法,您可以使用在运行时指定的类型参数来创建参数化类型,这是以在编译时丢失类型安全为代价的,因此您必须确保根据泛型类型为getParameterized提供正确的参数数量(例如,Map<K, V>需要两个类型参数),并且它们不验证类型变量的类型边界。
下面是在方法jsonArrayToList中使用它的方法:

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

相关问题