overridden handleMethodArgumentNotValid method of ResponseEntityExceptionHandler not called - spring

I am trying to have a custom validator and also an ExceptionHandler for my spring boot rest service and when I added ExceptionHandler, the validation errors are not being sent to the UI. So I tried to override handleMethodArgumentNotValid method and that does not work either. Can someone give some insight into this?
This is how I have configured my validation class in the controller -
package services.rest.controller;
import java.io.IOException;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import lombok.extern.slf4j.Slf4j;
import services.rest.model.TestInput;
import services.rest.validator.DataValidator;
#RestController
#RequestMapping("/test")
#Slf4j
public class RestResource {
#Autowired
private DataValidator validator;
#PostMapping("/create")
public String create(#Valid final TestInput input) throws IOException {
log.debug(input.toString());
return "Success";
}
#InitBinder()
public void init(final WebDataBinder binder) {
binder.addValidators(validator);
}
}
This is my ExceptionHandler code -
package services.rest.exceptionhandler;
import java.util.ArrayList;
import java.util.List;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
#SuppressWarnings({ "unchecked", "rawtypes" })
#ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(Exception.class)
public final ResponseEntity<Object> handleAllExceptions(final Exception ex, final WebRequest request) {
System.out.println("All exceptions Method getting executed!!!!");
final List<String> details = new ArrayList<>();
details.add(ex.getLocalizedMessage());
return new ResponseEntity("Server Error", HttpStatus.INTERNAL_SERVER_ERROR);
}
#Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(final MethodArgumentNotValidException ex,
final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
System.out.println("Validation Error Method getting executed!!!!");
final List<String> details = new ArrayList<>();
for (final ObjectError error : ex.getBindingResult().getAllErrors()) {
details.add(error.getDefaultMessage());
}
return new ResponseEntity("Validation Error", HttpStatus.BAD_REQUEST);
}
}
Initially did not override "handleMethodArgumentNotValid" method. Now after overriding it too, it does not work

Did you check the stack trace, it can be possible that instead of MethodArgumentNotValid exception, ConstraintViolation exception is getting raised. Spring doen not provide any default handler for that.

I tested your example and seems to work. Would be helpful if you would also post TestInput and DataValidator.
Doesn't work doesn't say precisely what happened, my guess is that you just received a 400 status code. If that is the case it might be just because the validation is trigger before but you did not override ResponseEntity<Object> handleBindException(final BindException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request)

The following approach worked for me:
import java.util.ArrayList;
import java.util.List;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
#Order(Ordered.HIGHEST_PRECEDENCE)
#ControllerAdvice
public class GlobalExceptionHandler {
#ExceptionHandler(Exception.class)
public ResponseEntity<Object> handleAllExceptions(final Exception ex, final WebRequest request) {
System.out.println("All exceptions Method getting executed!!!!");
final List<String> details = new ArrayList<>();
details.add(ex.getLocalizedMessage());
return new ResponseEntity("Server Error", HttpStatus.INTERNAL_SERVER_ERROR);
}
#ExceptionHandler(MissingServletRequestParameterException.class)
protected ResponseEntity<Object> handleMethodArgumentNotValid(final Exception ex, final WebRequest request) {
System.out.println("Validation Error Method getting executed!!!!");
final List<String> details = new ArrayList<>();
details.add(ex.getLocalizedMessage());
return new ResponseEntity("Validation Error", HttpStatus.BAD_REQUEST);
}
}
Basically what I did was:
Not extending from ResponseEntityExceptionHandler class.
Put the #Order(Ordered.HIGHEST_PRECEDENCE).
Create a handler for the exception MissingServletRequestParameterException.
Hope this help you

Define your exception handler pakcage in #ComponentScan in App class.
#SpringBootApplication
#ComponentScan(basePackages = { "services.rest.exceptionhandler" })
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}

Related

AuthenticationManager.authenticate method not getting called

