#Order(Ordered.HIGHEST_PRECEDENCE)
#RestControllerAdvice(basePackages = "com.cvresumeproject.cvresumeproject.service.*")
public class RestExceptionHandler {
#ExceptionHandler(value = {CustomNotFoundException.class})
protected ResponseEntity<Object> handleEntityNotFound(CustomNotFoundException exception){
ApiError apiError =new ApiError(HttpStatus.NOT_FOUND);
apiError.setMessage(exception.getMessage());
return new ResponseEntity<>(apiError,apiError.getStatus());
}
}
Main class
#SpringBootApplication
#ComponentScan("com.cvresumeproject.cvresumeproject.ExceptionHandler.RestExceptionHandler")
public class CvresumeprojectApplication {
public static void main(String[] args) {
SpringApplication.run(CvresumeprojectApplication.class, args);
}
}
Using my customnotfoundexception
#Override
public TemplateDto findById(Long id) throws CustomNotFoundException {
return templateMapper.templateToTemplateDto(templateRepository.findById(id).get());
}
My resume project using exceptionhandler but this exception handler not working please help me Thanks!!!
You don't need * in the basePackages element in #RestControllerAdvice. Controllers that belong to the configured base packages or sub-packages thereof will be included, so you don't need the wildcard. Use the following instead:
#RestControllerAdvice(basePackages = "com.cvresumeproject.cvresumeproject.service")
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(value = {CustomNotFoundException.class})
protected ResponseEntity<Object> handleEntityNotFound(Exception exception, WebRequest webRequest) {
HttpStatus errorCode = HttpStatus.NOT_FOUND;
ApiError apiError = new ApiError(errorCode);
apiError.setMessage(exception.getMessage());
return this.handleExceptionInternal(exception, apiError, new HttpHeaders(), errorCode, webRequest);
}
}
Related
#Component
public abstract class CommandBase {
#Autowired
WebServiceProxy nbiService;
#Autowired
OperationCacheRepository cacheRepository;
public CommandBase(
WebServiceProxy nbiService,
OperationCacheRepository cacheRepository) {
this.nbiService = nbiService;
this.cacheRepository = cacheRepository;
}
public abstract void executeSPV(SpeedTestDTO stDTO) throws NBIException;
public abstract long executeGPV(long guid, OperationCache operationCache) throws NBIException;
#Slf4j
public class DownloadDiagnosticsCommand extends CommandBase {
public DownloadDiagnosticsCommand(WebServiceProxy nbiService, OperationCacheRepository cacheRepository) {
super(nbiService, cacheRepository);
}
#Override
public void executeSPV(SpeedTestDTO stDTO) throws NBIException {
// some executable code
}
#Override
public long executeGPV(long guid, OperationCache operationCache) throws NBIException {
// some executable code
}
}
#Slf4j
public class UploadDiagnosticsCommand extends CommandBase {
public UploadDiagnosticsCommand(WebServiceProxy nbiService, OperationCacheRepository cacheRepository) {
super(nbiService, cacheRepository);
}
#Override
public void executeSPV(SpeedTestDTO stDTO) throws NBIException {
// some executable code
}
#Override
public long executeGPV(long guid, OperationCache operationCache) throws NBIException {
//some executable code
}
}
#Component
public class RFACommandFactory {
#Autowired
WebServiceProxy nbiServiceProxy;
#Autowired
OperationCacheRepository cacheRepository;
public final CommandBase createCommand(final String measureType) {
if ("download".equalsIgnoreCase(measureType)) {
return new DownloadDiagnosticsCommand(nbiServiceProxy, cacheRepository);
} else if ("upload".equalsIgnoreCase(measureType)) {
return new UploadDiagnosticsCommand(nbiServiceProxy, cacheRepository);
}
return null;
}
}
Calling method executeSPV from abstract class
#RestController
#RequestMapping("/rfa/speedtest/v1")
#Slf4j
public class Controller {
#Autowired
CommandBase command;
#Autowired
RFACommandFactory rfaCommandFactory;
#PostMapping(value = "{id}", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
private ResponseEntity<String> post(
#PathVariable String assetId,
#RequestBody Payload payload) {
log.info("Received new payload:{}", payload);
command = rfaCommandFactory.createCommand(speedTestDTO.getType());
try {
command.executeSPV(speedTestDTO);
} catch (NBIException e) {
log.info("NBIException", e);
return new ResponseEntity(payload, HttpStatus.BAD_REQUEST);
}
return new ResponseEntity(payload, HttpStatus.CREATED);
}
}
If I remove #Componet from Upload and Download classes I receive error I need to add Bean for abstrcat class CommndBase
If I use #Compoment on Upload and Download classes I receive dual Bean is useed...
Field command in .Controller required a single bean, but 2 were found:
You should not use #Component for abstract class, because Spring context will not be able to initialize that bean. You should remove it then.
Another thing is the way you want to implement a factory pattern here - I recommend you the way described here: https://stackoverflow.com/a/39361500/14056755, refactored version https://stackoverflow.com/a/55060326/14056755.
Have a custom error controller on Spring boot:
package com.example.controllers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.boot.web.servlet.error.ErrorController;
import javax.servlet.http.HttpServletRequest;
#Controller
public class CustomErrorController implements ErrorController
{
#RequestMapping("/error")
public String handleError(HttpServletRequest request)
{
...
}
#Override
public String getErrorPath()
{
return "/error";
}
}
But, when compile says: getErrorPath() in ErrorController has been deprecated. Ok, i found information: use server.error.path property. Ok, add this in application.properties and delete the function, but now says: CustomErrorController is not abstract and does not override abstract method getErrorPath() in ErrorController, ¿need a deprecated function?.
How to made the custom error controller?, the ErrorController requires getErrorPath but it is deprecated, what is the correct alternative?.
Starting version 2.3.x, Spring boot has deprecated this method. Just return null as it is anyway going to be ignored. Do not use #Override annotation if you want to prevent future compilation error when the method is totally removed. You can also suppress the deprecation warning if you want, however, the warning (also the #Override annotation) is helpful to remind you to cleanup/fix your code when the method is removed.
#Controller
#RequestMapping("/error")
#SuppressWarnings("deprecation")
public class CustomErrorController implements ErrorController {
public String error() {
// handle error
// ..
}
public String getErrorPath() {
return null;
}
}
#Controller
public class CustomErrorController implements ErrorController {
#RequestMapping("/error")
public ModelAndView handleError(HttpServletResponse response) {
int status = response.getStatus();
if ( status == HttpStatus.NOT_FOUND.value()) {
System.out.println("Error with code " + status + " Happened!");
return new ModelAndView("error-404");
} else if (status == HttpStatus.INTERNAL_SERVER_ERROR.value()) {
System.out.println("Error with code " + status + " Happened!");
return new ModelAndView("error-500");
}
System.out.println(status);
return new ModelAndView("error");
}
}
there is an #ControllerAdvice annotation
#ControllerAdvice
public class MyErrorController {
#ExceptionHandler(RuntimeException.class)
public String|ResponseEntity|AnyOtherType handler(final RuntimeException e) {
.. do handle ..
}
#ExceptionHandler({ Exception1.class, Exception2.class })
public String multipleHandler(final Exception e) {
}
}
To handle errors, There is no need to define a controller class
implementing an error controller.
To handle errors in your entire application instead of writing
#Controller
public class CustomErrorController implements ErrorController{
#RequestMapping("/error")
public String handleError(HttpServletRequest request)
{
...
}
}
use the below class
#ControllerAdvice
public class myExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(Exception.class)
public final ResponseEntity<YourResponseClass> handleAllExceptions(Exception ex, WebRequest request) {
YourResponseClassexceptionResponse = new YourResponseClass(new Date(), ex.getMessage());// Its an example you can define a class with your own structure
return new ResponseEntity<>(exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
#ExceptionHandler(CustomException.class)
public final ResponseEntity<YourResponseClass> handleAllExceptions(Exception ex, WebRequest request) {
YourResponseClass exceptionResponse = new YourResponseClass(new Date(), ex.getMessage()); // For reference
return new ResponseEntity<YourResponseClass>(exceptionResponse, HttpStatus.INTERNAL_SERVER_ERROR);
}
#ExceptionHandler(BadCredentialsException.class)
public final ResponseEntity<YourResponseClass> handleBadCredentialsException(BadCredentialsException ex, WebRequest request){
YourResponseClass exceptionResponse = new YourResponseClass(new Date(), ex.getMessage());// For refernece
return new ResponseEntity<>(exceptionResponse, HttpStatus.UNAUTHORIZED);
}
}
The class above annoted with #ControllerAdvice acts as custom exception handler and it handles all the expecptions thrown by ur application. In above code sample only three exceptions are showed for understanding. It can handle many exceptions
In your application if there's any exception thrown it will come to this class and send the response back. You can have a customized message and structure as per ur needs.
#Controller
public class AppErrorController implements ErrorController {
#RequestMapping("/error")
public String handleError(HttpServletRequest request) {
Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
if(status != null) {
int statusCode = Integer.valueOf(status.toString());
if (statusCode == HttpStatus.FORBIDDEN.value()) {
return "errorpages/error-403";
} else if (statusCode == HttpStatus.NOT_FOUND.value()) {
return "errorpages/error-404";
} else if (statusCode == HttpStatus.INTERNAL_SERVER_ERROR.value()) {
return "errorpages/error-500";
}
}
return "errorpages/error";
}
}
I have a springboot project with controllers and servies. And a GlobalExceptionHandler like -
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(DataIntegrityViolationException.class)
public ResponseEntity<Object> handle(DataIntegrityViolationException e, WebRequest request) {
....
String requestPath = ((ServletWebRequest)request).getRequest().getRequestURI();
// I am using this requestPath in my output from springboot
...
}
}
Can someone please tell me how to write mock this in my unit test class
((ServletWebRequest)request).getRequest().getRequestURI()
Unfortunately there is no support for subbing final methods in Mockito. You can use a other mocking framework like PowerMock.
I prefer in this cases to eliminate the need of mocking with an protected method:
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
#ExceptionHandler(DataIntegrityViolationException.class)
public ResponseEntity<Object> handle(final DataIntegrityViolationException e, final WebRequest request) {
final String requestPath = getRequestUri(request);
return ResponseEntity.ok().body(requestPath);
}
protected String getRequestUri(final WebRequest request) {
return ((ServletWebRequest) request).getRequest().getRequestURI();
}
}
And anonymous class in test:
public class GlobalExceptionHandlerTests {
private final GlobalExceptionHandler handler = new GlobalExceptionHandler() {
#Override
protected String getRequestUri(final org.springframework.web.context.request.WebRequest request) {
return "http://localhost.me";
};
};
#Test
void test() throws Exception {
final ResponseEntity<Object> handled = handler.handle(new DataIntegrityViolationException(""),
null);
assertEquals("http://localhost.me", handled.getBody());
}
}
I have a Custom exception that handles the expected errors of my program and here is the code.
#ControllerAdvice
#RestController
public class DashboardException {
#ExceptionHandler({Exception.class, IOException.class, ParseException.class, JsonProcessingException.class})
public final ResponseEntity<ErrorDetails> dataNotFoundException(Exception ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails();
errorDetails.setTimestamp(new Date().toString());
errorDetails.setMessage(ex.getMessage());
errorDetails.setPath(request.getDescription(false));
errorDetails.setStatus(HttpStatus.BAD_REQUEST.value());
errorDetails.setError(HttpStatus.BAD_REQUEST);
return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
}
}
My problem is on how to properly unit test this class. This is what I have made so far to make it cover, but with no luck.
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes = { DashboardException.class, TestConfiguration.class, DataController.class })
public class testDashboardException {
private MockMvc mockMvc;
#Autowired
WebApplicationContext wac;
#Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
#Configuration
#EnableWebMvc
public static class TestConfiguration { }
#Controller
#RequestMapping("/tests")
public static class RestProcessingExceptionThrowingController {
#GetMapping(value = "/exception")
public #ResponseBody String find() throws Exception {
throw new Exception("global_error_test");
}
}
#Test
public void testHandleException() throws Exception {
mockMvc.perform(get("/tests/exception"))
.andExpect(new ResultMatcher() {
#Override
public void match(MvcResult result) throws Exception {
result.getResponse().getContentAsString().contains("global_error_test");
}
})
.andExpect(status().isBadRequest());
}
/*
* #Test public void testErrorDetailsValue() {
*
* thrown.expect(Exception.class); thrown.expect(IOException.class);
* thrown.expect(ParseException.class);
* thrown.expect(JsonProcessingException.class);
*
* thrown.expectMessage("Bad Request");
*
* }
*/
}
I only have a little knowledge concerning custom exceptions. What am I missing here? Thanks for any assistance.
I found out how to cover my custom exception. I just included a test on my controller that will fail the endpoint and it did catch an exception and covered my custom exception.
I'm testing my RestController with mockMvc. I have a global RestExceptionHandler to resolve all exceptions. In my RestController I throw custom Exception RequestValidationException like this:
#ApiOperation("Search something")
#RequestMapping(path = "/search", method = RequestMethod.POST)
public CompletableFuture<SomeResponse> search(
#RequestBody #Validated SearchRequest request, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
throw new RequestValidationException(bindingResult);
}
return searchService.search(request);
}
And when i pass empty request it must throw RequestValidationException(bindingResult)
but when i start tests they fall in that place where i throw Exception instead to resolve it.
i try to configure my mockMvc like this:
#RunWith(SpringRunner.class)
public class SearchControllerTest {
private MockMvc mockMvc;
#InjectMocks
protected SearchController searchController;
#MockBean
private SearchService searchService;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(searchController)
.setHandlerExceptionResolvers(getHandlerExceptionResolver())
.build();
}
private HandlerExceptionResolver getHandlerExceptionResolver() {
final StaticApplicationContext applicationContext = new StaticApplicationContext();
applicationContext.registerSingleton("exceptionHandler", RestExceptionHandler.class);
final WebMvcConfigurationSupport webMvcConfigurationSupport = new WebMvcConfigurationSupport();
webMvcConfigurationSupport.setApplicationContext(applicationContext);
return webMvcConfigurationSupport.handlerExceptionResolver();
}
but it doesnt help. i'm getting an Exception insted json with message.
My RequestValidationExceptionHandler:
#Component
public class RequestValidationExceptionHandler implements ApiExceptionHandler {
#Override
public ResponseEntity<ApiResponse> process(Throwable throwable) {
RequestValidationException e = (RequestValidationException) throwable;
if (e.getBindingResult() != null) {
return new ResponseEntity<>(ApiResponse.badRequest(e.getBindingResult()), HttpStatus.OK);
}
return new ResponseEntity<>(ApiResponse.badRequest(throwable, ApiResponseCode.BAD_REQUEST), HttpStatus.OK);
}
#Override
public Class<? extends Throwable> getSupportedException() {
return RequestValidationException.class;
}
}
2) My #ControllerAdvice:
#Slf4j
#ControllerAdvice
#SuppressWarnings({"checkstyle:JavadocMethod", "checkstyle:MultipleStringLiterals"})
public class RestExceptionHandler {
#Autowired
private ExceptionHandlerRegistry handlerRegistry;
#ExceptionHandler
public ResponseEntity handleThrowable(Throwable throwable, WebRequest request) {
request.setAttribute(Constants.ERROR_ATTRIBUTE_NAME, throwable, RequestAttributes.SCOPE_REQUEST);
Throwable ex = throwable instanceof CompletionException ?
ObjectUtils.defaultIfNull(throwable.getCause(), throwable) : throwable;
for (ApiExceptionHandler handler : handlerRegistry.getHandlers()) {
if (handler.isSupported(ex)) {
return handler.process(ex);
}
}
return new ResponseEntity<>(ApiResponse.badRequest(throwable, ApiResponseCode.SERVER_ERROR), HttpStatus.OK);
}
}
3) And ExceptionHandlerRegistry :
#Component
public class ExceptionHandlerRegistry {
#Getter
private final List<ApiExceptionHandler> handlers;
#Autowired
public ExceptionHandlerRegistry(List<ApiExceptionHandler> handlers) {
this.handlers = ObjectUtils.defaultIfNull(handlers, Collections.emptyList());
}
}
The Error message:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is ru.filit.mvideo.mb2c.api.exceptions.RequestValidationException
UPDATE
So after some discussion with #MichaelMichailidis, i try to do this, i just add an inner #Configuration class with needed beans:
#TestConfiguration
static class SearchControllerTestConfiguration {
#Bean
public RequestValidationExceptionHandler requestValidationExceptionHandler(){
return new RequestValidationExceptionHandler();
}
#Bean
public ExceptionHandlerRegistry getExceptionHandlerRegistry(final RequestValidationExceptionHandler requestValidationExceptionHandler){
return new ExceptionHandlerRegistry(Collections.singletonList(requestValidationExceptionHandler));
}
#Bean
public RestExceptionHandler getRestExceptionHandler(){
return new RestExceptionHandler();
}
}
and my test pass. But i can't understand why test were working without configuration before i add #ControllerAdvice?
You can try importing your exception handler in your test class:
#RunWith(SpringRunner.class)
#Import(RestExceptionHandler.class) // EXCEPTION HANDLER CLASS
public class SearchControllerTest {