Skip to content
Advertisement

Make method accept only parameter with particular annotation

I have a method

public static void injectConfiguration(@Configurable Object bean) {}

And I have a class which holds field

public class LauncherComponentsHolder {
@Configurable
public RoomDao roomDao;

And I have main class, where I call that method and pass him that:

LauncherComponentsHolder root = new LauncherComponentsHolder();
root.roomDao = new RoomDaoImpl();
root.guestDao = new GuestDaoImpl();
root.maintenanceDao = new MaintenanceDaoImpl();
ConfigInjector.injectConfiguration(root.roomDao);
ConfigInjector.injectConfiguration(root.guestDao);
ConfigInjector.injectConfiguration(root.maintenanceDao);

Problem is that the method accepts all the 3 parameters, (no warnings, errors, nothing) however only roomDao is annotated. Annotation itself:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.FIELD})
public @interface Configurable {

}

How to make the restriction, so that injectConfiguration(@Configurable Object bean) would accept only field (or class instance) annotated with Configurable ?

Advertisement

Answer

You can accomplish this by using an annotation processor. An example of such a tool is the Checker Framework. It enables you to write type annotations in your program, then it type-checks the type annotations at compile time. It issues a warning if the type annotations in your program are not consistent with one another.

The easiest way for you to implement the checking would be to use the Subtyping Checker.

Here is an example from its manual:

import myPackage.qual.Encrypted;

...

public @Encrypted String encrypt(String text) {
    // ...
}

// Only send encrypted data!
public void sendOverInternet(@Encrypted String msg) {
    // ...
}

void sendText() {
    // ...
    @Encrypted String ciphertext = encrypt(plaintext);
    sendOverInternet(ciphertext);
    // ...
}

void sendPassword() {
    String password = getUserPassword();
    sendOverInternet(password);
}

When you invoke javac using a couple extra command-line arguments, javac issues an error for the second invocation of sendOverInternet but not the first one:

YourProgram.java:42: incompatible types.
found   : @PossiblyUnencrypted java.lang.String
required: @Encrypted java.lang.String
    sendOverInternet(password);
                     ^
Advertisement