I am trying to follow the API Key authentication code from this answer:
https://stackoverflow.com/a/48448901
I created my filter class:
package com.propfinancing.CADData.web;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.LoggerFactory;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
public class PullAPIKeyFromHeaderFilter extends AbstractPreAuthenticatedProcessingFilter {
private String apiKeyHeaderName;
public PullAPIKeyFromHeaderFilter(String apiKeyHeaderName) {
this.apiKeyHeaderName = apiKeyHeaderName;
}
#Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
String headerValue = request.getHeader(apiKeyHeaderName);
return request.getHeader(headerValue);
}
#Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
return apiKeyHeaderName;
}
}
And then I implemented my security configuration:
package com.propfinancing.CADData.web;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
#Configuration
#EnableWebSecurity
#Order(1)
public class APIKeySecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${caddata.apiKey.header.name}")
private String apiKeyHeaderName;
#Value("${caddata.apiKey}")
private String apiKey;
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
PullAPIKeyFromHeaderFilter pullAPIKeyFromHeaderfilter = new PullAPIKeyFromHeaderFilter(apiKeyHeaderName);
AuthenticationManager authManager = new AuthenticationManager() {
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String principal = (String) authentication.getPrincipal();
if (!apiKey.equals(principal))
throw new BadCredentialsException("Invalid API key");
authentication.setAuthenticated(true);
return authentication;
}
};
pullAPIKeyFromHeaderfilter.setAuthenticationManager(authManager);
httpSecurity.antMatcher("/**");
httpSecurity.addFilter(pullAPIKeyFromHeaderfilter);
httpSecurity.requiresChannel().anyRequest().requiresSecure();
httpSecurity.csrf().disable();
httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry urlAuthConfigurer = httpSecurity.authorizeRequests();
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.AuthorizedUrl authorizedUrl = urlAuthConfigurer.anyRequest();
authorizedUrl.authenticated();
}
}
When I do an external call to the application with the header as part of the request, I get a 403 Forbidden response.
I can see the filter pulling the key from the header. That part is working.
But, the authenticate() method is not being called to check if the header is valid.
I am not sure what I missed, the code looks the same to me.
Any ideas?
Looks like the wrong base class, per https://docs.spring.io/spring-security/site/docs/4.0.x/apidocs/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.html :
The purpose is then only to extract the necessary information on the
principal from the incoming request, rather than to authenticate them.
Try extending https://docs.spring.io/spring-security/site/docs/4.0.x/apidocs/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.html instead.
I was not able to get the code above to work, but I changed it to use the second answer on the thread (Using a Filter) https://stackoverflow.com/a/63852212 It works as expected.

Spring-Boot OpenAPI - #RestControllerAdvice not limited to methods throwing the Exception

