SonarLint:返回一个空集合,而不是null

时间:2020-01-29 15:32:58

标签: java spring-boot sonarlint

我正在对返回一个对象列表的方法进行ajax调用,如果在try-catch块中获取数据时发生了某些事情,我会使用response.setStatus(400)在前面显示错误-最后,我返回的是null,那里是我收到SonarLint通知的地方。现在,如果我将其更改为空集合,则会出现以下错误:

getWriter() has already been called for this response

我认为上面的原因是因为我返回的是空集合,并且http响应状态为400。如果我将其保留为null,那么一切正常,只是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;        
}

关于如何解决此通知的任何想法?

2 个答案:

答案 0 :(得分:1)

我建议不要在此方法中捕获异常,而是将其抛出,并在控制器中使用exception handler method来处理它。在这种情况下,您将永远不会从方法中返回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 response参数。

答案 1 :(得分:0)

我建议您创建一个包含所有响应的 GenericReponse ,这对于前端也非常有用,因为您面对的是固定模板。

因此,通过此解决方案,您可以包装所需的任何对象并将其发送给响应。


我对这种情况进行了编码:

1-创建GenericResponse类

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class GenericResponse {

    private Boolean error;
    private List<ErrorPayload> errorPayload;
    private Object payload;

    public GenericResponse(Boolean error) {
        this.error = error;
    }

    public static GenericResponse ok() {
        return new GenericResponse(false);
    }

     public GenericResponse payload(Serializable o) {
         this.payload = o;
         return this;
     }

    //Getters and Setters and other Constructors

2-创建ErrorPayload类

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class ErrorPayload {

    private String errorMessage;
    private String errorType;

//Getters and Setters and Constructors
}

3-创建ExceptionConverter服务(有异常时使用)

@Service
public class ExceptionConverterService {

    public GenericResponse convert(Exception x) {

        GenericResponse genericResponse = new GenericResponse();
        genericResponse.setError(true);
        String exceptionType = x.getClass().getSimpleName();
        String exceptionMessage = x.getClass().getSimpleName();
        genericResponse.setErrorPayload(Collections.singletonList(new ErrorPayload(exceptionType, exceptionMessage)));
        return genericResponse;

    }

}

4-使用GenericResponse更改您的方案

您需要做的是:

  1. 创建上述类(复制我在1、2和3中编写的代码)
  2. 将您的回复形式List<Map<String, Object>>更改为GenericResponse
  3. 将返回类型包装为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);
    }

}

结果如下:

{
    "error": false,
    "payload": {
        "name": "foo",
        "family": "bar"
    }
}

示例2

当我们在业务中遇到异常时,

带有GenericResponse的控制器

@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"
        }
    ]
}
相关问题