How to get out of this error in spring application - spring

#PostMapping("/addStudent")
String addStudent(#ModelAttribute("student") Students student, Model model) {
studentsRepository.save(student);
return "index";
}
This code is not returning me to the index page, instead giving an error:
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Tue Oct 18 20:32:54 IST 2022
There was an unexpected error (type=Internal Server Error, status=500).

you can try #ControllerAdvice
and #ExceptionHandler
then return your error page
reference docs: https://www.baeldung.com/exception-handling-for-rest-with-spring

Related

Invalid Cookie Header returned by GET controller in both POSTMAN and Insomnia

I have the following Spring controller class:
#CrossOrigin
#RestController
#Slf4j
public class RcmApi extends ApiController {
#Value("${rcmRestApiServer}")
private String rcmRestApiServer;
#GetMapping(value = "/rcm/api/v1/matter/{matterId}", produces = "application/json")
public ResponseEntity<String> getMatter(#PathVariable String matterId) throws Exception {
log.info("Received call to RCM api getMatter: {}", matterId);
return buildGetResponseEntity("/api/v1/cases/" + matterId + "/aggregate");
}
private ResponseEntity<String> buildGetResponseEntity(String target) throws Exception {
return buildResponseEntity(
new HttpGet(rcmRestApiServer + target), HttpClientBuilder.create().build());
}
}
The method buildResponseEntity() referenced by buildGetResponseEntity() is defined in the base class ApiController:
public ResponseEntity<String> buildResponseEntity(HttpUriRequest request, HttpClient client)
throws Exception {
HttpResponse response = client.execute(request);
return ResponseEntity.status(response.getStatusLine().getStatusCode())
.headers(convertHeaders(response.getAllHeaders()))
.body(EntityUtils.toString(response.getEntity()));
}
public HttpHeaders convertHeaders(Header[] responseHeaders) {
HttpHeaders headers = new HttpHeaders();
Arrays.stream(responseHeaders)
.forEach(header -> headers.add(header.getName(), header.getValue()));
return headers;
}
The String matterId that the top-level method getMatter() receives is of form uuid, e.g c445e164-842f-44ec-9e38-6ae3a99fefd8. Unfortunately, when testing this endpoint locally from my POSTMAN at localhost:8084/rcm/api/v1/matter/c445e164-842f-44ec-9e38-6ae3a99fefd8, I notice the following:
POSTMAN receives a 200 OK but with boilerplate HTML source for a redirect page.
More interestingly, the controller thread logs of an "Invalid Cookie Header" at WARN - level:
2022-07-18 20:05:52.331-04:00 INFO 60322 --- [reactor-http-nio-3] o.f.r.caseapi.gateway.controller.RcmApi : Received call to RCM api getMatter: c445e164-842f-44ec-9e38-6ae3a99fefd8
2022-07-18 20:05:56.803-04:00 WARN 60322 --- [reactor-http-nio-3] o.a.h.c.protocol.ResponseProcessCookies : Invalid cookie header: "Set-Cookie: AWSALB=pAa3xa4sTidJy1nU1HKgYZEGx55KVvoCyojb+0FWnPksfr8qSmfBLg052RiLhw7FmhDYzSxzikY7rKIhfisr6YCP08ubdoUcSjJqOf8UcndIpU7q9fQzqM13GTYA; Expires=Tue, 26 Jul 2022 00:05:54 GMT; Path=/". Invalid 'expires' attribute: Tue, 26 Jul 2022 00:05:54 GMT
2022-07-18 20:05:56.804-04:00 WARN 60322 --- [reactor-http-nio-3] o.a.h.c.protocol.ResponseProcessCookies : Invalid cookie header: "Set-Cookie: AWSALBCORS=pAa3xa4sTidJy1nU1HKgYZEGx55KVvoCyojb+0FWnPksfr8qSmfBLg052RiLhw7FmhDYzSxzikY7rKIhfisr6YCP08ubdoUcSjJqOf8UcndIpU7q9fQzqM13GTYA; Expires=Tue, 26 Jul 2022 00:05:54 GMT; Path=/; SameSite=None; Secure". Invalid 'expires' attribute: Tue, 26 Jul 2022 00:05:54 GMT
Thinking that POSTMAN was messing up the request cookie somehow, I have tried the exact same process through INSOMNIA, getting the exact same behavior. Any help appreciated.
Try to prepare your HttpClient like so:
HttpClient httpClient = HttpClients.custom()
.setDefaultRequestConfig(RequestConfig.custom()
.setCookieSpec(CookieSpecs.STANDARD).build())
.build();

