Unable to inject EJBTransactionRolledbackException - spring

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

How to use #ControllerAdvice to handle webclient errors from the reactive stack (web flux -> spring)

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

what is the usage of extending ResponseEntityExceptionHandler?

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() {
...
}
}

#ControllerAdvice not throwing exception

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) {..}

Required parameters exception doesn't work in spring boot 2.x

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).

Spring MVC - calling methods in #ResponseBody

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

Resources