Can Java Annotations help me with this?

I'm wondering if there is a way to specify that a method gets called in advance of a class method. I know something like this should be posssible, since JUnit has before(), what I want to do is similar.

Here is a concrete example of what I'd like to do

class A {

 public void init(int a) {
  System.out.println(a);
 }

 @magic(arg=1)
 public void foo() { 
   //
 }

 public static void main() {
   A a = new A();
   a.foo();
 }
}

//Output: 1

Basically I want an annotation to tell either the compiler or the jvm call init() before foo()


If you have interface A you can wrap instances of this interface with Proxy and inside invoke method of its InvocationHandler you are free to check whether method is annotated and perform some actions depending on that:

class Initalizer implements InvocationHandler {
    private A delegate;
    Initializer(A delegate) {
        this.delegate = delegate;
    }

    public Object invoke(Object proxy, Method method, Object[] args) {
        if (method.isAnnotationPresent(magic.class)) {
            magic annotation = method.getAnnotation(magic.class);
            delegate.init(magic.arg);
        }
        method.invoke(delegate, args);
    }
} 
A realA = ...;
A obj = Proxy.newProxyInstance(A.class.getClassLoader(), new Class[] {A.class}, new Initializer(realA));

Or you can try using "before" advice of AspectJ. It will be something like the next:

@Aspect
public class Initializer {
    @Before("@annotation(your.package.magic) && target(obj) && @annotation(annotation)")
    private void initialize(A obj, magic annotation) {             
         a.init(annotation.arg);
    }
}

I'm not sure that snippets are working, they just illustrate idea.


Why are you doing this? Are you attempting to avoid having a constructor with many arguments (using setters then calling init) or are you avoiding having many constructors that all have similar arguments? If this is the case, you can use a builder pattern.

public class Foo {
int a, b, c, d, e;
Foo(int a, int b, int c, int d, int e) { this.a=a; /*etc*/ }
}

public class FooBuilder {
int a,b,c,d,e;
FooBuilder A(int a) { this.a=a; return this;}
FooBuilder B(int b) { this.b=b; return this;}
//etc
Foo create(){ return new Foo(a,b,c,d,e);
}

If this doesn't work, I'd suggest looking into AOP. I'd mark the methods that must have init() called already with an annotation [perhaps @requires('init') or the like] and make you AOP framework insert the proper code. Be careful that multiple init's either don't have side effects or that you do proper synchronization on your has_init_been_called state.


只需在foo()的开头调用Init()?

链接地址: http://www.djcxy.com/p/68258.html

上一篇: 你什么时候使用Java的@Override注解,为什么?

下一篇: Java注释可以帮助我吗?