I need to document my SpringBoot APIs and their possible exceptions with OpenAPI,
and I am using SpringDoc-OpenAPI https://springdoc.org/.
To handle the NotFound cases I created this exception class:
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
public class NotFoundException extends ResponseStatusException {
public NotFoundException() {
super(HttpStatus.NOT_FOUND);
}
}
and this #RestControllerAdvice
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
#RestControllerAdvice
public class GlobalControllerExceptionHandler {
#ExceptionHandler(NotFoundException.class)
#ResponseStatus(HttpStatus.NOT_FOUND)
public ResponseEntity<String> handleNotFoundException(RuntimeException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
}
}
The problem I am facing is that the generated OpenAPI yaml file has
responses:
"404":
description: Not Found
content:
'*/*':
schema:
type: string
for all #RestController endpoints, instead of only for the methods with throws NotFoundException.
How can I limit the #ControllerAdvice (or the OpenAPI), to generate the 404 Response documentation only for methods with the throwing signature?
Do I need to use something else other than the #RestControllerAdvice?
I would like to avoid having to annotate every single method.
A possible solution is to:
Make the #RestControllerAdvice #Hidden
Provide an OperationCustomizer #Bean
import io.swagger.v3.oas.annotations.Hidden;
import it.eng.cysec.ot.risk.assessment.api.exceptions.NotFoundException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
#Hidden
#RestControllerAdvice
public class GlobalControllerExceptionHandler {
#ExceptionHandler(NotFoundException.class)
#ResponseStatus(HttpStatus.NOT_FOUND)
public ResponseEntity<String> handleNotFoundException(NotFoundException exception) {
return new ResponseEntity<>(exception.getMessage(), HttpStatus.NOT_FOUND);
}
}
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.media.Content;
import io.swagger.v3.oas.models.media.MediaType;
import io.swagger.v3.oas.models.media.StringSchema;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
import it.eng.cysec.ot.risk.assessment.api.exceptions.NotFoundException;
import org.springdoc.core.customizers.OperationCustomizer;
import org.springframework.web.method.HandlerMethod;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
public class OperationResponseCustomizer implements OperationCustomizer {
public static final ApiResponse NOT_FOUND_API_RESPONSE;
static {
MediaType mediaType = new MediaType();
mediaType.setSchema(new StringSchema());
Content content = new Content();
content.addMediaType("*/*", mediaType);
NOT_FOUND_API_RESPONSE = new ApiResponse()
.description("Not Found")
.content(content);
}
/**
* Customize operation.
*
* #param operation input operation
* #param handlerMethod original handler method
* #return customized operation
*/
#Override
public Operation customize(Operation operation, HandlerMethod handlerMethod) {
Method method = handlerMethod.getMethod();
List<Class<?>> exceptions = Arrays.asList(method.getExceptionTypes());
if(exceptions.contains(NotFoundException.class)){
ApiResponses apiResponses = operation.getResponses();
apiResponses.addApiResponse("404", NOT_FOUND_API_RESPONSE);
}
return operation;
}
}

How to pass request parameters as-is between REST service calls in a Spring Boot services application?

