jackson:无法将java.util.LinkedHashMap强制转换为X

JsonJack:无法将java.util.LinkedHashMap强制转换为X

1.概述

Jackson是一个广泛使用的Java库,它使可以方便地对JSON或XML进行序列化/反序列化。

有时,当尝试将JSON或XML反序列化为对象集合时,可能会遇到“ java.lang.ClassCastException:java.util.LinkedHashMap无法转换为X”。

2.了解问题

让创建一个简单的Java应用程序来重现此异常,以了解何时会发生该异常。

2.1创建一个POJO类

public class Book {
    private Integer bookId;
    private String title;
    private String author;
    //getters, setters, constructors, equals and hashcode omitted
}

json数据

[ {
    "bookId" : 1,
    "title" : "A Song of Ice and Fire",
    "author" : "George R. R. Martin"
}, {
    "bookId" : 2,
    "title" : "The Hitchhiker's Guide to the Galaxy",
    "author" : "Douglas Adams"
}, {
    "bookId" : 3,
    "title" : "Hackers And Painters",
    "author" : "Paul Graham"
} ]
   ObjectMapper objectMapper = new ObjectMapper();
    List<Book> bookList = objectMapper.readValue(jsonString, ArrayList.class);
    System.out.println("test1:"+bookList);
    System.out.println( bookList.get(0).getBookId());//这步出现问题

现在,如果仔细查看异常消息:“无法将类java.util.LinkedHashMap强制转换为类… Book”,可能会出现两个问题。

已经声明了类型为List 的bookList变量,但是为什么Jackson尝试将LinkedHashMap类型转换为Book类呢?此外,LinkedHashMap来自何处?

首先,实际上声明了类型为List 的bookList。但是,当我们调用objectMapper.readValue()方法时,我们将ArrayList.class传递为Class对象。因此,Jackson会将JSON内容反序列化为ArrayList对象,但不知道ArrayList对象中应该包含哪种类型的元素。

其次,当Jackson尝试在JSON中反序列化对象时,但未提供目标类型信息时,它将使用默认类型:LinkedHashMap。换句话说,反序列化之后,我们将获得一个ArrayList 对象。在地图中,键是属性的名称,例如“ bookId”,“ title”等。这些值是相应属性的值:

在这里插入图片描述

3.将TypeReference传递给objectMapper.readValue()

要解决该问题,需要以某种方式让Jackson知道元素的类型。 但是,编译器不允许我们执行诸如objectMapper.readValue(jsonString,ArrayList .class)之类的操作。

相反,可以将TypeReference对象传递给objectMapper.readValue(String content,TypeReference valueTypeRef)方法。 在这种情况下,我们只需要传递新的TypeReference <List >(){}作为第二个参数:

ObjectMapper objectMapper = new ObjectMapper();
List<Book> bookList = objectMapper.readValue(jsonString, new TypeReference<List<Book>>() {});
System.out.println("test2:"+bookList);
  System.out.println( bookList.get(0).getBookId());

4.将JavaType传递给objectMapper.readValue()

在上一节中,传递Class对象或TypeReference对象作为第二个参数来调用objectMapper.readValue()方法。

objectMapper.readValue()方法仍然接受JavaType对象作为第二个参数。 JavaType是类型标记类的基类。 反序列化器将使用它,以便反序列化器知道反序列化过程中的目标类型。

可以通过TypeFactory实例构造一个JavaType对象,并且可以从objectMapper.getTypeFactory()中检索TypeFactory对象。

在此示例中,要具有的目标类型是ArrayList 。 因此,我们可以按照以下要求构造一个CollectionType:

objectMapper.getTypeFactory().constructCollectionType(ArrayList.class, Book.class);
 ObjectMapper objectMapper = new ObjectMapper();
 CollectionType listType  = objectMapper.getTypeFactory().constructCollectionType(ArrayList.class, Book.class);
 List<Book> bookList = objectMapper.readValue(jsonString, listType);
 System.out.println("test4:"+bookList);
 System.out.println( bookList.get(0).getBookId());

5.使用JsonNode对象和objectMapper.convertValue()方法

上面已经看到了将TypeReference或JavaType对象传递给objectMapper.readValue()方法的解决方案。

另外,可以在Jackson中使用树模型节点,然后通过调用objectMapper.convertValue()方法将JsonNode对象转换为所需的类型。

同样,可以将TypeReference或JavaType对象传递给objectMapper.convertValue()方法。

ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(jsonString);
List<Book> bookList = objectMapper.convertValue(jsonNode,
objectMapper.getTypeFactory().constructCollectionType(ArrayList.class, Book.class));
System.out.println("test2:"+bookList);
System.out.println( bookList.get(0).getBookId());

6.创建通用的反序列化方法

到目前为止,已经解决了在将JSON数组反序列化为Java集合时如何解决类转换问题。 在现实世界中,可能想创建一个通用方法来处理不同的元素类型。

可以在调用objectMapper.readValue()方法时传递一个JavaType对象:

  public static <T> List<T> jsonArrayToList(String json, Class<T> elementClass) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        CollectionType listType =
                objectMapper.getTypeFactory().constructCollectionType(ArrayList.class, elementClass);
        return objectMapper.readValue(json, listType);
    }

为什么不使用TypeReference方法来构建通用方法,因为它看起来更紧凑?

现在,创建一个通用实用程序方法,并将相应的TypeReference对象传递给objectMapper.readValue()方法:

 public static <T> List<T> jsonArrayToList(String json, Class<T> elementClass) throws IOException {
        return new ObjectMapper().readValue(json, new TypeReference<List<T>>() {});
    }

运行结果:

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.example.demo.web.Testb$Book

将TypeReference对象传递给readValue()方法,并且以前已经看到这种方法可以解决类转换问题。 那么,为什么在这种情况下会看到相同的异常?

这方法是通用的。 即使使用类型参数T传递TypeReference实例,也无法在运行时对类型参数T进行验证。
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
java.util.LinkedHashMap不能强制转换为类的原因是它们是两个不同的类型。强制转换是指将一个对象从一个类类型转换为另一个类类型。然而,java.util.LinkedHashMap和特定的类之间没有继承或实现关系,所以无法进行强制转换。因此,在你的代码中尝试将java.util.LinkedHashMap对象转换为特定类时,会出现java.lang.ClassCastException异常。 要解决这个问题,你可以通过检查和调整代码,确保将正确的对象类型分配给正确的类。如果你需要将java.util.LinkedHashMap对象转换为特定类,你应该使用适当的方法或构造函数来创建新的特定类的实例,并将java.util.LinkedHashMap对象的值传递给它。 参考资料: <span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [java.lang.ClassCastException:java.util.LinkedHashMap不能转换为实体类异常](https://blog.csdn.net/Ai_Ting_Java/article/details/100987125)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [java.util.LinkedHashMap中不能被强制转换为DataList控件](https://blog.csdn.net/weixin_36163672/article/details/118834879)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值