Spring Boot - Rest Api occasionally adds Error Object to a response - java

I use spring-boot-starter-web (Spring Boot 2.3.0.RELEASE) and my Controller looks like:
#RestController
#RequestMapping(value = "/v1")
public class Controller {
#GetMapping
public ResponseEntity<Object> getObject() {
return ResponseEntity.ok(new Object());
}
}
I've noticed that sometimes in a browser I catch a response like
{}{"timestamp":"2021-03-11T13:39:08.100+00:00","status":200,"error":"OK","message":"","path":"/v1"}
This reproduces randomly - most time I get a correct JSON {}.
Could you advise how to disable adding of the second JSON and what can be a reason for this behavior? Is it a bug?

Related

Spring value binding in #RequestMapping

I have a health check controller like the below one:
#RestController
#RequestMapping("/api/${app-name}/management")
public class HealthCheckController {
#GetMapping(path = "health", produces = MediaType.TEXT_PLAIN_VALUE)
public Mono<String> healthCheck() {
return Mono.just("Ok");
}
}
I have this controller in a common library and this library is included in all our services. In each service properties, I have given the value for app-name. So the URLs like http://host:port/api/service1/management/health will return Ok. This is working fine on my local machine but on the server, getting a 404 error. Our services are deployed in Kubernetes.
Am I missing anything here? Was the value binding in #RequestMapping (${app-name}) is correct usage?

Webflux Http 404 Response when header is added to Request

I am currently trying to shift my application from spring boot 1.5.x to 2.x.x on reactive stack. I am facing a kinda weird problem that I can't figure out. Hope someone knows the solution to this.
I implemented an api to receive a user jwt token as "Authorization" field on the header. The api is a POST method that receives a certain json data from the user in the body, goes to the backend and processes it.
The unfortunate thing is i keep getting a http 404 error when i add in the header, a normal 200 when i remove it in postman.
Here is my controller.
#RestController
#RequestMapping("/user")
#Slf4j
public class UserHandler {
#Autowired
private UserService service;
#Autowired
private Utility utility;
#PostMapping("/updateLink")
public Mono<ServerResponse> addNewAccountLinkAPI(#RequestHeader(name="Authorization") String id, #RequestBody UpdateAccountLink request){
return Mono.just(request)
.flatMap(s -> service.addNewAccountLink(s))
.flatMap(s -> ok().body(BodyInserters.fromObject(new RespWrap("Success", new Date(), null, s))))
.switchIfEmpty(badRequest().body(BodyInserters.fromObject(new RespWrap("Failed", new Date(), "Failed to create new link", null))));
}
}
Here is my simple security config
#Configuration
#EnableWebFluxSecurity
#EnableWebFlux
public class ResourceServerConfig implements WebFluxConfigurer {
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http, FirebaseAuthenticationManager manager) {
http
.authorizeExchange().anyExchange().permitAll()
.and().csrf().disable();
return http.build();
}
}
Can anyone please point me out on the problem. This sure seems like a lack of config problem.
I can see two issues with your code snippets.
First, you shouldn't add #EnableWebFlux as it completely disables the auto-configuration done by Spring Boot. Same goes for #EnableWebMvc in a Spring MVC application.
Second, you're mixing WebFlux annotations and WebFlux functional. The annotations you're using are fine, but the ServerResponse type should only be used when writing functional handlers. You should try instead here to use ResponseEntity.

Spring Boot Validation with ControllerAdvice Not Behaving Deterministically