We are doing an architectural refactoring to convert a monolithic J2EE EJB application to Spring services. In order to do that I'm creating services by breaking the application against the joints of its domain. Currently, I have three of them and each calls another service via Rest.
In this project our ultimate purpose is transforming the application to microservices, but since cloud infrastructure isn't clear and probably won't be possible, we decided to make it this way and thought that since services using Rest, it will be easy to make the transform in future.
Does our approach makes sense? My question stems from this.
I send a request to UserService with a header parameter, userName from Postman.
GET http://localhost:8087/users/userId?userName=12345
UserService calls another service which calls another. Rest call order between services is this:
UserService ---REST--> CustomerService ---REST--> AlarmService
Since I'm doing the work of carrying the common request parameters like this right now, I need to set common header parameters in every method that making Rest requests by taking them from incoming request to outgoing request:
#RequestMapping(value="/users/userId", method = RequestMethod.GET)
public ResponseEntity<Long> getUserId(#RequestHeader("userName") String userName) {
...
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList
(MediaType.APPLICATION_JSON));
headers.set("userName", userName);
HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
HttpEntity<Long> response =
restTemplate.exchange(CUSTOMER_REST_SERVICE_URI,
HttpMethod.GET, entity, Long.class);
...
}
UserService:
package com.xxx.userservice.impl;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.Collections;
import java.util.Map;
#RestController
public class UserController extends AbstractService{
Logger logger = Logger.getLogger(UserController.class.getName());
#Autowired
private RestTemplate restTemplate;
private final String CUSTOMER_REST_SERVICE_HOST = "http://localhost:8085";
private final String CUSTOMER_REST_SERVICE_URI = CUSTOMER_REST_SERVICE_HOST + "/customers/userId";
#RequestMapping(value="/users/userId", method = RequestMethod.GET)
public ResponseEntity<Long> getUserId(#RequestHeader("userName") String userName) {
logger.info(""user service is calling customer service..."");
try {
//do the internal customer service logic
//call other service.
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList
(MediaType.APPLICATION_JSON));
headers.set("userName", userName);
HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
HttpEntity<Long> response =
restTemplate.exchange(CUSTOMER_REST_SERVICE_URI,
HttpMethod.GET, entity, Long.class);
return ResponseEntity.ok(response.getBody());
} catch (Exception e) {
logger.error("user service could not call customer service: ", e);
throw new RuntimeException(e);
}
finally {
logger.info("customer service called...");
}
}
}
CustomerService:
package com.xxxx.customerservice.impl;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.xxx.interf.CustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class CustomerController extends AbstractService{
private final String ALARM_REST_SERVICE_HOST = "http://localhost:8086";
private final String ALARM_REST_SERVICE_URI = ALARM_REST_SERVICE_HOST + "/alarms/maxAlarmCount";
#Autowired
private CustomerService customerService;
#Autowired
private RestTemplate restTemplate;
...
#GetMapping(path="/customers/userId", produces = "application/json")
public long getUserId(#RequestHeader(value="Accept") String acceptType) throws RemoteException {
//customer service internal logic.
customerService.getUserId();
//customer service calling alarm service.
return restTemplate.getForObject(ALARM_REST_SERVICE_URI, Long.class);
}
}
AlarmService:
package com.xxx.alarmservice.impl;
import com.xxx.interf.AlarmService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class PriceAlarmController extends AbstractService{
#Autowired
private AlarmService priceAlarmService;
#RequestMapping("/alarms/maxAlarmCount")
public long getMaxAlarmsPerUser() {
// alarm service internal logic.
return priceAlarmService.getMaxAlarmsPerUser();
}
}
I have tried these config and interceptor files but i can use them just for logging and can't transfer header parameters by using them. Probably because each service has them. And also, this interceptor only works in UserService which first uses RestTemplate to send request. Called service and first request which is coming from Postman doesn't work with it because they doesn't print any log message like UserService does.
CommonModule:
package com.xxx.common.config;
import com.xxx.common.util.HeaderRequestInterceptor;
import org.apache.cxf.common.util.CollectionUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.List;
#Configuration
public class RestTemplateConfig {
#Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
List<ClientHttpRequestInterceptor> interceptors
= restTemplate.getInterceptors();
if (CollectionUtils.isEmpty(interceptors)) {
interceptors = new ArrayList<>();
}
interceptors.add(new HeaderRequestInterceptor());
restTemplate.setInterceptors(interceptors);
return restTemplate;
}
}
ClientHttpRequestInterceptor:
package com.xxx.common.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpRequest;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.StreamUtils;
import java.io.IOException;
import java.nio.charset.Charset;
public class HeaderRequestInterceptor implements ClientHttpRequestInterceptor {
private final Logger log = LoggerFactory.getLogger(this.getClass());
#Override
public ClientHttpResponse intercept(
HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution) throws IOException
{
log.info("HeaderRequestInterceptor....");
logRequest(request, body);
request.getHeaders().set("Accept", MediaType.APPLICATION_JSON_VALUE);
ClientHttpResponse response = execution.execute(request, body);
logResponse(response);
return response;
}
private void logRequest(HttpRequest request, byte[] body) throws IOException
{
log.info("==========request begin=======================");
}
private void logResponse(ClientHttpResponse response) throws IOException
{
log.info("==========response begin=============");
}
}
How can I manage the passing of common header information like userName by using some kind of interceptors or other mechanism in single place?
In your HeaderRequestInterceptor's intercept method, you can access the current http request and its headers (userId in your case) in the following way:
#Override
public ClientHttpResponse intercept(HttpRequest request..
...
HttpServletRequest httpServletRequest = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
String userId = httpServletRequest.getHeader("userId");
request.getHeaders().set("userId", userId);

How to redirect to other site from onApplicationEvent() in spring boot application

I have a class:
#Component
public class AuthenticationSuccessListener implements ApplicationListener<InteractiveAuthenticationSuccessEvent>
and method which is void:
#Override
public void onApplicationEvent(InteractiveAuthenticationSuccessEvent arg0)
I would like to redirect to other site
if(daysBetweenLocalDates(LocalDate.now(), operator.getDateOfChangePassword()) >= 30)
{
System.out.println("###DEB forcing operator to change pass because date of change pass is: " + operator.getDateOfChangePassword());
ModelAndView mav = new ModelAndView();
mav.setViewName("redirect:/changePassword");
}
but I need return mav; and there is problem since onApplicationEvent is void. How can I redirect user to another website from that method?
As #Brian Clozel suggested Handler works great!
So I made a handler:
package local.vlex.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
#Component
public class VlexAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
response.sendRedirect("/changePassword");
}
}
and used it in WebSecurityConfig:
#Autowired
VlexAuthenticationSuccessHandler successHandler;
then:
.formLogin().loginPage("/login").permitAll().successHandler(successHandler)
Thank you #Brian Clozel!

