如何以可重构的安全方式分配方法名称(或注释元素)字符串?

时间:2015-09-22 17:02:23

标签: java reflection annotations refactoring

假设我有一个班级com.example.Foo,另一个班级com.sample.Bar需要知道Foo的完全限定名称。如果我是Java新手,我可能会说:

public class Bar {
    private String fooName = "com.example.Foo";
    //...
}

但是,如果我重构Foo来更改名称或包,则更改不会反映在Bar中,除非IDE非常聪明。所以做这样的事情会更好:

import com.example.Foo;

public class Bar {
    private String fooName = Foo.class.getName();
    // ...
}

这样,如果我重构Foo,则应该Bar选择更改。

现在考虑方法。如果我在类Foo中有一个方法名称并且Bar需要知道该名称,那么我能做的最好就是:

public class Bar {
    private String bazName = Foo.class.getMethod("bazMethod", Qux.class);
    // ...
}

但我实际上没有取得任何成果 - 我仍然有一个字符串文字“bazMethod”,如果真正的bazMethod被重命名,它将不会被重构。

我真正想要的是:

public class Bar {
    private String bazName = tellMeTheMethodName((new Foo()).bazMethod(null));
    // ...
}

不确定这是否可行以及是否有任何解决办法。

现在出现了真正的问题 - 即使您可以按上述方式对其进行排序,我尝试访问的真实内容是注释属性/元素名称。但注释是抽象的,甚至无法实例化。这可能吗?

1 个答案:

答案 0 :(得分:0)

Annotation只是一个接口,您也可以将其子类化! :)例如,注释

public @interface SomeAnno
{
    String attr1();
    int    attr2();
}

你想要一个"静态输入"引用名称的方式" attr1"," attr2"。

这可以通过一些方法中的一些精心设计的阴谋来实现。

String n1 = name( SomeAnno::attr1 );

class MyAnno implements SomeAnno
{
    String attr1(){ ... }

MyAnno.attr1()/attr2()/...每个都会引发明显的副作用; name(action)比较action的副作用,并将其与attr之一进行匹配。

我们可以概括这个技巧来编写一个适用于任何注释类型的通用工具(实际上,任何接口类型)。

SomeAnno anno = proxy(SomeAnno.class);

String n1 = name( anno::attr1 );

但这真的不值得:)你可以只对该名称进行硬编码,并进行运行时检查(尽早)以断言该名称确实有效。