pass result of annotation work to annotated method - java

Annotation:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Multipart {
Class acceptClass();
}
Annotated method:
#Multipart (acceptClass = SomeClass.class)
public void someMethod(SomeClass a){
//do stuff..
}
MultipartAspect:
#Aspect
public class MultipartAspect {
#Autowired(required=true)
private HttpServletRequest request;
#Pointcut(value = "#annotation(Multipart)", argNames = "multipart")
public void before(JoinPoint jp, Multipart multipart) {}
#Before("before()")
public SomeClass doStuffBeforeThing() {
SomeClass sc = new SomeClass(); //object of passed class
//do something..
return sc; //return this to annotated method(somemethod)
}
}
I want before method works execute annotation, create object of passed class(SomeClass) and the pass object of this class to annotated method. Could I do this?

You should use #Around advice instead of #Before.

Related

Custom annotation does not work in method

I created annotation to check permissions on the APIs. Annotation worked when placed in class or method. But when I use it for both class and method at the same time, the annotation placed on the method is ignored
Here is an example:
#RestController
#RequestMapping("/user")
#CustomAnnotation(permission="manageUser")
public class UserController {
#CustomAnnotation(permission="updateUser")
#PutMapping("/{id}")
public UserDto getUser(HttpServletRequest request) {
...
}
}
Now #CustomAnnotation(permission="updateUser") in the getUser() method will be ignored and only execute annation in class UserController
My custom code
#Target(value = {ElementType.METHOD, ElementType.TYPE})
#Retention(value = RetentionPolicy.RUNTIME)
#Inherited
#Documented
public #interface CustomAuthorize {
public String permission() default "";
public String attribute() default "";
}
#Aspect
#Component
public class CustomAnnotationAspect {
#Autowired
CustomAuthorizationImpl authBean;
#Pointcut("#annotation(customAuthorize) || #within(customAuthorize)")
public void pointcutForCustomAnnotation(CustomAuthorize customAuthorize) {
// Do nothing.
}
#Around("pointcutForCustomAnnotation(customAuthorize)")
public Object customAspect(ProceedingJoinPoint pjp, CustomAuthorize customAuthorize) throws Throwable {
if (Objects.isNull(customAuthorize)) {
System.out.println("Call from method");
// Check permission
return pjp.proceed();
}
System.out.println("Call from class");
ExpressionParser elParser = new SpelExpressionParser();
if (!customAuthorize.permission().isBlank()) {
// check permission
}
return pjp.proceed();
}
}

Jackson Mixin Deserializer not calling Setter

I have a POJO class & Mixin like below.
When calling Jackson I expect {'enquiry_id':'1234'} to work but the setter method is not called and the getter returns null. When I pass it in input as {'enquiryId':'1234'} it gets deserialized correctly.
Before using Mixin, I was using the same annotation directly in the class and was not facing this problem.
public class Party {
private String enquiryId;
public String getEnquiryId() {
return enquiryId;
}
public String setEnquiryId(String enquiryId) {
this.enquiryId = enquiryId;
}
}
public abstract class PartyMixIn {
#JsonProperty("enquiry_id") String enquiryId;
}
Can anybody elaborate why the Jackson Mixin Deserializer is not calling the setEnquiryId(String enquiryId) method of Party Class.
Example usage
import io.swagger.annotations.ApiOperation;
import io.swagger.annotation.Api;
#Api(value = "Party Api")
#RestController
public class MainController {
#ApiOperation(value = "Process Party", notes = "Example usage {'enquiry_id':'1234'}")
#RequestMapping(value = "process", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public Party process(#RequestBody Party party) throws IOException, HttpException {
// Here i get party.getEnquiryId() as null
return party;
}
}
#Configuration
#EnableWebMvc
#EnableCaching
public class SpringConfig extends WebMvcConfigurerAdapter {
#Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
for (HttpMessageConverter<?> mc : converters) {
if (mc instanceof MappingJackson2HttpMessageConverter || mc instanceof MappingJackson2XmlHttpMessageConverter) {
((AbstractJackson2HttpMessageConverter) mc).getObjectMapper().addMixIn(Party.class, PartyMixIn.class);
}
}
return;
}
}

How to dynamically disable specific API in spring?

