5

如何在@Override使用 javaassist 创建类时向方法添加注释?

ClassPool pool = ClassPool.getDefault();
CtClass ctClasz = pool.makeClass("test.ExampleImpl");
ctClasz.addInterface(pool.get(MyInterface.class.getName()));
CtMethod method = CtNewMethod.make ("@Override public void print() { System.out.println(\"Hello!    \"); }", ctClasz);
ctClasz.addMethod(method);

System.out.println("Implementd: Interfaces:" + ctClasz.getInterfaces());
System.out.println("Methods: " + ctClasz.getMethods());
ctClasz.writeFile("D:");

此代码抛出异常如下:

 Exception in thread "main" javassist.CannotCompileException: [source error] syntax error    
 near "@Override p"
at javassist.CtNewMethod.make(CtNewMethod.java:78)
at javassist.CtNewMethod.make(CtNewMethod.java:44)
at javaassist.Demo.main(Demo.java:17)
 Caused by: compile error: syntax error near "@Override p"
at javassist.compiler.Parser.parseClassType(Parser.java:983)
at javassist.compiler.Parser.parseFormalType(Parser.java:191)
at javassist.compiler.Parser.parseMember1(Parser.java:51)
at javassist.compiler.Javac.compile(Javac.java:89)
at javassist.CtNewMethod.make(CtNewMethod.java:73)
... 2 more
4

3 回答 3

7

@Override不是运行时注释,因此即使您可以添加它,也不会产生任何影响。

对于确实具有运行时效果的注解(RetentionPolicy.RUNTIME),您可以看看这个问题

于 2012-07-03T14:34:42.840 回答
3

精简版

添加注释并不有趣。因为有了这个@java.lang.annotation.Retention(value=java.lang.annotation.RetentionPolicy.SOURCE),它不会有任何区别。所以,你不需要关心这个问题。

我会关心具有@java.lang.annotation.Retention(value=java.lang.annotation.RetentionPolicy.RUNTIME)保留的注释。

长版

此注释具有@java.lang.annotation.Retention(value=java.lang.annotation.RetentionPolicy.SOURCE)保留性,这意味着即使您在生成一些要在运行时使用的类时使用 JAVASSIST 添加它,它也不会改变任何内容。

注释对代码没有任何影响。当 Java 生成源时,这已经被剥离了。由于 JAVASSIST 生成代码,添加它没有任何意义。

根据文档,保留可以配置为:

  • CLASS注释将由编译器记录在类文件中,但不需要在运行时由 VM 保留。
  • RUNTIME注释将由编译器记录在类文件中,并在运行时由 VM 保留,因此可以反射性地读取它们。
  • SOURCE注解将被编译器丢弃。

在 JAVASSIST 中,添加RUNTIMECLASS注释会很有趣(但对于 CLASS,它不会那么有趣,请参见此处)。

于 2012-07-03T14:32:46.830 回答
2

@Override 仅对编译器有用。

它告诉编译器确保带注释的方法:

a. Overrides a method on the superclass
b. Implements an interface method.

当接口或超类发生变化时,这变得特别重要。您的类可能会编译,但您认为在接口上定义功能的方法或超类可能不再这样做。

所以 @Override 注释让编译器在这种情况下对你咆哮。

编辑

例子:

public interface Foo {
    void bar();
}

public class FooImpl {
    public void bar() { ... }
}

public class MyFooExtension extends FooImpl {
    public void bar() { .... }
}

现在,假设 Foo 和 FooImpl 发生变化:

public interface Foo {
    void bar(String input);
}

public class FooImpl {
    public void bar(String input) { ... }
}

你是 MyFooExtension 类仍然可以编译,但该类中的“bar()”方法永远不会被调用。因此,您的方法是无用的。如果您添加@Override 注释,您会收到一个编译错误,告诉您没有方法“void bar()”被覆盖,您必须修复您的类才能使其编译。

于 2012-07-03T19:06:50.630 回答