I am not able to inject EJBTransactionRolledbackException. I want to catch ConstraintViolationException. So first I need catch EJBTransactionRolledbackException then I can propagate to ConstraintViolationException exception using getCause().
How to inject it?
Below is my code.
#ControllerAdvice
public class RestExceptionProcessor extends ResponseEntityExceptionHandler {
// Here I am not able to inject EJBTransactionRolledbackException.
#ExceptionHandler({EJBTransactionRolledbackException.class})
protected ResponseEntity<Object> handleUniqueKeyViolation(EJBTransactionRolledbackException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
Throwable t = ex.getCause();
if(t != null &(t instanceof RollbackException)){
if(t != null &(t instanceof ConstraintViolationException)) {
return handleConstraintViolation((ConstraintViolationException) ex.getCause(), headers, status, request);
}
return handleConstraintViolation((RollbackException) ex.getCause(), headers, status, request);
}
String error = ex.getLocalizedMessage() + " " + ex.getMessage();
ApiError apiError = new ApiError(HttpStatus.BAD_REQUEST, ex.getLocalizedMessage(), error);
return new ResponseEntity<Object>(apiError, new HttpHeaders(), apiError.getStatus());
}
#ExceptionHandler({RollbackException.class})
protected ResponseEntity<Object> handleConstraintViolation(RollbackException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
String error = ex.getLocalizedMessage() + " " + ex.getMessage();
ApiError apiError = new ApiError(HttpStatus.CONFLICT, ex.getLocalizedMessage(), error);
return new ResponseEntity<Object>(apiError, new HttpHeaders(), apiError.getStatus());
}
#ExceptionHandler({ConstraintViolationException.class})
protected ResponseEntity<Object> handleConstraintViolation(ConstraintViolationException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
List<String> errors = new ArrayList<String>();
for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
errors.add(violation.getRootBeanClass().getName() + " " +
violation.getPropertyPath() + ": " + violation.getMessage());
}
ApiError apiError = new ApiError(HttpStatus.CONFLICT, ex.getLocalizedMessage(), error);
return new ResponseEntity<Object>(apiError, new HttpHeaders(), apiError.getStatus());
}
}
And my ApiErrors class is like below:
public class ApiError {
private HttpStatus status;
private String message;
private List<String> errors;
public ApiError(HttpStatus status, String message, List<String> errors) {
super();
this.status = status;
this.message = message;
this.errors = errors;
}
public ApiError(HttpStatus status, String message, String error) {
super();
this.status = status;
this.message = message;
this.errors = Arrays.asList(error);
}
}
Related
I use webclient from weblux to send a request to a remote server. At this point, I can get error 400. I need to intercept it and send it to the client.
webClient
.post()
.uri(
)
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.body(
BodyInserters
.fromFormData()
.with()
.with()
)
.retrieve()
.onStatus(
HttpStatus::isError, response -> response.bodyToMono(String.class) // error body as String or other class
.flatMap(error -> Mono.error(new WrongCredentialsException(error)))
)
.bodyToMono(TResponse.class)
.doOnNext(...);
error
#ControllerAdvice
#Slf4j
public class ApplicationErrorHandler {
#ExceptionHandler(WrongCredentialsException.class)
public ResponseEntity<ErrorResponse> handleResponseException(WrongCredentialsException ex) {
// log.error("Error from WebClient - Status {}, Body {}", ex.getRawStatusCode(), ex.getResponseBodyAsString(), ex);
ErrorResponse error = new ErrorResponse();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(error);
}
#Data
#NoArgsConstructor
#AllArgsConstructor
public class ErrorResponse {
private String errorCode;
private String message;
}
rest api
#PostMapping
public ResponseEntity<String> send(#RequestBody Dto dto) {
log.debug("An notification has been send to user");
return new ResponseEntity<>(HttpStatus.OK);
}
I tried the options from here, but it didn't work out . Can someone explain how it works and how it can be configured for my case?
first case
return Objects.requireNonNull(oauthWebClient
.post()
.uri(uri)
.bodyValue(dto)
.attributes(oauth2AuthorizedClient(authorizedClient))
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.exchangeToMono(response -> {
HttpStatus httpStatus = response.statusCode();
if (httpStatus.is4xxClientError()) {
getErrFromClient(response, httpStatus);
}
if (httpStatus.is5xxServerError()) {
getErrFromServer(response, httpStatus);
}
return Mono.just(ResponseEntity.status(response.statusCode()));
})
.block())
.build();
}
private void getErrFromServer(DtoResponse response, HttpStatus httpStatus) {
String err = response.bodyToMono(String.class).toString();
log.error("HttpStatus: {}, message: {}", httpStatus, err);
HttpHeaders httpHeaders = response.headers().asHttpHeaders();
List<String> errorBody = httpHeaders.get("errBody");
assert errBody != null;
throw new CustomException(
"{ HttpStatus : " + httpStatus + " , message : " + errBody + " }");
}
private void getErrFromClient(DtoResponse response, HttpStatus httpStatus) {
String err = response.bodyToMono(String.class).toString();
log.error("HttpStatus: {}, err: {}", httpStatus, err);
HttpHeaders httpHeaders = response.headers().asHttpHeaders();
List<String> errorBody = httpHeaders.get("errBody");
assert errBody != null;
throw new CustomException(
"{ HttpStatus : " + httpStatus + " , message : " + errBody + " }");
}
and than
#ControllerAdvice
public class HandlerAdviceException {
#ExceptionHandler(CustomException.class)
public ResponseEntity<ErrorResponse> handleCustomException(CustomException e) {
//here your code
//for example:
String errMessage = e.getLocalizedMessage();
return ResponseEntity
.internalServerError()
.body(new ErrorResponse(ErrorCode.INTERNAL_ERROR, errMessage));
}
}
second case
return webClient
.post()
.uri(
properties......,
Map.of("your-key", properties.get...())
)
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.body(
prepare....()
)
.retrieve()
.bodyToMono(TokenResponse.class)
.doOnSuccess(currentToken::set);
}
Here, if successful, you will get the result you need, but if an error occurs, then you only need to configure the interceptor in the Advice Controller for WebClientResponseException.
#ControllerAdvice
#Slf4j
public class CommonRestExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(WebClientResponseException.class)
protected ResponseEntity<ApiErrorResponse> handleWebClientResponseException(WebClientResponseException ex) {
log.error(ex.getClass().getCanonicalName());
String errMessageAdditional = .....
final ApiErrorResponse apiError = ApiErrorResponse.builder()
.message(ex.getLocalizedMessage())
.status(HttpStatus.UNAUTHORIZED)
.build();
//if it needs
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add(.......);
return new ResponseEntity<>(apiError, httpHeaders, apiError.getStatus());
}
}
can some one explain me what is the usage of extending ResponseEntityExceptionHandler. If Ido not extend also ResponseEntityExceptionHandler GlobalExceptionHandler is working and sending the response to client.
#ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler{
#ExceptionHandler({ UserNotFoundException.class, ContentNotAllowedException.class })
public final ResponseEntity<ApiError> handleException(Exception ex, WebRequest request) {
HttpHeaders headers = new HttpHeaders();
if (ex instanceof UserNotFoundException) {
HttpStatus status = HttpStatus.NOT_FOUND;
UserNotFoundException unfe = (UserNotFoundException) ex;
return handleUserNotFoundException(unfe, headers, status, request);
} else if (ex instanceof ContentNotAllowedException) {
HttpStatus status = HttpStatus.BAD_REQUEST;
ContentNotAllowedException cnae = (ContentNotAllowedException) ex;
return handleContentNotAllowedException(cnae, headers, status, request);
} else {
HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
return handleExceptionInternal(ex, null, headers, status, request);
}
}
}
#ControllerAdvice
public class GlobalExceptionHandler{
#ExceptionHandler({ UserNotFoundException.class, ContentNotAllowedException.class })
public final ResponseEntity<ApiError> handleException(Exception ex, WebRequest request) {
HttpHeaders headers = new HttpHeaders();
if (ex instanceof UserNotFoundException) {
HttpStatus status = HttpStatus.NOT_FOUND;
UserNotFoundException unfe = (UserNotFoundException) ex;
return handleUserNotFoundException(unfe, headers, status, request);
} else if (ex instanceof ContentNotAllowedException) {
HttpStatus status = HttpStatus.BAD_REQUEST;
ContentNotAllowedException cnae = (ContentNotAllowedException) ex;
return handleContentNotAllowedException(cnae, headers, status, request);
} else {
HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
return handleExceptionInternal(ex, null, headers, status, request);
}
}
}
ResponseEntityExceptionHandler is used when one is generally satisfied with Spring's default ExceptionHandlers - except for a few, which may then be overridden.
Have a look at all the protected methods in the API documentation: ResponseEntityExceptionHandler
Your GlobalExceptionHandler is already accepting any Exceptions and custom handling two specific Exceptions.
If you insist on using ResponseEntityExceptionHandler, a similar effect may be achieved by extending the class and implementing handleExceptionInternal():
#ControllerAdvice
public class CustomRestExceptionHandler extends ResponseEntityExceptionHandler {
#Override
public handleExceptionInternal() {
...
}
}
I am handling exceptions globally in CustomHandler class. I could see while debugging this class is catching exceptions, but not throwing them to client. Please let me know what i am missing...
#ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(Exception.class)
public final ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request) {
List<String> details = new ArrayList<>();
details.add(ex.getLocalizedMessage());
ErrorResponse error = new ErrorResponse("Server Error", details);
return new ResponseEntity<Object>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
#ExceptionHandler(ConstraintViolationException.class)
public final ResponseEntity<Object> constraintValidationException(
ConstraintViolationException e) {
List<String> details = new ArrayList<>();
for (ConstraintViolation violation : e.getConstraintViolations()) {
details.add(violation.getMessage());
}
ErrorResponse error = new ErrorResponse("Validation Failed", details);
return new ResponseEntity<Object>(error, HttpStatus.BAD_REQUEST);
}
#Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
List<String> details = new ArrayList<>();
for(ObjectError error : ex.getBindingResult().getAllErrors()) {
details.add(error.getDefaultMessage());
}
ErrorResponse error = new ErrorResponse("Validation Failed", details);
return new ResponseEntity(error, HttpStatus.UNPROCESSABLE_ENTITY);
}
Create your own application specific exceptions and handle them. E.g: public class MyAppEx extends RuntimeException {}. Catch the Exception.class and then throw your exception:
try {
// something goes wrong
} catch (Exception e) {
throw new MyAppEx("details of the exception");
}
Replace:
#ExceptionHandler(MyAppEx.class)
public final ResponseEntity<Object> handleAllExceptions(MyAppEx ex, WebRequest request) {..}
In my spring boot application, I tried to handled the Required parameter exception. This question may be duplicated. But the answers posted don't help me.
My controller
#GetMapping("/test")
public ObjectId test(#RequestBody OIdLGroupIds OIdLGroupIds,#RequestParam ObjectId _id){
return videoService.test();
}
My global exception handler is like following.
#RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(Exception.class)
public final ResponseEntity<Object> handleAllExceptions(Exception ex, WebRequest request) {
List<String> details = new ArrayList<>();
details.add(ex.getLocalizedMessage());
ErrorResponse error = new ErrorResponse("Server Error", details);
return new ResponseEntity(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
#ExceptionHandler(NotFoundHandler.class)
public final ResponseEntity<Object> handleRecordNotFoundException(NotFoundHandler ex, WebRequest request) {
Map<String, Object> body = new LinkedHashMap<>();
body.put("timestamp", LocalDateTime.now());
body.put("message", "Record not found");
List<String> details = new ArrayList<>();
details.add(ex.getLocalizedMessage());
ErrorResponse error = new ErrorResponse("Record Not Found", details);
return new ResponseEntity(error, HttpStatus.NOT_FOUND);
}
#Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) {
Map<String, Object> body = new LinkedHashMap<>();
body.put("timestamp", LocalDate.now());
body.put("status", status.value());
Set<String> errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(x -> x.getDefaultMessage())
.collect(Collectors.toSet());
body.put("details", errors);
return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST);
}
}
It doesn't throw any details (Body is blank). But the response status is 400 Bad Request. But when I comment all above codes, it throws default exceptions with body.
I tried this also
#Override
protected ResponseEntity<Object> handleMissingServletRequestParameter(MissingServletRequestParameterException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
String name = ex.getParameterName();
System.out.println(name);
logger.error(name + " parameter is missing");
return super.handleMissingServletRequestParameter(ex, headers, status, request);
}
I have tried in many ways, But no luck. Did I miss anything? Please help me. Thanks in advance.
Empty request body raises HttpMessageNotReadableException.
#RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
#Override
protected ResponseEntity<Object> handleMissingServletRequestParameter(MissingServletRequestParameterException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
String name = ex.getParameterName();
System.out.println(name);
logger.error(name + " parameter is missing");
return super.handleMissingServletRequestParameter(ex, headers, status, request);
}
#Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(
HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
System.out.println(ex.getMessage());
logger.error("Request body is missing");
return super.handleHttpMessageNotReadable(ex, headers, status, request);
}
}
If you allow empty body, use #RequestBody(required = false).
I am Spring MVC beginner and I want to call rest in #ResponseBody. My external node server doesn't react on that method. I don't got message about request in my server console. Without UserRest it works. I would be grateful for your help
#Controller
public class AjaxController {
#RequestMapping(value= "user", method=RequestMethod.GET)
public #ResponseBody String login (){
UserRest ur = new UserRest();
Response r = ur.getUserName(2);
Gson gs = new Gson();
String str = gs.toJson(r);
return str;
}
}
Response getUserName(int userID){
Response response = new Response();
StringBuilder total = new StringBuilder();
try {
URL url = new URL(Properties.SERVER_SECURE_URL + "users/" + userID);
urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setDoOutput(false);
urlConnection.setDoInput(true);
urlConnection.setRequestMethod("GET");
urlConnection.setRequestProperty("Authorization","1Strajk");
response.setMessageCode(urlConnection.getResponseCode());
if(response.getMessageCode()==Response.MESSAGE_OK) {
InputStream in = urlConnection.getInputStream();
BufferedReader r = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = r.readLine()) != null) {
total.append(line);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(!total.toString().isEmpty()){
response.setObject(total.toString());
}
urlConnection.disconnect();
}
return response;
}
I resolve it. I forgot about SSL connection. Before calling rest I called that method:
public class SSLUtils {
public static void trustEveryone() {
try {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new X509TrustManager[]{new X509TrustManager(){
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}}}, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(
context.getSocketFactory());
} catch (Exception e) { // should never happen
e.printStackTrace();
}
}
}