I have a flag DISABLE_FLAG and I want to use it to control multiple specific APIs in different controllers.
#RestController
public final class Controller1 {
#RequestMapping(value = "/foo1", method = RequestMethod.POST)
public String foo1()
}
#RestController
public final class Controller2 {
#RequestMapping(value = "/foo2", method = RequestMethod.POST)
public String foo2()
}
I can use an interceptor to handle all the urls. Is there a easy way to do that like annotation?
You could use AOP to do something like that.
Create your own annotation...
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Maybe { }
and corresponding aspect...
#Aspect
public class MaybeAspect {
#Pointcut("#annotation(com.example.Maybe)")
public void callMeMaybe() {}
#Around("callMeMaybe()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
// do your logic here..
if(DISABLE_FOO) {
// do nothing ? throw exception?
// return null;
throw new IllegalStateException();
} else {
// process the request normally
return joinPoint.proceed();
}
}
}
I don't think there is direct way to disable a constructed request mapping but We can disable API in many ways with some condition.
Here is the 2 ways disabling by spring profile or JVM properties.
public class SampleController {
#Autowired
Environment env;
#RequestMapping(value = "/foo", method = RequestMethod.POST)
public String foo(HttpServletResponse response) {
// Using profile
if (env.acceptsProfiles("staging")) {
response.setStatus(404);
return "";
}
// Using JVM options
if("true".equals(System.getProperty("DISABLE_FOO"))) {
response.setStatus(404);
return "";
}
return "";
}
}
If you are thinking futuristic solution using cloud config is the best approach. https://spring.io/guides/gs/centralized-configuration/
Using Conditional components
This allows to build bean with conditions, if the condition failed on startup, the entire component will never be built. Group all your optional request mapping to new controller and add conditional annotation
#Conditional(ConditionalController.class)
public class SampleController {
#Autowired
Environment env;
#RequestMapping(value = "/foo", method = RequestMethod.POST)
public String foo(HttpServletResponse response) {
return "";
}
public static class ConditionalController implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().acceptsProfiles("staging"); // Or whatever condition
}
}
}
You can solve this with annotations by utilizing spring profiles. You define two profiles one for enabled flag and another profile for the disabled flag. Your example would look like this:
#Profile("DISABLED_FLAG")
#RestController
public final class Controller1 {
#RequestMapping(value = "/foo1", method = RequestMethod.POST)
public String foo1()
}
#Profile("ENABLED_FLAG")
#RestController
public final class Controller2 {
#RequestMapping(value = "/foo2", method = RequestMethod.POST)
public String foo2()
}
Here is the link to the spring framework documentation for this feature: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Profile.html
I did it as follows :
#Retention(RUNTIME)
#Target(ElementType.METHOD)
public #interface DisableApiControl {
}
This class is my customization statement. After could use AOP :
for AbstractBaseServiceImpl :
public abstract class AbstractBaseServiceImpl {
private static boolean disableCheck = false;
public void setDisableChecker(boolean checkParameter) {
disableCheck = checkParameter;
}
public boolean getDisableChecker() {
return disableCheck;
}
}
NOTE : The above class has been prepared to provide a dynamic structure.
#Aspect
#Component
public class DisableApiControlAspect extends AbstractBaseServiceImpl {
#Autowired
private HttpServletResponse httpServletResponse;
#Pointcut(" #annotation(disableMe)")
protected void disabledMethods(DisableApiControl disableMe) {
// comment line
}
#Around("disabledMethods(disableMe)")
public Object dontRun(ProceedingJoinPoint joinPoint, DisableApiControl disableMe) throws Throwable {
if (getDisableChecker()) {
httpServletResponse.sendError(HttpStatus.NOT_FOUND.value(), "Not found");
return null;
} else {
return joinPoint.proceed();
}
}
}
checker parameter added global at this point. The rest will be easier when the value is given as true / false when needed.
#GetMapping("/map")
#DisableApiControl
public List<?> stateMachineFindMap() {
return new ArrayList<>;
}

How to intercept setter method with AOP

I want to do something with a field BEFORE it gets the value assigned with a setter. I created the annotation and the aspect, but I don't know how to get the setter. This is my code:
#Aspect
public class AnnotationAspect{
#Pointcut("#annotation(annotationVariableName)")
public void annotationPointCutDefinition(Annotation annotationVariableName){
}
#Pointcut("execution(* *(..))")
public void atExecution(){}
#Around("annotationPointCutDefinition(annotationVariableName) && atExecution()")
public Object aroundAdvice(ProceedingJoinPoint joinPoint, Annotation annotationVariableName) throws Throwable {
Object returnObject = null;
returnObject = joinPoint.proceed();
return returnObject;
}
}
The annotation #Annotation is applied to a field in scala, so the method is "field =" (I don't know if this can change something).
Can anyone help me?
Thanks!
EDIT
This is the annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface Annotation{
}
And an example code:
class Test{
#Annotation
var testing: String =_
}

CDI-Interceptor: Get param from intercepted Method

I have a interface
#InterceptorBinding
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.METHOD, ElementType.TYPE })
public #interface LoggingInterceptorBinding {
}
and a class:
#LoggingInterceptorBinding
#Interceptor
public class LoggingInterceptor implements Serializable {
#AroundInvoke
public Object onMethodCall(InvocationContext context) throws Exception {
try {
System.out.println("Log before Method");
return context.proceed();
} finally {
System.out.println("Log after Method");
}
}
and a annotated method:
#LoggingInterceptorBinding
public void sayHello(String name)
Is it possible to get the parameter "name" from sayHello in the interceptors "onMethodCalls"-method?
The InvocationContext interface has a getParameters() method that
Returns the parameter values that will be passed to the method of the
target class. If setParameters() has been called, getParameters()
returns the values to which the parameters have been set.

Categories

Resources