Consider this example, I'm looking for a general solution to this kind of problem though.
I'm working on an annotation processor that creates interfaces for classes, basically copying all their public mehtods. The name (and package) of the interface can be configured using a String parameter. But because the annotation is @Inherited
, there should be the ability to define an InterfaceNamingStrategy
that maps the name of a subclass to its interface name.
I tried to use a dynamic annotation parameter following this answer.
/**
* Generates an interface that contains all public member mehtods of the annotated class.
* This can only be used on top-level classes.
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
@Inherited
@Documented
public @interface GenerateInterface {
/**
* Name of the generated interface. If this is not specified, the {@link #namingStrategy()}
* is used to retrieve the interface name.
* If the name is not fully qualified, the interface will have the same package
* as the annotated class.
*/
String value() default "";
/**
* An implementation of {@link InterfaceNamingStrategy} that returns the interface name
* for a given annotated class. It must be accessible and contain a public no-arg constructor.
*/
Class<? extends InterfaceNamingStrategy> namingStrategy() default InterfaceNamingStrategy.PrefixI.class;
}
/**
* Naming strategy to be used with {@link GenerateInterface}.
*/
public interface InterfaceNamingStrategy {
/**
* @param impl TypeElement representing the annotated class
* @return the name of the generated interface. See {@link GenerateInterface#value()}.
*/
String getInterfaceName(TypeElement impl);
/**
* Will create the interface {@code Foo} for the annotated class {@code FooImpl}
*/
public static class ExceptLastFourChars implements InterfaceNamingStrategy {
@Override
public String getInterfaceName(TypeElement impl) {
return impl.getSimpleName().toString().substring(0, impl.getSimpleName().length()-4);
}
}
/**
* Will create the interface {@code IFoo} for the annotated class {@code Foo}
*/
public static class PrefixI implements InterfaceNamingStrategy {
@Override
public String getInterfaceName(TypeElement impl) {
return "I" + impl.getSimpleName();
}
}
}
This does, however, not work when processing the annotation at compile-time because you can't instantiate the implementation of InterfaceNamingStrategy
as discussed in this question.
Is there any way to pass a dynamic parameter to an annotation that is processed at compile-time?
My current solution would be to use a String parameter and evaluate it as a Groovy closure. But I would prefer a solution using actual type-checked Java code.