Java SonarLint:返回空集合而不是null

Java SonarLint:返回空集合而不是null,java,spring-boot,sonarlint,Java,Spring Boot,Sonarlint,我正在对一个返回对象列表的方法进行ajax调用,如果在try-catch块中获取数据时发生了什么,我会有一个响应。setStatus400将在前端显示错误,在那里我返回null,在那里我会收到SonarLint通知。现在,如果我将其更改为空集合,则会出现以下错误: 已为此响应调用getWriter 我认为以上是因为我返回的是空集合和http响应状态400。如果我将其保留为空,则所有操作都可以正常工作,只需SonarLint通知即可 @GetMapping("/runquery") @Respon

我正在对一个返回对象列表的方法进行ajax调用,如果在try-catch块中获取数据时发生了什么,我会有一个响应。setStatus400将在前端显示错误,在那里我返回null,在那里我会收到SonarLint通知。现在,如果我将其更改为空集合,则会出现以下错误:

已为此响应调用getWriter

我认为以上是因为我返回的是空集合和http响应状态400。如果我将其保留为空,则所有操作都可以正常工作,只需SonarLint通知即可

@GetMapping("/runquery")
@ResponseBody
public List<Map<String, Object>> runQuery(@RequestParam(name = "queryId") String queryId, @RequestParam(name = "formData") String formData, HttpServletResponse response) throws IOException {
    (...)

    try {
        queryResult = namedParameterJdbcTemplateHive.queryForList(query, paramSource);

        for (Map<String, Object> map : queryResult) {
            Map<String, Object> newMap = new HashMap<>();
            for (Map.Entry<String, Object> entry : map.entrySet()) {                    
                String key = entry.getKey();
                Object value = entry.getValue();

                if (key.contains(".")) {
                    key = key.replace(".", "_");
                    newMap.put(key, value);
                } else {
                    newMap.put(key, value);
                }
            }
            queryResultFinal.add(newMap);
        }


    } catch (Exception e) {
        response.setStatus(400);
        response.getWriter().write(e.getMessage());
        return null;  <-- SonarLint notification
    }

    return queryResultFinal;        
}

您知道如何修复此通知吗?

我建议不要用此方法捕获异常,而是抛出异常,并使用控制器中的来处理它。在这种情况下,您将永远不会从该方法返回null,Sonar将没有什么可抱怨的。这也意味着您正在按设计使用的方式使用Spring

例如,如下所示:

@ExceptionHandler
@ResponseStatus(HttpStatus.BAD_REQUEST)
public void handleException(Exception e) {
    log.error("Exception during request", e);
}
或直接等同于您当前的处理方式:

@ExceptionHandler
public ResponseEntity<?> handleException(Exception e) {
    return ResponseEntity.badRequest().body(e.getMessage()).build();
}

切换到异常处理程序后,您可以从常规方法中删除HttpServletResponse参数。

我建议您创建一个通用报告来包装所有响应,这对于前端来说也是非常好的,因为您面对的是一个固定的模板

因此,通过这个解决方案,您可以包装您想要的任何对象并将其发送到响应

我对场景进行了如下编码:

1-创建GenericResponse类

3-创建异常时使用的异常转换器服务

4-使用GenericResponse更改场景

您需要做的只是:

创建前面提到的类复制我在1、2和3中编写的代码 将响应表单列表更改为GenericResponse 将您的返回类型包装到GenericResponse中 我改变了你的代码如下只改变3行

@RestController
public class TestController {

    @Autowired
    private ExceptionConverterService exceptionConverter;

    @GetMapping("/runquery")
    @ResponseBody
    //Changed (Change Return type to GenericResponse )
    public GenericResponse runQuery(@RequestParam(name = "queryId") String queryId, @RequestParam(name = "formData") String formData, HttpServletResponse response) throws IOException {


        try {
            //Your code
            }

        } catch (Exception e) {

            //Changed (Create GenericResponse for Exception)
            GenericResponse genericResponse = exceptionConverter.convert(e);
            return genericResponse;
        }

        //Changed (Create GenericResponse for main result)
        return GenericResponse.ok().payload(queryResultFinal);
    }

}
两个场景的示例:第一个没有例外,第二个有例外

样本1

控制器与GenericResponse我们在这个示例中没有例外

@RestController
public class TestController {

    @GetMapping(value = "/getNameAndFamily")
    public GenericResponse getNameAndFamily() {

        Map<String, String> person = new HashMap<>();
        person.put("name", "foo");
        person.put("family", "bar");
        return GenericResponse.ok().payload((Serializable) person);
    }

}
样本2

当我们在业务中遇到异常时,具有一般响应的控制器

@RestController
public class TestController {

    @Autowired
    private ExceptionConverterService exceptionConverter;

    @GetMapping(value = "/getNameAndFamily")
    public GenericResponse getNameAndFamily() {

        try {

            //Create Fake Exception
            int i = 1 / 0;
            return GenericResponse.ok();
        } catch (Exception e) {

            //Handle Exception
            GenericResponse genericResponse = exceptionConverter.convert(e);
            return GenericResponse.ok().payload((Serializable) genericResponse);

        }
    }

}
结果如下:

{
    "error": false,
    "payload": {
        "name": "foo",
        "family": "bar"
    }
}
{
    "error": true,
    "errorPayload": [
        {
            "errorType": "ArithmeticException"
        }
    ]
}
如果在获取try-catch块中的数据时发生问题,我有一个响应。setStatus400-4xx错误用于与客户端相关的问题,您应该返回5xx。也许最好让异常传播并通过@ControllerAdvice连接exceptionmapper这不是Serializable的目的。Serializable用于Java二进制序列化,它既不用于也不需要用于json的序列化。使用Object作为payload方法的参数类型就足够了。
{
    "error": false,
    "payload": {
        "name": "foo",
        "family": "bar"
    }
}
@RestController
public class TestController {

    @Autowired
    private ExceptionConverterService exceptionConverter;

    @GetMapping(value = "/getNameAndFamily")
    public GenericResponse getNameAndFamily() {

        try {

            //Create Fake Exception
            int i = 1 / 0;
            return GenericResponse.ok();
        } catch (Exception e) {

            //Handle Exception
            GenericResponse genericResponse = exceptionConverter.convert(e);
            return GenericResponse.ok().payload((Serializable) genericResponse);

        }
    }

}
{
    "error": true,
    "errorPayload": [
        {
            "errorType": "ArithmeticException"
        }
    ]
}