user5182503
user5182503

Reputation:

How to allow only classes annotated with some annotation in method parameters in Java?

Let's suppose I have annotation @MyAnnotation and two classes:

@MyAnnotation
class Foo {
}

class Bar {
}

and some method that needs class as parameter

someMethod(Class<?> klass)

Is it possible to restrict someMethod parameter only to classes that are annotated with @MyAnnotation? I mean:

someMethod(Foo.class) //Must work
someMethod(Bar.class) //Compiler error

If yes, how to do that?

Upvotes: 0

Views: 2757

Answers (1)

mernst
mernst

Reputation: 8117

Yes, this is possible.

As a general rule, if a property is expressed using an annotation, you will need to use an annotation processor.

Here is a full example that uses the Checker Framework.

File SO61029446.java:

public class SO61029446 {
  void someMethod(Class<? extends @MyAnnotation Object> klass) {}

  void client() {
    someMethod(Foo.class); // Must work
    someMethod(Bar.class); // Compiler error
  }
}

@MyAnnotation
@SuppressWarnings("subtyping")
class Foo {}

class Bar {}

File MyAnnotation.java:

@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@SubtypeOf(UnknownMyAnnotation.class)
@interface MyAnnotation {}

@DefaultQualifierInHierarchy
@Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER})
@SubtypeOf({})
@interface UnknownMyAnnotation {}

Now, run these commands (after installing the Checker Framework):

javacheck MyAnnotation.java
javacheck -g SO61029446.java -processor org.checkerframework.common.subtyping.SubtypingChecker -Aquals=MyAnnotation,UnknownMyAnnotation SO61029446.java

The output of the second command is:

SO61029446.java:11: error: [argument.type.incompatible] incompatible types in argument.
    someMethod(Bar.class); // Compiler error
                  ^
  found   : @UnknownMyAnnotation Class<@UnknownMyAnnotation Bar>
  required: @UnknownMyAnnotation Class<? extends @MyAnnotation Object>

The compiler has complained about the illegal invocation but has permitted the legal invocation, just as you requested.

A few notes:

  • The javacheck command is as described in the Checker Framework Manual.
  • There are two javacheck commands because the first one makes the annotations available on the classpath for the second one.
  • The @SuppressWarnings("subtyping") annotation on the Foo class might not be needed, depending on your actual code. (This is a toy example.)
  • Slaw's answer starts with first sentence "No, this is not possible.", which is incorrect. Slaw's different approach to solving the problem without annotations is not a bad one (in some ways it's better because it uses just the Java compiler without any additional tool), but it does not answer this question about using annotations.

Upvotes: 2

Related Questions