1

I have functions that include different javax Query annotations like : @QueryParam , @Context , @PathParam etc..

is there a way to exclude these parameters when calling joinPoint.getArgs()?

Example:

    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("{pathParam}/v1/{pathParam2}/")
    @MyAnnotation
    public Response update(@PathParam("pathParam") String p1, @PathParam("pathParam2") int p2, MyObject x);



    @Before("@annotation(MyAnnotation)")
        public void doSomething(JoinPoint joinPoint){
            Object[] objects = joinPoint.getArgs(); // HERE - is there a way to get only MyObject and not other params..?
    }

The reason I want to do it is that I have several urls, while marking ~10% as persistent. It means that I want the input data to be saved in some persistent service. The Query & Context params are not important to me, but the input data itself is.

user1386966
  • 3,302
  • 13
  • 43
  • 72
  • Please describe what you want to achieve, not how you think it should be done. Then I am quite optimistic that I can help you. You are making the same mistake as many unexperienced and even some experienced developers: You have a technical solution in mind instead of the requirement and thus are no longer open-minded enough to see alternatives to achieve what you want to. Show some more sample code which explains what happens in your situation and what you wish to happen instead. – kriegaex Mar 02 '17 at 10:36
  • I guess you are right - i will edit now the question . Thank you – user1386966 Mar 02 '17 at 15:41
  • The question still only consists of incoherent snippets. The smart way to ask a question is to enable others to reproduce the problem and more easily answer them. Otherwise they will feel reluctant to answer and you are just hurting yourself. You should always try to provide an [SSCCE](http://sscce.org/). But anyway, I was just bored and prepared an answer for you. On another day I would not have done this. Don't be so lazy! – kriegaex Mar 02 '17 at 16:24

3 Answers3

3

Assuming you really use full AspectJ and not Spring AOP like so many others, you should be aware of the fact that in full AspectJ @annotation(XY) potentially matches not just execution() joinpoints but also call(), i.e. your advice will be triggered twice. Even worse, if other places than method executions are also annotated - e.g. classes, fields, constructors, parameters - the pointcut will also match and your try to cast to MethodSignature will cause an exception as a consequence.

Furthermore, please note that in @AspectJ syntax you need to provide the fully qualified class name of the annotation you want to match against, i.e. don't forget to also prepend the package name. Otherwise there will be no match at all. So before doing anything else you want to change your pointcut to:

@annotation(de.scrum_master.app.MyAnnotation) && execution(* *(..))

Now here is a fully self-consistent example, an SSCCE producing repeatable results, as requested by me in the comment under your question:

Annotation:

package de.scrum_master.app;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}

Driver application:

As you can see, the test method has parameters with different types of annotations:

  1. only javax annotation
  2. javax + own annotation
  3. only your own annotation
  4. no annotation

We want to ignore #1/2 and only print #3/4.

package de.scrum_master.app;

import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;

public class Application {
  public static void main(String[] args) {
    new Application().update("foo", 11, "bar", 22);
  }

  @MyAnnotation
  public Response update(
    @PathParam("pathParam") String p1,
    @PathParam("pathParam2") @MyAnnotation int p2,
    @MyAnnotation String text,
    int number
  ) {
    return null;
  }
}

Aspect:

Just as user Andre Paschoal started to show in his code fragment, you need to iterate over both the arguments and annotations arrays in order to pull off the filtering trick. I think it is quite ugly and possibly slow just for logging's sake (and I assume this is what you want to do), but for what it is worth, here is your solution:

package de.scrum_master.aspect;

import java.lang.annotation.Annotation;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;

@Aspect
public class ParameterFilterAspect {
  @Before("@annotation(de.scrum_master.app.MyAnnotation) && execution(* *(..))")
  public void doSomething(JoinPoint joinPoint) {
    Object[] args = joinPoint.getArgs();
    MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
    Annotation[][] annotationMatrix = methodSignature.getMethod().getParameterAnnotations();
    for (int i = 0; i < args.length; i++) {
      boolean hasJavaxAnnotation = false;
      for (Annotation annotation : annotationMatrix[i]) {
        if (annotation.annotationType().getPackage().getName().startsWith("javax.")) {
          hasJavaxAnnotation = true;
          break;
        }
      }
      if (!hasJavaxAnnotation)
        System.out.println(args[i]);
    }
  }
}

Console log:

bar
22

Tadaa! :-)

kriegaex
  • 63,017
  • 15
  • 111
  • 202
  • First of all thank you very much for the detailed answer. I tried doing it but getting null as Annotation. From my search here, I saw that my annotation is located in front of an interface like that : function (@QueryParam("something") boolean something). When implementing this interface - the annotation does not exist. So when I put my annotation after the @Override of the function - i don't get any annotation but it works. When putting it in the interface I get the following error: ...has not been applied [Xlint:adviceDidNotMatch] – user1386966 Mar 05 '17 at 08:29
  • That is not an AspectJ problem but a known limitation in the JVM: Annotations are never inherited from interface to implementing class, also not from method to overriding method. The only existing annotation inheritance is from class to subclass, but only if the annotation itself is annotated by [`@Inherited`](https://docs.oracle.com/javase/8/docs/api/java/lang/annotation/Inherited.html?is-external=true). See also [this answer](http://stackoverflow.com/a/35680800/1082681). So your real situation is different from what you described in your question. – kriegaex Mar 05 '17 at 09:03
  • Because I have answered this question several times before, I have just documented the problem and also a workaround in [Emulate annotation inheritance for interfaces and methods](http://stackoverflow.com/questions/42607015/emulate-annotation-inheritance-for-interfaces-and-methods) – kriegaex Mar 05 '17 at 10:09
  • thanks, I was sure it is will be similar (interface via implementation). I will take a look at these answers you've posted! thanks a lot – user1386966 Mar 05 '17 at 11:31
0

I don't think there's a magic way to do this, so go with the obvious:

  • define your argument acceptance criteria;
  • iterate over the args and filter based on the previously defined criteria and that's it.

It seems that your acceptance criteria is that the arg is not annotated with these javax annotations, right ?

Try this:

Object[] args = joinPoint.getArgs();
Annotation[][] anns = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterAnnotations();

for (int i = 0; i < args.length; i++) {
    for (int j = 0; j < args[i].length; j++) {
        // check here for the annotations you would like to exclude
    }
}
Andre Paschoal
  • 332
  • 2
  • 7
0

this snippet code works for me:

Annotation[][] anns = ((MethodSignature)   thisJoinPoint.getSignature()).getMethod().getParameterAnnotations();

parameterValues = thisJoinPoint.getArgs();
signature = (MethodSignature) thisJoinPoint.getSignature();
parameterNames = signature.getParameterNames();
if (parameterValues != null) {
    for (int i = 0; i < parameterValues.length; i++) {

        boolean shouldBeExcluded = false;
        for (Annotation annotation : anns[i]) {
            if (annotation instanceof ExcludeFromCustomLogging) {//<<---------ExcludeFromCustomLogging is my class
                shouldBeExcluded = true;
                break;
            }
        }
        if (shouldBeExcluded) {
            //System.out.println("should be excluded===>"+parameterNames[i]);
            continue;
        }

  //.......and your business

}
adiga
  • 34,372
  • 9
  • 61
  • 83
M.Namjo
  • 374
  • 2
  • 13