Spring-Web发送请求时报错 “No HttpMessageConverter for java.util.HashMap”

蔚和风
2023-12-01

 
总结

遇到这个报错是因为: Spring-Web 的RestTemplate$HttpEntityRequestCallback.doWithRequest 发起请求时, 需要一个对应的转换器 转换body对象。如果传入的是Map,则可以通过引入Jackson依赖包来做转换。

下面是排查过程


通报错日志发现 发起http请求请求的地方报错:
org.springframework.web.client.RestClientException: No HttpMessageConverter for java.util.HashMap
        at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:961)
        at com.llljjj.commons.jwt.JwtRestTemplate.getToken(JwtRestTemplate.java:166)
        at com.llljjj.commons.jwt.JwtRestTemplate.getAccessToken(JwtRestTemplate.java:146)
        at com.llljjj.commons.jwt.JwtRestTemplate.createRequest(JwtRestTemplate.java:96)
        at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:735)
        at com.llljjj.commons.jwt.JwtRestTemplate.doExecute(JwtRestTemplate.java:71)
        at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:674)
        at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:342)
        at com.llljjj.xxxmmm.util.JWTUtil.jwtQuery(JWTUtil.java:74)
        at com.llljjj.xxxmmm.util.JWTUtil.jwtQuery(JWTUtil.java:65)
        at com.llljjj.xxxmmm.util.JWTUtil.jwtQueryList(JWTUtil.java:148)
        at com.llljjj.xxxmmm.util.JWTUtil.queryWhoisRecord(JWTUtil.java:263)
        at com.llljjj.xxxmmm.util.ExportUtil.packageIcpWhois(ExportUtil.java:127)
        at com.llljjj.xxxmmm.util.ExportUtil.exportADomain(ExportUtil.java:85)
        at com.llljjj.xxxmmm.service.task.DomainTask.parseDomain(DomainTask.java:202)
        at com.llljjj.xxxmmm.service.task.DomainTask.run(DomainTask.java:85)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.lang.Thread.run(Thread.java:748)
        
发起请求的项目代码
RequestCallback requestCallback = httpEntityCallback(getAuthenticateMap(), Object.class);
ClientHttpRequest request = super.createRequest(url, method);
requestCallback.doWithRequest(request);

查看 doWithRequest方法 spring-web的源码
org.springframework.web.client.RestTemplate.HttpEntityRequestCallback#doWithRequest

该方法中 会通过获取 getMessageConverters()中的转换器,依次判断能否 转换Body 中的对象,判断代码如下:
Type requestBodyType = (this.requestEntity instanceof RequestEntity ?
        ((RequestEntity<?>)this.requestEntity).getType() : requestBodyClass);
if (genericConverter.canWrite(requestBodyType, requestBodyClass, requestContentType)) {
并写入请求的Body中
genericConverter.write(requestBody, requestBodyType, requestContentType, httpRequest);
如果所有的转换器都不能转化,则会报上面的错误。


由于请求包装的body getAuthenticateMap() 是一个map,报错信息 No HttpMessageConverter for java.util.HashMap ,也显示无法转化的是Map对象。
所以 针对map类型的转换器 应该有缺失。


        
调试正常和异常的代码

获取转换器 可以见到缺少 MappingJackson2HttpMessageConverter 转换器
正常:
getMessageConverters() = {ArrayList@4965}  size = 6
 0 = {ByteArrayHttpMessageConverter@4967} 
 1 = {StringHttpMessageConverter@4968} 
 2 = {ResourceHttpMessageConverter@4969} 
 3 = {SourceHttpMessageConverter@4970} 
 4 = {AllEncompassingFormHttpMessageConverter@4971} 
 5 = {Jaxb2RootElementHttpMessageConverter@4972} 

异常:
getMessageConverters() = {ArrayList@4941}  size = 7
 0 = {ByteArrayHttpMessageConverter@5122} 
 1 = {StringHttpMessageConverter@5123} 
 2 = {ResourceHttpMessageConverter@5124} 
 3 = {SourceHttpMessageConverter@5125} 
 4 = {AllEncompassingFormHttpMessageConverter@5126} 
 5 = {Jaxb2RootElementHttpMessageConverter@5127} 
 6 = {MappingJackson2HttpMessageConverter@5128} 
 
 
排查spring-web 源码:
RestTemplate的构造函数 根据 jackson2Present 来设置该转换器
if (jackson2Present) {
    this.messageConverters.add(new MappingJackson2HttpMessageConverter());
}
 
RestTemplate 的静态函数
判断jackson2Present 的值,是根据是否有存在以下两个类来设置
jackson2Present =
                ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
                        ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);

两个类分别属于两个jackson的jar包
com.fasterxml.jackson.databind.ObjectMapper  属于jar包 jackson-databind-2.9.0.pr3.jar
com.fasterxml.jackson.core.JsonGenerator 属于jar包 jackson-core-2.9.0.pr3.jar

排查到jar确实没有引入,因为最近在做安全升级,有同事把这两个jar包删除了,遗漏引入新的jar包。
重新引入了 Jackson 2.12.4版本的jar包。可以正常转换 Map 类型Body 的请求。
 

 类似资料: