I am new to reactive java and working on spring boot project. I have a method in controller class, which takes id and return Mono. its works fine and retrun response with data.But It returns blank and and 200 status when I uncomment a line @ValidateParam(name = StringValidator.class) annotation in this method.
@GetMapping("/vendor/id/{id}")
//@ValidateParam(name = StringValidator.class)
public Mono<Vendor> getVendor(@PathVariable("id") String id){
//get specific vendor
return vendorService.getVendorByID(id);
}
I have created my custom validator to validate the id, I receive as param to this method.I am running the validator using pointcut. I check the joint point and if there is no error then I use proceed method from ProceedingJoinPoint
Any help is much appreciated? I can not understand what is wrong here.
Upon debug, I find when there is no validation error in id, method proceeds and I can print the data when I subscribe to Mono. But it return blank when I return same mono.
Here is how validate param method looks like:
@Around(value = "@annotation(ValidateParam)")
public void validationProcessror(ProceedingJoinPoint method , ValidateParam validateParam) throws Throwable {
Object arg = method.getArgs()[0];
Class validatorclass = validateParam.name();
ValidationError err = applyValidation((Validator) validatorclass.getConstructor().newInstance(), arg);
if(err.size() == 0) {
method.proceed();
}else {
throw new RuntimeException(err.errors.toString());
}
}
Your @Around
advice returns null
, because it is a void
method, which would only make sense when intercepting void
methods. If you study Spring AOP or AspectJ manuals, you will find out that, in contrast to @Before
and @After
adbvice types which are always void
because they return nothing, an @Around
advice needs to return something copmpatible with ther intercepted method's return type.
Your advice should rather look like this (untested due to incomplete sample code):
@Around("@annotation(validateParam)")
public Object validationProcessror(ProceedingJoinPoint joinPoint, ValidateParam validateParam) throws Throwable {
Object arg = joinPoint.getArgs()[0];
Class validatorclass = validateParam.name();
ValidationError err = applyValidation((Validator) validatorclass.getConstructor().newInstance(), arg);
if (err.size() == 0)
return joinPoint.proceed();
else
throw new RuntimeException(err.errors.toString());
}
Please also note that if you want to bind the annotation value to an advice method sargument, you need to use the argument name validateParam
(lower-case) rather than the class name ValidateParam
.
There are other things which could be optimised in your advice, but I want to avoid throwing too much information at you.
Update: If you always want to pass on the original method parameters to your target method and return the original value without modification, you do not need an @Around
advice at all. @Before
is enough and simplifies your code:
@Before("@annotation(validateParam)")
public void validationProcessror(JoinPoint joinPoint, ValidateParam validateParam) {
Object arg = joinPoint.getArgs()[0];
Class validatorclass = validateParam.name();
ValidationError err = applyValidation((Validator) validatorclass.getConstructor().newInstance(), arg);
if (err.size() > 0)
throw new RuntimeException(err.errors.toString());
}
Update 2: I have never used any reactive frameworks before, but I got a hunch that throwing a runtime error might not be the right thing to do in the first place. This is, of course, unrelated to the problem at hand, but might cause you trouble later on. Maybe, your @Around
advice ought to return Mono.error()
in that situation. But I could be wrong, being a reactive noob.