Java Annotations可以帮助我解决这个问题吗?

时间:2009-09-22 13:07:54

标签: java annotations

我想知道是否有办法指定在类方法之前调用方法。我知道这样的事情应该是可能的,因为JUnit之前有(),我想做的是类似的。

以下是我想做的具体例子

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

基本上我想要一个注释来告诉编译器或jvm调用init()之前foo()

7 个答案:

答案 0 :(得分:8)

如果你有interface A,你可以用ProxyInvocationHandlerinvoke方法包装这个接口的实例,你可以自由检查方法是否被注释并执行一些行动取决于:

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));

或者您可以尝试使用AspectJ的“之前”建议。它将类似于下一个:

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

我不确定片段是否有效,它们只是说明了想法。

答案 1 :(得分:3)

你为什么要这样做?您是否试图避免使用具有许多参数的构造函数(使用setter然后调用init)或者您是否避免使用许多具有相似参数的构造函数?如果是这种情况,您可以使用构建器模式。

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);
}

如果这不起作用,我建议调查AOP。我将使用注释[也许是@requires('init')等标记必须具有init()的方法)并使AOP框架插入正确的代码。注意多个init没有副作用,或者你在has_init_been_called状态下进行了正确的同步。

答案 2 :(得分:2)

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

答案 3 :(得分:2)

AOP使用所谓的切入点来做到这一点 AspectJ可能拥有你需要的东西。

简单来说,你可以在你的foo()方法的建议之前添加,这会调用init()

答案 4 :(得分:1)

在java语言中没有直接的方法。您在JUnit中看到的是通过首先调用@Before注释的方法来决定如何运行方法的框架。找到带注释的方法并运行它们非常容易,但这是调用者的责任。

您提出的问题太简单,无法找到正确的解决方案。 AspectJ通过操作字节代码(通过更改字节码来调用foo()实际上调用init()方法来解决这个问题),但是我无法想象将其作为解决问题的方法。 / p>

如果您可以向此类提供接口或包装器对象,则可以这样做。但我建议你在一个单独的问题中首先发布让你陷入这种情况的丑陋黑客,然后发布你当前的黑客解决方案如何要求拦截方法调用以及为什么会这样,如果有更好的话解决方法。这样我们就可以更好地帮助解决潜在需求。

答案 5 :(得分:0)

看看AspectJ。它会帮助你做你想要的。

答案 6 :(得分:0)

我认为这里的问题如下:

  1. 您有一个可以部分构建对象的构造函数,但由于必须构造类的方式,因此无法完全构建它。 (我无法想象一个例子。)
  2. 所以你需要一个init()方法来完成构建。
  3. 所以你想要保证在构造函数之后立即调用init()
  4. 我的建议是使用工厂对象或方法。最简单的方法是将构造函数设为私有,使用构造函数的参数或类似的东西添加construct()方法,然后让construct()方法创建对象并调用{{1} },然后返回。