lundi 27 mai 2019

Parametr does not have correct annotation

I am trying to perform null checks on my methods using simple custom @NotNull annotation i.e. I declare method as myMethod(@NotNull String name, String description) and when someone calls this method with null value passed as the 'name' argument an exception is thrown.

I already have an implementation of a simple aspect using aspectj. This solution works quite well for me. The one exception is constructors of inner classes. In such case the aspect crashes because of an exception inside java.lang.reflect.Parameter (I changed some method names):

....
Caused by: java.lang.ArrayIndexOutOfBoundsException: 2
  at java.lang.reflect.Parameter.getDeclaredAnnotations(Parameter.java:305) ~[na:1.8.0_161]
  at java.lang.reflect.Parameter.declaredAnnotations(Parameter.java:342) ~[na:1.8.0_161]
  at java.lang.reflect.Parameter.getAnnotation(Parameter.java:287) ~[na:1.8.0_161]
  at java.lang.reflect.Parameter.getDeclaredAnnotation(Parameter.java:315) ~[na:1.8.0_161]
  at my.package.core.common.validation.ValidationAspect.checkNotNullArguments(ValidationAspect.java:42) ~[ybus-web-1.0.jar:na]
  at my.package.server.web.admin.commission.MyOuterClass$MyInnerAnonymousClass.<init>(MyOuterClass.java:344) ~[ybus-web-1.0.jar:na] at 
....

As far as I can tell this is caused by java passing the enclosing class object as the first argument to the constructor of the inner class (which I was told is standard behavior). The problem is, that params[i].executable.getParameterAnnotations() does not seem to know about the additional argument and returns annotations only for the "normal" parameters

Relevant part of the aspect:

 @Before("anyConstructorWithNotNullParam() || anyMethodWithNotNullParam()")
  public void checkNotNullArguments(
      final JoinPoint joinPoint
  ) {
    final Signature signature = joinPoint.getSignature();
    final Object[] args = joinPoint.getArgs();
    final Parameter[] params = signature instanceof ConstructorSignature
        ? ((ConstructorSignature) signature).getConstructor().getParameters()
        : ((MethodSignature) signature).getMethod().getParameters();

    for (int i = 0; i < args.length; i++) {
        if (args[i] == null && params[i].getDeclaredAnnotation(NotNull.class) != null) {
          throw new IllegalArgumentException("Illegal null argument");
        }
    }
  }

I feel like this is a bug in either aspectj or java.lang.reflection. But as I cannot find any bug report for this, it seems more likely to me that I am doing something wrong. The app runs on java 8 (tried multiple different builds of the oracle jdk and the last openjkd build) and aspectj 1.8.13 (but tried also 1.9.4).

So my question(s): Is this a known bug? Is there some flaw in my implementation? Is there some workaround? (I guess it would not be that hard to match the annotations to the parameters manually. But as I have very limited knowledge about java reflection, I am not really able to foresee the consequences).





Aucun commentaire:

Enregistrer un commentaire