I have the following setup
#ControllerAdvice
public class AppControllerAdvice extends ResponseEntityExceptionHandler {
#ExceptionHandler({UserInputValidationException.class})
public ResponseEntity<UserInputValidationResponseBody> handleBadInputException(UserInputValidationException ex, WebRequest request) {
return new ResponseEntity<>(
new UserInputValidationResponseBody().setFieldErrors(ex.getFieldErrors()),
HttpStatus.BAD_REQUEST
);
}
}
This is roughly the #RestController that throws well formatted validation exceptions
#RestController
#RequestMapping("api")
public class MyController {
/**
per the answer, BindingResult must immediately follow the #RequestBody or the item being found
*/
#PostMapping
public ResponseEntity<?> foo(#Valid #RequestBody FormPOJO formBody, Principal principal, BindingResult bindingResult) {
// if bindingResult has errors, throw a UserInputValidationException
}
}
And POJOs that I want to bind have JSR-303 validation annotations on them, Spring correctly validate them at Bind time during request parameter binding
However ... while I got this setup to work for a while - then Spring randomly started to bypass the #RestController and #ControllerAdvice
It appears that now I am receiving org.springframework.web.bind.MethodArgumentNotValidException ... i.e. the request is getting short circuited
I am running Spring Boot 1.5.4.RELEASE ...
EDIT following suggestion from another thread, I added
#Order(Ordered.HIGHEST_PRECEDENCE)
to the controller advice ... it only served to make matters worse. now there is absolutely no validation errors - the client only receives a blank message (which was the symptom of the problem for a while before the current issue surfaced without any code changes)
Ok it turns out
An Errors/BindingResult argument is expected to be declared immediately after the model attribute, the #RequestBody or the #RequestPart arguments to which they apply: public org.springframework.http.ResponseEntity com.remo.api.portfolios.PortfolioController.put(java.security.Principal,org.springframework.validation.BindingResult,com.remo.api.portfolios.Portfolio
tl;dr Please go ahead and make sure #RequestBody is declared IMMEDIATELY before BindingResult

Tomcat 7 default bad request page conflict #ControllerAdvice

I am currently developing a webservice which will always return json as a response to any request(all good request are working already). I would like to return a json when the http status of the request is a bad request(status 400 to be exact). I used the #ControllerAdvice of spring mvc to do the job:
#ControllerAdvice
public class RestErrorHandler {
#ExceptionHandler(Exception.class)
#ResponseStatus(value=HttpStatus.BAD_REQUEST, reason="Something went wrong. Please check your JSON REQUEST!")
public #ResponseBody ErrorClass processValidationError() {
// some stuff in setting the error response
return new ErrorClass();
}
But what happen is that it returns the default Tomcat 7 error message for bad request and not the json I set. processValidationError() will return an ErrorClass instance which will automatically be in json format using jackson plugin. Did I missed something?

Data Binding Error Handling in Spring MVC

I have a question about data binding in Spring MVC.
I have a Controller which accepts a JSON request in the form of #RequestBody. I have all the JSR 303 validations in place and it works like a charm.
JSON Request
public class TestJSONRequest {
#Size(min=10,message="{invalid.demo.size}")
String demo;
int code;
}
Controller
#Controller
#RequestMapping("/test")
public class TestController {
public void testEntry(#RequestBody TestJSONRequest jsonRequest,ModelMap map)
Set<ConstraintViolation<TestJSONRequest>> violationList = validator.val(jsonRequest);
....
....
TestJSONResponse response = // Do complex Logic.
modelMap.addattribute("TestJSONResponse",response);
}
}
But JSR 303 validations kick in once the incoming JSON data is bound to the Request object.
If I send ab in the code field of the input JSON request, binding would itself fail.
How do I handle that?
I want to catch those data binding errors and do some kind of generalized error handling in my controller.
Could you please help me out on this?
P.S - I am using Spring 3.0.3
According to the current Spring documentation (V3.1) :
Unlike #ModelAttribute parameters, for which a BindingResult can be used to examine the errors, #RequestBody validation errors always result in a MethodArgumentNotValidException being raised. The exception is handled in the DefaultHandlerExceptionResolver, which sends a 400 error back to the client.
Now you can to tell Spring that you'd like to handle this, by creating a new method, as follows:
#ExceptionHandler(MethodArgumentNotValidException.class)
public String handleValidation(MethodArgumentNotValidException e, ModelMap map) {
List<ObjectError> errors = e.getBindingResult() .getAllErrors();
// your code here...
return "path/to/your/view";
}
Finally, have a read of the Spring docs wrt #ExceptionHandler. There's most likely some useful information there.

Categories