通过自定义注解注入常量

Injecting Constants via Custom Annotation

我的代码中有一堆常量,用于我系统的各种可调整属性。我正在将它们全部移动到中央 .properties 文件中。我当前的解决方案是使用一个 Properties.java 静态加载 .properties 文件并公开各种 getter 方法,如下所示:

public class Properties {
    private static final String FILE_NAME = "myfile.properties";
    private static final java.util.Properties props;

    static {
        InputStream in = Properties.class.getClassLoader().getResourceAsStream(
                FILE_NAME);
        props = new java.util.Properties();
        try {
            props.load(in);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static String getString(Class<?> cls, String key) {
        return props.getProperty(cls.getName() + '.' + key);
    }

    public static int getInteger(Class<?> cls, String key) {
        return Integer.parseInt(getString(cls, key));
    }

    public static double getDouble(Class<?> cls, String key) {
        return Double.parseDouble(getString(cls, key));
    }
}

唯一的问题是,对于我从该文件中获得的每个常量,我都有一些样板文件:

private final static int MY_CONSTANT = Properties.getInteger(
    ThisClass.class, "MY_CONSTANT");

我不认为我想使用 Spring 或类似的东西,因为这看起来更像样板。我希望使用自定义注释来解决这个问题。我找到了 this tutorial,但我无法真正弄清楚如何从注释处理中获得我想要的功能。 Java 文档的帮助甚至更少。不过,这应该是我应该能够在编译时做的事情。我知道 class 和字段的名称。

我的想法是这样的:

@MyAnnotation
private static final int MY_CONSTANT;

有人知道我将如何着手做这件事,或者至少知道我想做的事情的最佳实践吗?

其实不是很清楚你为什么要存档,要存档什么。

据我正确理解,您希望使用特殊类型的注释自动为某些 properties 文件中的 static final 常量赋值。不幸的是,没有特殊技巧是不可能的。注释与此无关。

原因是final字段必须初始化,这是编译器的要求。 java 中没有特殊注释可以提供您想要的语法糖。

但如果你坚持这样做,有两种方法:

  1. Extrim 方式。使用默认值初始化所有属性字段。然后在某些 static 初始化部分使用 this hack 使用 reflection 机制初始化此值,然后通过从 properties.

  2. 读取值进行编码
  3. Less extrim方式:拒绝对属性字段的final修饰符的请求,并且仅使用reflection填充这些字段值。

此外,对于这些方式,您可以使用注释。但您必须解决以下技术问题:

1) 查找classpath中所有classes中的所有字段,其中注解有你特殊的annotation。看着: Get all of the Classes in the Classpath and Get list of fields with annotation, by using reflection

2) 强制您的 Properties class 在您的应用程序的所有可能输入点中被 初始化 。在此 class 的静态部分中,您将加载属性文件,然后使用 (1) 方法与反射和 classloader,为所有常量赋值。

首先,你不应该这样做。它很实用,但是太老套了,如果您想使用不同的设置编写测试,您会 运行 遇到问题。而且,没有人会明白它是如何工作的。

注释处理器可能无法为您做任何事情。一个 Lombok 风格的黑客处理器可以。你想制作

@MyAnnotation
private static final int MY_CONSTANT;

一样工作
private final static int MY_CONSTANT =
    Properties.getInteger(ThisClass.class, "MY_CONSTANT");

原始表达式无法编译(由于未初始化的 final 变量),但它可以很好地解析并且 Lombok 可以完成它的工作。那里已经有相关内容:

所以实际上,你可以只写

@MyAnnotation
int MY_CONSTANT;

并让您的注释也更改修饰符。我会查看 @UtilityClasseclipse and javac 处理程序,我猜你所需要的只是生成初始化程序(这是相当多的工作,因为它太复杂了)。

我认为 Lombok 本身不会很快实现这一点,因为

  • 所有 static 东西都是不可测试的,而且大部分都是糟糕的风格
  • 并不是每个人都希望在他们的代码中使用这个
  • 没有那么多样板文件
  • 它也神奇地引用了 class Properties,但这可以通过 configuration
  • 来解决

但我猜贡献可能会被接受。