SonarLint: вернуть пустую коллекцию вместо нуля - PullRequest
0 голосов
/ 29 января 2020

Я делаю ajax вызов метода, который возвращает список объектов, если что-то происходит во время получения данных в блоке try-catch, у меня есть response.setStatus(400), чтобы затем показать ошибку в переднем конец, также там я возвращаю ноль, там я получаю уведомление SonarLint. Теперь, если я изменю это на пустую коллекцию, я получу ошибку ниже:

getWriter() has already been called for this response

Я думаю, что выше, потому что я возвращаю пустую коллекцию и статус ответа 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;        
}

Есть идеи, как исправить это уведомление?

Ответы [ 2 ]

1 голос
/ 29 января 2020

Я бы порекомендовал не перехватывать исключение в этом методе, а вместо этого бросить его и использовать для обработки обработчик исключений в вашем контроллере. В этом случае вы никогда не вернете null из метода, и Сонар не будет на что жаловаться. Это также будет означать, что вы используете 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 из обычного метода после переключения на обработчик исключений.

0 голосов
/ 29 января 2020

Я бы порекомендовал вам создать 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-Create ErrorPayload Class

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

    private String errorMessage;
    private String errorType;

//Getters and Setters and Constructors
}

3-Create ExceptionConverter Service (Используется, когда у нас есть исключение)

@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);
    }

}

Примеры для двух сценариев ios (сначала без Ион и второй за исключением)

Образец 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"
        }
    ]
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...