I have a rest controller that looks like this:
@RequestMapping(
value = "/foo",
method = RequestMethod.POST)
@ResponseBody
public ResponseEntity<JsonNode> getFOOs(@Valid Payload payload) {
/** some code **/
}
The Payload
class looks like this:
@OneOrTheOther(first = "a", second = "b")
public final class Payload {
private final String userName;
private final String a;
private final String b;
@NotNull
private final String c;
@NotEmtpy{message="At least 1 item"}
private List<String> names = new ArrayList<String>();
}
And the ArgumentResolver looks like this:
public class PayloadArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.getParameterType().equals(Payload.class);
}
@Override
public Object resolveArgument(MethodParameter methodParameter,
ModelAndViewContainer modelAndViewContainer,
NativeWebRequest nativeWebRequest,
WebDataBinderFactory webDataBinderFactory) throws Exception {
if(supportsParameter(methodParameter)) {
HttpServletRequest requestHeader = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
String userName = requestHeader.getHeader("userName");
ObjectMapper mapper = new ObjectMapper();
JsonNode requestBody = mapper.readTree(CharStreams.toString(requestHeader.getReader()));
JsonNode a = requestBody.path("a");
String a = a.isMissingNode() ? null : a.asText();
JsonNode b = requestBody.path("b");
String b = b.isMissingNode() ? null : b.asText();
JsonNode c = requestBody.path("c");
String c = c.isMissingNode() ? null : c.asText();
JavaType type = mapper.getTypeFactory().constructCollectionType(ArrayList.class, String.class);
List<String> ids
= requestBody.path("ids").isMissingNode()
? null : mapper.readValue(requestBody.path("ids").toString(), type);
return new Payload(username, a, b, c, ids);
}
return null;
}
}
Currently this does about 95% of what I want it to do. It successfully retrieves all the items from the header and request body and creates a Payload
object. But after creating the object I want to run the validations annotated in the Payload
class like NotNull
, NotEmpty
or my customer validator OneOrTheOther
.
I did some digging around and found a couple stack articles here and here. I don't know how to implement the first one and the second one seems overly complicated and cumbersome so I don't want to really go that route. It seems like using the validateIfApplicable
method is the way to go but how would I call it in my context?
The @Validated annotation is a class-level annotation that we can use to tell Spring to validate parameters that are passed into a method of the annotated class. We'll learn more about how to use it in the section about validating path variables and request parameters.
The @Valid annotation ensures the validation of the whole object. Importantly, it performs the validation of the whole object graph. However, this creates issues for scenarios needing only partial validation. On the other hand, we can use @Validated for group validation, including the above partial validation.
When Spring Boot finds an argument annotated with @Valid, it automatically bootstraps the default JSR 380 implementation — Hibernate Validator — and validates the argument. When the target argument fails to pass the validation, Spring Boot throws a MethodArgumentNotValidException exception.
You could add a SmartValidator instance in your class. Just add:
@Autowired
SmartValidator payloadValidator;
Once injected, you just have to call the validate method on it, passing your bean and the list of errors.
For reference:
SmartValidator: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/validation/SmartValidator.html
Erros: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/validation/Errors.html
It means you want those validations to be run right after the creation of object. If this is the case then you can create the @Pointcut to the method which returns your Object,and which will call the validations you want @AfterReturning(methodthat returns object)
@Pointcut("execution(* YourClass.*(..))")
public void pointcut(){}
@AfterReturning("method that returns object")
public final class Payload {
private final String userName;
private final String a;
private final String b;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With