I would like to create own class that will transform HTTP request and initializes object from this HTTP request in my Spring MVC application. I can create object by defining parameters in method but I need to do mapping in my own way and do it manually.
How can I do it with my own implementation that will pass to Spring and it will use it seamlessly?
Update1
Solution that kindly provided Bohuslav Burghardt doesn't work:
HTTP Status 500 - Request processing failed; nested exception is
java.lang.IllegalStateException: 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
java.lang.String
cz.deriva.derivis.api.oauth2.provider.controllers.OAuthController.authorize(api.oauth2.provider.domain.AuthorizationRequest,org.springframework.ui.Model,org.springframework.validation.BindingResult,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
Maybe I should mention that I use own validator:
public class RequestValidator {
public boolean supports(Class clazz) {
return AuthorizationRequest.class.equals(clazz);
}
public void validate(Object obj, Errors e) {
AuthorizationRequest request = (AuthorizationRequest) obj;
if ("foobar".equals(request.getClientId())) {
e.reject("clientId", "nomatch");
}
}
}
and declaration of my method in controller (please not there is needed a validation - #Valid):
#RequestMapping(value = "/authorize", method = {RequestMethod.GET, RequestMethod.POST})
public String authorize(
#Valid AuthorizationRequest authorizationRequest,
BindingResult result
) {
}
I have two configurations classes in my application.
#Configuration
#EnableAutoConfiguration
#EnableWebMvc
#PropertySource("classpath:/jdbc.properties")
public class ApplicationConfig {
}
and
#Configuration
#EnableWebMvc
public class WebappConfig extends WebMvcConfigurerAdapter {
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new AuthorizationRequestArgumentResolver());
}
}
What is wrong?
Update 2
The problem is with param BindingResult result, when I remove it it works. But I need the result to process it when some errors occur.
If I understand your requirements correctly, you could implement custom HandlerMethodArgumentResolver for that purpose. See example below for implementation details:
Model object
public class AuthorizationRequestHolder {
#Valid
private AuthorizationRequest authorizationRequest;
private BindingResult bindingResult;
// Constructors, accessors omitted
}
Resolver
public class AuthorizationRequestMethodArgumentResolver implements HandlerMethodArgumentResolver {
#Override
public boolean supportsParameter(MethodParameter parameter) {
return AuthorizationRequestHolder.class.isAssignableFrom(parameter.getParameterType());
}
#Override
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
// Map the authorization request
AuthorizationRequest authRequest = mapFromServletRequest(request);
AuthorizationRequestHolder authRequestHolder = new AuthorizationRequestHolder(authRequest);
// Validate the request
if (parameter.hasParameterAnnotation(Valid.class)) {
WebDataBinder binder = binderFactory.createBinder(webRequest, authRequestHolder, parameter.getParameterName());
binder.validate();
authRequestHolder.setBindingResult(binder.getBindingResult());
}
return authRequestHolder;
}
}
Configuration
#Configuration
#EnableWebMvc
public class WebappConfig extends WebMvcConfigurerAdapter {
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new AuthorizationRequestMethodArgumentResolver());
}
}
Usage
#RequestMapping("/auth")
public void doSomething(#Valid AuthRequestHolder authRequestHolder) {
if (authRequestHolder.getBindingResult().hasErrors()) {
// Process errors
}
AuthorizationRequest authRequest = authRequestHolder.getAuthRequest();
// Do something with the authorization request
}
Edit: Updated answer with workaround to non-supported usage of #Valid with HandlerMethodArgumentResolver parameters.
Related
For learning purposes, I have made a custom authentication system where I pass a token from the client to the server through the Authorization header.
In the server side, I'd like to know if it's possible to create in the interceptor, before the request reaches a method in the controller, an User object with the email from the token as a property, and then pass this user object to every request where I require it.
This what I'd like to get, as an example:
#RestController
public class HelloController {
#RequestMapping("/")
public String index(final User user) {
return user.getEmail();
}
}
public class User {
private String email;
}
Where user is an object that I created in the pre-interceptor using the request Authorization header and then I can pass, or not, to any method in the RestController.
Is this possible?
#Recommended solution
I would create a #Bean with #Scope request which would hold the user and then put the appropriate entity into that holder and then take from that holder inside the method.
#Component
#Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class CurrentUser {
private User currentUser;
public User getCurrentUser() {
return currentUser;
}
public void setCurrentUser(User currentUser) {
this.currentUser = currentUser;
}
}
and then
#Component
public class MyInterceptor implements HandlerInterceptor {
private CurrentUser currentUser;
#Autowired
MyInterceptor(CurrentUser currentUser) {
this.currentUser = currentUser;
}
#Override
public boolean preHandle(
HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
this.currentUser.setCurrentUser(new User("whatever"));
return true;
}
}
and in the Controller
#RestController
public class HelloController {
private CurrentUser currentUser;
#Autowired
HelloController(CurrentUser currentUser) {
this.currentUser = currentUser;
}
#RequestMapping("/")
public String index() {
return currentUser.getCurrentUser().getEmail();
}
}
#Alternative solution
In case your object that you would like to have, only contains one field, you can just cheat on that and add that field to the HttpServletRequest parameters and just see the magic happen.
#Component
public class MyInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(
HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//TRY ONE AT THE TIME: email OR user
//BOTH SHOULD WORK BUT SEPARATELY OF COURSE
request.setAttribute("email", "login#domain.com");
request.setAttribute("user", new User("login#domain.com"));
return true;
}
}
You can use a local thread context object as follows - which will be handling one parameter per request thread (thread safe):
public abstract class LoggedUserContext {
private static ThreadLocal<User> currentLoggedUser = new ThreadLocal<>();
public static void setCurrentLoggedUser(User loggedUser) {
if (currentLoggedUser == null) {
currentLoggedUser = new ThreadLocal<>();
}
currentLoggedUser.set(loggedUser);
}
public static User getCurrentLoggedUser() {
return currentLoggedUser != null ? currentLoggedUser.get() : null;
}
public static void clear() {
if (currentLoggedUser != null) {
currentLoggedUser.remove();
}
}
}
Then in the interceptor prehandle function:
LoggedUserContext.setCurrentLoggedUser(loggedUser);
And in the interceptor postHandler function:
LoggedUserContext.clear();
From any other place:
User loggedUser = LoggedUserContext.getCurrentLoggedUser();
So i am trying to add a custom argument resolver to my Spring-Data-Rest project.
I am devolping a multi-tenant application, and need to filter data based on a users tenant-id.
So i wrote a simple annotation and ArgumentResolver to query my tenant repository and inject a tenant Object as Parameter on some needed Methods:
Handler:
#AllArgsConstructor
public class TenantInjector implements HandlerMethodArgumentResolver {
private final TenantStore tenantStore;
private final TenantRepository tenantRepository;
#Override
public boolean supportsParameter(MethodParameter methodParameter) {
if(! methodParameter.hasParameterAnnotation(InjectTenant.class)) {
return false;
}
return true;
}
#Override
public Object resolveArgument(MethodParameter methodParameter,
ModelAndViewContainer modelAndViewContainer,
NativeWebRequest nativeWebRequest,
WebDataBinderFactory webDataBinderFactory) throws Exception {
return tenantRepository.findById(tenantStore.getId()).get();
}
}
This handler queries the tenantRepository to find the current tenant by its Id, which is set when the incoming requests security token is parsed.
To register the handler, i do the following:
#Configuration
public class DispatcherContext implements WebMvcConfigurer {
private final TenantStore tenantStore;
private final TenantRepository tenantRepository;
#Autowired
public DispatcherContext(TenantStore tenantStore, TenantRepository tenantRepository) {
this.tenantStore = tenantStore;
this.tenantRepository= tenantRepository;
}
#Override
public void addArgumentResolvers(
List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new TenantInjector(tenantStore, tenantRepository));
}
}
This works nice as long as the corrensponding Controller is annotated with either #Controller or #RestController
As the #RepositoryRestController has an other context, this configuration is ignored. How can I add the same ArgumentResolver to the Spring-Data-Rest configuration?
It might be an option to just switch the annotations, but i would like to rather stick with this approche, as links get generated by spring-data-rest.
Has anyone stumble over this to?
Your issue could be that you registered your custom argument resolver in your WebMvcConfigurer. Spring Data Rest seems to work in a different context, so you have to register your custom argument resolver in your RepositoryRestMvcConfiguration.
#Configuration
public class RepositoryConfiguration extends RepositoryRestMvcConfiguration {
public RepositoryConfiguration(ApplicationContext context, ObjectFactory<ConversionService> conversionService)
{
super(context, conversionService);
}
#Override
protected List<HandlerMethodArgumentResolver> defaultMethodArgumentResolvers()
{
List<HandlerMethodArgumentResolver> resolvers =
new ArrayList<>(super.defaultMethodArgumentResolvers());
resolvers.add(new TenantInjector(tenantStore, tenantRepository));
return resolvers;
}
}
Answer inspired by: https://github.com/tkaczmarzyk/specification-arg-resolver/issues/6#issuecomment-111952898
I would like to wrap the response of my #RestController method into different object structure before Jackson starts to serialize the response to JSON. Let's say I work with the following Spring controller.
#RestController
#RequestMapping("/api/susu")
public class SusuController {
#RequestMapping(path = "/{id}", method = RequestMethod.GET)
public Susu hello(String id) {
Susu susu = new Susu();
susu.setDate(LocalDate.now());
susu.setName("Peter Pan");
return susu;
}
}
In JEE7 I used JAX-RS Interceptor the get access to the Susu instance and wrap it.
#Provider
#Priority(1)
public class JsonStructureInterceptor implements WriterInterceptor {
private final JsonResponseBuilder jsonResponseBuilder = new JsonResponseBuilder();
#Override
public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
Susu s = (Susu) context.getEntity(); // read the JAX-RS response entity
JsonObject jsonObjectWithStructure = jsonResponseBuilder.toResponse(s); // wrap it
// add it back into the JAX-RS context
context.setEntity(jsonObjectWithStructure);
context.proceed();
}
}
When using Spring Boot what is the preferred way to to something equivalent without using JAX-RS features?
Update 1: Using a HandlerInterceptorAdapter
I added the following HandlerInterceptorAdapter to my application context and the postHandle method gets called. Everything works fine so far but I cannot figure out how to get the Susu instance and how to pass the wrapped instance over for further processing.
#Component
public class SusuHandlerInterceptor extends HandlerInterceptorAdapter {
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
Susu s = ; // how to get access to my Susu instance?
Wrapper w = new Wrapper(s);
// how to pass Wrapper instance on?
}
}
Update 2: Implementing a ResponseBodyAdvice
I found another approach that allows me to access the return value of my controller action. The problem here is that I cannot change the type of the return value. It seems it is not possible to wrap Susu instance in a Wrapper instance.
#ControllerAdvice
public class JsonFilter implements ResponseBodyAdvice<SusuController.Susu> {
#Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
#Override
public SusuController.Susu beforeBodyWrite(SusuController.Susu body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
return body;
}
}
Implementing a ResponseBodyAdvice lets you modify the object before it's converted.
If the return-type should be modified, one has to omit the Generic-types:
#ControllerAdvice
class JsonModifyingAdvice implements ResponseBodyAdvice {
#Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
#Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
return new WrappedResponse(body);
}
}
I am using Spring Boot 1.4.1 which includes spring-web-4.3.3. I have a class annotated with #ControllerAdvice and methods annotated with #ExceptionHandler to handle exceptions thrown by the service code. When handling these exceptions, I would like to log the #RequestBody that was part of the request for PUT and POST operations so I can see the request body that caused the problem which in my case is crucial for diagnosis.
Per Spring Docs the method signature for #ExceptionHandler methods can include various things including the HttpServletRequest. The request body can normally be obtained from here via getInputStream() or getReader(), but if my controller methods parse the request body like "#RequestBody Foo fooBody" as all of mine do, the HttpServletRequest's input stream or reader is already closed by the time my exception handler method is called. Essentially the request body has already been read by Spring, similar to the issue described here. It is a common problem working with servlets that the request body can only be read once.
Unfortunately #RequestBody is not one of the options available for the exception handler method, if it were then I could use that.
I can add an InputStream to the exception handler method, but that ends up being the same thing as the HttpServletRequest's InputStream and so has the same issue.
I also tried getting the current request with ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest() which is another trick for getting the current request, but this ends up being the same HttpServletRequest that Spring passes into the exception handler method and so has the same problem.
I have read about a few solutions like this and this that involve inserting a custom request wrapper in the filter chain that will read the contents of the request and cache them so they can be read more than once. I don't like this solution because I don't want to interrupt the entire filter/request/response chain (and potentially introduce performance or stability problems) just to implement logging, and if I have any large requests such as uploaded documents (which I do), I don't want to cache that in memory. Besides, Spring probably has the #RequestBody cached somewhere already if I could only find it.
Incidentally many solutions recommend using the ContentCachingRequestWrapper Spring class but in my experience this does not work. Aside from not being documented, looking at its source code it looks like it only caches the parameters, but not the request body. Trying to get the request body from this class always results in an empty string.
So I am looking for any other options that I may have missed. thanks for reading.
Accepted answer creates a new POJO to pass things around, but the same behaviour can be achieved without creating additional objects by reusing the http request.
Example code for Controller mapping:
public ResponseEntity savePerson(#RequestBody Person person, WebRequest webRequest) {
webRequest.setAttribute("person", person, RequestAttributes.SCOPE_REQUEST);
And later in the ExceptionHandler class / method you can use:
#ExceptionHandler(Exception.class)
public ResponseEntity exceptionHandling(WebRequest request,Exception thrown) {
Person person = (Person) request.getAttribute("person", RequestAttributes.SCOPE_REQUEST);
You can reference the request body object to a request-scoped bean. And then inject that request-scoped bean in your exception handler to retrieve the request body (or other request-context beans that you wish to reference).
// #Component
// #Scope("request")
#ManagedBean
#RequestScope
public class RequestContext {
// fields, getters, and setters for request-scoped beans
}
#RestController
#RequestMapping("/api/v1/persons")
public class PersonController {
#Inject
private RequestContext requestContext;
#Inject
private PersonService personService;
#PostMapping
public Person savePerson(#RequestBody Person person) throws PersonServiceException {
requestContext.setRequestBody(person);
return personService.save(person);
}
}
#ControllerAdvice
public class ExceptionMapper {
#Inject
private RequestContext requestContext;
#ExceptionHandler(PersonServiceException.class)
protected ResponseEntity<?> onPersonServiceException(PersonServiceException exception) {
Object requestBody = requestContext.getRequestBody();
// ...
return responseEntity;
}
}
You should be able to get the content of the request body by using the RequestBodyAdvice interface. If you implement this on a class annotated with #ControllerAdvice it should be picked up automatically.
To get other request information like the HTTP method and query params I'm using an interceptor. I'm capturing all this request info for error reporting in a ThreadLocal variable which I clear on the afterCompletion hook in that same interceptor.
The class below implements this and can be used in your ExceptionHandler to get all request information:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
#ControllerAdvice
public class RequestInfo extends HandlerInterceptorAdapter implements RequestBodyAdvice {
private static final Logger logger = LoggerFactory.getLogger(RequestInfo.class);
private static final ThreadLocal<RequestInfo> requestInfoThreadLocal = new ThreadLocal<>();
private String method;
private String body;
private String queryString;
private String ip;
private String user;
private String referrer;
private String url;
public static RequestInfo get() {
RequestInfo requestInfo = requestInfoThreadLocal.get();
if (requestInfo == null) {
requestInfo = new RequestInfo();
requestInfoThreadLocal.set(requestInfo);
}
return requestInfo;
}
public Map<String,String> asMap() {
Map<String,String> map = new HashMap<>();
map.put("method", this.method);
map.put("url", this.url);
map.put("queryParams", this.queryString);
map.put("body", this.body);
map.put("ip", this.ip);
map.put("referrer", this.referrer);
map.put("user", this.user);
return map;
}
private void setInfoFromRequest(HttpServletRequest request) {
this.method = request.getMethod();
this.queryString = request.getQueryString();
this.ip = request.getRemoteAddr();
this.referrer = request.getRemoteHost();
this.url = request.getRequestURI();
if (request.getUserPrincipal() != null) {
this.user = request.getUserPrincipal().getName();
}
}
public void setBody(String body) {
this.body = body;
}
private static void setInfoFrom(HttpServletRequest request) {
RequestInfo requestInfo = requestInfoThreadLocal.get();
if (requestInfo == null) {
requestInfo = new RequestInfo();
}
requestInfo.setInfoFromRequest(request);
requestInfoThreadLocal.set(requestInfo);
}
private static void clear() {
requestInfoThreadLocal.remove();
}
private static void setBodyInThreadLocal(String body) {
RequestInfo requestInfo = get();
requestInfo.setBody(body);
setRequestInfo(requestInfo);
}
private static void setRequestInfo(RequestInfo requestInfo) {
requestInfoThreadLocal.set(requestInfo);
}
// Implementation of HandlerInterceptorAdapter to capture the request info (except body) and be able to add it to the report in case of an error
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
RequestInfo.setInfoFrom(request);
return true;
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) {
RequestInfo.clear();
}
// Implementation of RequestBodyAdvice to capture the request body and be able to add it to the report in case of an error
#Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
#Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return inputMessage;
}
#Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
RequestInfo.setBodyInThreadLocal(body.toString());
return body;
}
#Override
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
}
Just an enhancement to quintencls answer
I got request body and can use it anywhere inside exception handler class.
#ControllerAdvice
public class CustomErrorHandler extends ResponseEntityExceptionHandler implements RequestBodyAdvice {
...
private Object reqBody;
...
#ExceptionHandler(NoSuchElementException.class)
public ResponseEntity<Object> handleNoSuchElementException(final NoSuchElementException ex,
final WebRequest request) {
System.out.println("===================================" + reqBody);
return handleNotFoundException(ex, request);
}
...
#Override
public boolean supports(MethodParameter methodParameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
#Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
return inputMessage;
}
#Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) {
// capture request body here to use in our controller advice class
this.reqBody = body;
return body;
}
#Override
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
}
Here is a solution in Kotlin syntax that I used for some fields validation control.
I needed to enhance the default handleMethodArgumentNotValid(...) method from the #RestControllerAdvice, to systematically log a field that was embedded in that same request body object.
override fun handleMethodArgumentNotValid(e: MethodArgumentNotValidException, headers: HttpHeaders, status: HttpStatus, request: WebRequest): ResponseEntity<Any> {
val error = e.bindingResult.fieldErrors.first()
val requestBody = try {
val field = error.javaClass.getDeclaredField("violation").apply { trySetAccessible() }
((field[error] as ConstraintViolationImpl<Any>).rootBean as MyRequestBodyObject)
} catch (ex : Exception) {
//do some failsafe here
}
}
See here: https://stackoverflow.com/a/61813076/1036433 - for a clean way to have access to the HttpServerRequest.
How can I achive that the #ResponseBody (in my case a class of type SomePojoInterface) is automatically validated (lets say through JSR-303 validation). Nice to have would be, that in case of a validation-failure the handler would throw an Exception which can be handled in some #ControllerAdvice annotated class.
My code so far.
#RestController
public class MyRestController {
#GetMapping(value = "validate", produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
protected SomePojo validateResponse() {
return new SomePojo();
}
}
#ControllerAdvice
class GlobalControllerExceptionHandler {
#ResponseStatus(HttpStatus.XXX)
#ExceptionHandler(MyResponseValidationException.class)
public void handleResponseValidationException() {
// ...
}
}
public class SomePojo implements SomePojoInterface {
#NotNull
private String someValue;
// getter / setter
}
If you have annotated your class SomePojo, then:
#GetMapping(value = "validate", produces = MediaType.APPLICATION_JSON_VALUE)
protected SomePojo validateResponse() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
SomePojo somePojo = new SomePojo(null);
Set<ConstraintViolation<Car>> constraintViolations = validator.validate(somePojo);
// Other stuff
}
#Valid annotation is for request. More examples from their docs. I am not sure what all you want to validate
I managed to achieve this through the #RestControllerAdvice.
#RestControllerAdvice
public class RestPostProcessingAdvice implements ResponseBodyAdvice<SomePojoInterface> {
#Inject
private Validator validator;
#Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
if(doSomeChecksIfEligiable(returnType, converterType)) {
return true;
}
return false;
}
#Override
public SomePojoInterface beforeBodyWrite(SomePojoInterface body, MethodParameter returnType,
MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(body);
if(constraintViolations.size() > 0) {
response.setStatusCode(HttpStatus.XXX);
LOG.fatal("Sorry, I'm sending crap");
}
return body;
}
}
Be aware that throwing an Exception and catching it in an #ExceptionHandler that is sending the same (mofified) object out in the #ResponseBody could lead to an endless loop, since the object will be checked again this #RestControllerAdvice.