Spring-Boot - Error Handling

I'm trying to write error handler in Spring-Boot for my controllers that would catch most possible errors (Spring, sql etc.). So far I'm able to get JSON response with Nulls however i'm unable to put any data inside. When I try to get error message in I just receive a blank page.
import java.io.IOException;
import java.sql.SQLException;
import javax.servlet.http.HttpServletRequest;
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException;
#RestController
public class BasicErrorController implements ErrorController {
private static final String ERROR_PATH = "/error";
#RequestMapping(value=ERROR_PATH)
#ExceptionHandler(value = {NoSuchRequestHandlingMethodException.class, SQLException.class, IOException.class, RuntimeException.class, Exception.class})
public ErrorBody defaultErrorHandler(HttpServletRequest request, Exception e) {
ErrorBody eBody = new ErrorBody();
eBody.setMessage(e.getCause().getMessage());
return eBody;
}
}
import lombok.Getter;
import lombok.Setter;
#Getter
#Setter
public class ErrorBody {
private String dateTime;
private String exception;
private String url;
private String message;
}
Yo can do something like this:
#ControllerAdvice
public class ControllerExceptionTranslator {
#ExceptionHandler(EntityNotFoundException.class)
#ResponseStatus(HttpStatus.NOT_FOUND)
#ResponseBody
SimpleErrorMessage handleException(EntityNotFoundException exception){
log.debug("Entity Not Found Exception {}",exception.getMessage());
log.trace(exception.getMessage(),exception);
return new SimpleErrorMessage("Entity not found","This resource was not found");
}
#ExceptionHandler({UsernameNotFoundException.class})
#ResponseStatus(HttpStatus.UNAUTHORIZED)
#ResponseBody
SimpleErrorMessage handleException(UsernameNotFoundException exception){
log.debug("Username not found {}",exception.getLocalizedMessage());
log.trace(exception.getMessage(),exception);
return new SimpleErrorMessage("Unaouthorized"," ");
}
}
I was able to get to data about errors and send them as json properly by using "HttpServletRequest request" and reading information from request.
#RequestMapping(value = ERROR_PATH)
public ErrorBody defaultErrorHandler(HttpServletRequest request) {....}
Here this is an example of #ExceptionHandler(Exception.class)
https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
You can use #ControllerAdvice
package demo.controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
#ControllerAdvice
public class ExceptionControllerAdvice {
#InitBinder
public void initBinder(WebDataBinder binder) {
System.out.println("controller advice: init binder");
}
#ExceptionHandler(Exception.class)
public String exception(Exception e) {
System.out.println("controller advice: exception Handler");
System.out.println(e.getMessage());
return "error";
}
#ModelAttribute
public void modelAttribute(){
System.out.println("controller advice:model Attribute");
}
}

Resources