微服务接口调用空指针问题分析

今天有个动态筛选条件不能正常筛选,估计是没有拿到查询条件。因查询条件是由入参调微服务接口查询拿到的,故先看微服务的producer端日志,发现了个HttpMessageNotWritableException,类型转换失败。

先看日志:

 2021-11-29 15:13:39 [ERROR] userId:108340 c.l.c.b.c.LSControllerAdvice >> 程序产生未知异常:o(╥﹏╥)o 
  ==> 接口地址:/client/customer/regRelation/querySupervisedIds 
  ==> Referer: null
  ==> 请求参数:{"regulatorId":["104323"],"dataFlag":["0"]} 
 org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: (was java.lang.ClassCastException); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.ClassCastException) (through reference chain: java.util.ArrayList[0])
     at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:354)
     at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:104)
     at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:277)
     at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:181)
     at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:78)
     at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:124)
     at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894)
     at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
     at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
     at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1060)
     at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:962)
     at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
     at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
     at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
     at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
     at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
     at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
     at cn.lonsun.core.base.filter.BaseFilter.doFilter(BaseFilter.java:85)
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
     at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:93)
     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
     at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
     at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
     at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
     at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
     at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
     at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
     at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
     at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
     at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
     at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
     at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:888)
     at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1597)
     at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
     at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
     at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
     at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
     at java.base/java.lang.Thread.run(Thread.java:829)
 Caused by: com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.ClassCastException) (through reference chain: java.util.ArrayList[0])
     at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:397)
     at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:368)
     at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:338)
     at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContentsUsing(CollectionSerializer.java:178)
     at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:116)
     at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:107)
     at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25)
     at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
     at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:400)
     at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1512)
     at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1006)
     at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:345)
     ... 47 common frames omitted
 Caused by: java.lang.ClassCastException: null

拿到问题后仔细核对了自己的微服务接口,发现并没有问题。

 @FeignClient(value = "admin-server", contextId = "xxxxxx")
 public interface CustomerRegRelationClient {
     
     @GetMapping(value = "/client/customer/regRelation/querySupervisedIds?dataFlag=0", consumes = MediaType.APPLICATION_JSON_VALUE)
     List<Long> querySupervisedIds(@RequestParam("regulatorId") Long regulatorId);
 ​
 }

故认为返回值类型不能被转换为List<Long>, 分析dao层方法:

 default List<Long> querySupervisedIdList(Long regulatorId) {
     List<Long> supervisedIdList = new ArrayList<>();
     String sql = "select child_organ_id from customer_reg_relation " +
         "where parent_organ_id = :regulatorId";
     Map<String, Object> params = new HashMap<>();
     params.put("regulatorId", regulatorId);
     List<?> objectsBySql = getObjectsBySql(sql, params);
     if (null != objectsBySql && objectsBySql.size() != 0){
         supervisedIdList = (List<Long>) objectsBySql;
     }
     return supervisedIdList;
 }

认为此处强转并没有生效。

强转无泛型集合类的时候,不会生效,需遍历转换。Collection<?>类型的集合,采用强转可以用任意泛型替代问号,强转本身不报错,但实际类型并没有发生变化。

但是postMan单独测试微服务producer端的接口,能正常输出。

分析:强转没有生效,但直接测试接口输出时候,是转化成字符串,并不涉及类型转换,所以不会报错。当使用微服务接口调用时,需要转换数据类型,而(List<Long>)并未强转每个对象,故会报错。

分析后,采用单个类型转换为Long型的方式

此时,考虑数据库类型bigint如何转换为java类型的long。采用Number来进行中间转化。

 default List<Long> querySupervisedIdList(Long regulatorId) {
         List<Long> supervisedIdList = new ArrayList<>();
         String sql = "select child_organ_id from customer_reg_relation " +
                 "where parent_organ_id = :regulatorId";
         Map<String, Object> params = new HashMap<>();
         params.put("regulatorId", regulatorId);
 ​
         List<?> objectsBySql = getObjectsBySql(sql, params);
         if (null != objectsBySql && objectsBySql.size() != 0){
             for (Object o : objectsBySql) {
                 Long l = ((Number) o).longValue();
                 supervisedIdList.add(l);
             }
         }
         return supervisedIdList;
     }

此时,微服务接口能正常访问。

上一篇:C++ - 类的虚函数\虚继承所占的空间


下一篇:spring 定时任务配置