401 and 404 error when validation error happen

today I faced an error, I did solve it, but I am having trouble understanding why the error happens that way.
so I was just experimenting with Spring Boot and building a sample application with #RestController, I used "spring-boot-starter-validation" as my user input validation.
my restcontroller endpoint method is like this
#PostMapping("/newEmployee")
#ApiOperation(value = "creates a new employee",
response =EmployeeDTO.class)
public EmployeeDTO newEmployee(#Valid #RequestBody EmployeeDTO newEmployee) {
employeeValidator.validateEmployeeDTO(newEmployee);
return employeeManagementBO.saveOrUpdateEmployee(newEmployee);
}
then I defined a handler method like below
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ExceptionHandler(MethodArgumentNotValidException.class)
//note that if #ResponseBody is not annotated here, you may get weird error like 404 or 401
#ResponseBody
public Map<String, String> handleValidationExceptions(
MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
System.out.println("error caught...");
return errors;
}
so if I remove the #ResponseBody, when I test the endpoint with PostMan, I get error code 404 (but I did debug and saw that the handler method ran), which means that after errors were returned I get 404 error.
however, if I annotate it with #ResponseBody, then everything work as expected and I get a JSON response body back with the expected error structure in a map.
so I can make sense of the #ResponseBody making my return value as the Response of my endpoint, but my question is how does the 404 error happen? also, if I make the return type a String, then I get a 405 error (saying 'POST' is not allowed).
does anybody knows without the #ResponseBody, what is happening? and is there any usecase for not annotating it with #ResponseBody?

How to throw and detect this exception correct

