Java tricks. Implementing annotations

Say, as it is popular now, you want to have possibility of either static (annotation-based) or dynamic (xml/db-based) configuration of your piece of programming mastership. For instance, your application should support some basic privilege-based security, so, we’ll define @Privilege annotation:

package annotations;
 
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Privilege {
    String code();
}

And a class using it:

@Privilege(code="manage.account")
public class AccountController {}

Abstracting from the details of implementation, the handling of the annotation might look like this:

public class SecurityInterceptor {
 
    public Object intercept(User user, Object controller) {
        annotations.Privilege priv = getPrivilege(controller);
        user.hasPrivilege(priv.code());
    }
 
    protected annotations.Privilege getPrivilege(Object controller) {
        return controller.getClass().getAnnotation(annotations.Privilege.class);
    }
}

Now, we want to be able to configure another controller, OrderController, in a more dynamic way, e.g. by loading the following configuration:

<controller class="OrderController">
    <privilege>manage.account</privilege>
</controller>

So we need to have an object representation for privilege:

public class Privilege {
    public String getCode() { return code; }
    private String code;
}

and a privilege-aware controller:

public class SecuredController {
    public SecuredController(Privilege priv) { this.privilege = priv; }
    public Privilege getPrivilege() { return privilege; }
}
 
public class OrderController extends SecuredController {
    public OrderController(Privilege priv) { super(priv); }
}

See how Privilege and @Privilege are similar? (yeh, I tried to make it obvious ;) )… And in the declaration of annotations.Privilege there is an interface keyword… hm, does it mean we can implement the annotation? Why not! So here we go:

public class Privilege implements annotations.Privilege {
    public String getCode() { return code; }
    public String code() { return getCode(); }
    private String code;
}

And the last stroke is to slightly modify SecurityInterceptor‘s getPrivilege method (of course, being developers of good manners, we shall follow Open-Close Principle):

public class EnhancedSecurityInterceptor extends SecurityInterceptor {
 
    protected annotations.Privilege getPrivilege(Object controller) {
        return (controller instanceof SecuredController) ?
            ((SecuredController) controller).getPrivilege() :
            controller.getClass().getAnnotation(annotations.Privilege.class);
    }
}

Note: the java compiler will threaten you with “Annotation is used as super interface” warning, but you should remain brave and confident!

Moral of the story: reuse code and reduce your maintenance effort!

Feel free to comment, criticise and share your feelings.

Tags: ,

  • ctapobep

    Wow, that was really useful! Didn’t think about putting annotations this way.