I'm using #ControllerAdvice to detect exceptions that are thrown in the application.
Trying to throw exception during creation of a class:
public void setStatus(String status) throws InvalidInputStatusException{
if(checkIfStatusIsAllowed(status)) {
this.status = status;
} else {
throw new InvalidInputStatusException();
}
}
Trying to catch the error:
#ControllerAdvice
public class RekvisisjonRESTControllerExceptionHandler {
//TODO: Add logger here!
#ExceptionHandler
public final ResponseEntity<RekvisisjonRESTErrorResponse> handleException(InvalidInputStatusException e, WebRequest request) {
//TODO: Do some logging
return new ResponseEntity<>(new RekvisisjonRESTErrorResponse(HttpStatus.BAD_REQUEST.toString(),
e.getClass().getName(),
e.getMessage(), LocalDateTime.now()), HttpStatus.BAD_REQUEST);
}
}
What I want is the object specified above returned, but I get this crap here instead:
"error": "Bad Request",
"message": "JSON parse error: Ugyldig status som input; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Ugyldig status som input\n at [Source: (PushbackInputStream); line: 2, column: 12] (through reference chain: no.pasientreiser.atom.rekvisisjon.controller.dto.UpdateRekvisisjonStatusRequest[\"status\"])",
"trace": "org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Ugyldig status som input; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Ugyldig status som input\n at [Source: (PushbackInputStream); line: 2, column: 12] (through reference chain: no.pasientreiser.atom.rekvisisjon.controller.dto.UpdateRekvisisjonStatusRequest[\"status\"])\n\tat org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:245)\n\tat org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:227)\n\tat org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:205)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:158)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:131)\n\tat org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)\n\tat org.springframework.web.me
I'm assuming it fails to detect the intended exception because another is thrown before it, but this is not what i want.
Any recommendations?
An exception handler handles exceptions that occur in your handler methods (see https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc). The exception you see happens earlier, while Spring is trying to turn the JSON request body into an UpdateRekvisisjonStatusRequest. The Jackson JSON deserializer is invoking the setStatus method and encounters an exception, which Spring takes to mean the HTTP body is not readable (since Jackson couldn't deserialize it).
Take a look at how Spring MVC handles validation instead: https://spring.io/guides/gs/validating-form-input/
The exception happens not in your business code, but during the parsing of the request into your request presentation object. Spring Web treats any kind of exception that happened during parsing of the request as a presentation-level error, not a business-level error, hence, your exception handler doesn't get invoked.
Since you try to enforce a business rule here, I'd propose to move it out of the setter method of a presentation object and find a better place for it. E.g. put this logic inside the business entity, or one of your services, or at the very least in the controller method that accepts the request.
First your RekvisisjonRESTControllerExceptionHandler should extends from ResponseEntityExceptionHandler.
If you return ResponseEntity, it would wrap your value class (RekvisisjonRESTErrorResponse).
Here your exception is generated after the advice, when json serialized.

Redirect to index.html when URL contained a potentially malicious String in spring boot

I'm developing an app with spring boot as its backend and angular 6 as its frontend. I build all frontend files to static folder of the spring boot. In all cases whether it be a (type=Internal Server Error, status=500) error or (type=Not Found, status=404) error, I want my app to not show the "Whitelabel Error Page" and instead redirect the user to index.html file in the static folder. I could achieve it for 404 error code by adding below code to my WebMvcConfigurer:
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
//registry.addResourceHandler("/**").addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS);
registry.addResourceHandler("/**/*")
.addResourceLocations("classpath:/static/")
.resourceChain(true)
.addResolver(new PathResourceResolver() {
#Override
protected Resource getResource(String resourcePath,
Resource location) throws IOException {
Resource requestedResource = location.createRelative(resourcePath);
return requestedResource.exists() && requestedResource.isReadable() ? requestedResource
: new ClassPathResource("/static/index.html");
}
});
}
But could not achieve the same result for 500 error code. For example when I type a url with special characters in addressbar, I get this error:
**Whitelabel Error Page**
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Tue Oct 23 13:56:11 IRST 2018
There was an unexpected error (type=Internal Server Error, status=500).
The request was rejected because the URL contained a potentially malicious String ";"
but if I type some wrong url without special character, I'd be redirected the the "index.html" file.
I also tried adding these lines to my WebMvcConfigurer but that didn't work either:
#Override
public void addViewControllers(final ViewControllerRegistry registry) {
registry.addViewController("/notFound").setViewName("forward:/static/index.html");
registry.addViewController("/login").setViewName("forward:/static/index.html");
registry.addViewController("/error").setViewName("forward:/static/index.html");
}
#Bean
public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> containerCustomizer() {
return container -> {
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notFound"));
container.addErrorPages(new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error"));
};
}
there is not need to more code for this you can create a folder named 'public' in static directory and create directory in this folder named 'error' after that create file named '500.html' or '404.html' or http_code.html in error directory now you can redirect these files.

Springboot: trying to map a logout url - There was an unexpected error (type=Method Not Allowed, status=405)

I am trying to map a logout url in spring boot application. Every other mapping I have specified is working perfectly but this logout url mapping is refusing to map to the controller
this is the form with the submit command
<form method="post" action="/livechat/logout">
<input type="submit" value="Leave Chat"/>
</form>
this is the controller when you hit the submit button
#RequestMapping(value = "/logout", method = RequestMethod.POST)
public ModelAndView logout(HttpServletRequest request,
HttpServletResponse response) {
for (Cookie cookie : request.getCookies()) {
if ("name".equals(cookie.getName()) || "email".equals(cookie.getName())) {
// clear cookie
cookie.setMaxAge(0);
response.addCookie(cookie);
}
}
return new ModelAndView("redirect:/");
}
in my application.properties file I have this configuration for the server url definition
server.context-path= /livechat
#server port
server.port = 8081
When I click on logout i get this error
Fri Aug 05 11:56:22 WAT 2016
There was an unexpected error (type=Method Not Allowed, status=405).
Request method 'POST' not supported
when I look at the url borwser it seems correct but I get error responce
http://localhost:8081/livechat/logout
Please what be wrong. Kiindly assist!

Resources