【问题标题】:How to create a dynamic Interface with properties file at compile time?如何在编译时使用属性文件创建动态接口?
【发布时间】:2014-10-12 05:28:18
【问题描述】:

这里的问题是我们使用的属性文件有非常大的名称作为键,我们大多数人都会遇到不正确的键命名问题。所以它让我想到是否有一种方法可以根据属性文件生成以下界面。我们对属性文件所做的每一次更改都会自动调整属性界面。还是有其他解决方案?

属性文件

A=Apple
B=Bannana
C=Cherry

应该生成如下接口

interface Properties{
public static final String A = "A" // keys
public static final String B = "B"; 
public static final String C = "C"; 

}

所以在我的应用程序代码中

String a_value = PROP.getString(Properties.A);

【问题讨论】:

  • 看来你正在学习 Maven。
  • 您是否考虑过更改属性文件会在您的应用程序中产生编译错误?我个人会生成一次 Properties 接口,然后手动维护它。也许我会使用枚举而不是接口。

标签: java properties-file


【解决方案1】:

关于编程有一条古老的规则,而不仅仅是关于它,如果某些东西看起来很漂亮,那么它很可能是正确的做法。

在我看来,这种方法看起来不太好。

第一件事:

不要在接口中声明常量。它违反了封装方法。请查看这篇文章:http://en.wikipedia.org/wiki/Constant_interface

第二件事:

为您的属性的名称部分使用前缀,这在某种程度上是特殊,比如说:key_

当您加载属性文件时,迭代键并提取名称以 key_ 开头的键,并使用这些键的值,就像您计划在问题中使用这些常量一样。


更新

假设,我们在编译过程中使用我们的 Apache Ant 脚本生成了一个巨大的属性文件。

例如,让我们的属性文件 (myapp.properties) 看起来像这样:

key_A = Apple
key_B = Banana
key_C = Cherry
anotherPropertyKey1 = blablabla1
anotherPropertyKey2 = blablabla2

我们要处理的特殊属性的键名以key_前缀开头。

所以,我们编写以下代码(请注意,它没有优化,只是概念证明):

package propertiestest;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;


public class PropertiesTest {

  public static void main(String[] args) throws IOException {
       final String PROPERTIES_FILENAME = "myapp.properties";      

       SpecialPropertyKeysStore spkStore = 
                            new SpecialPropertyKeysStore(PROPERTIES_FILENAME);

       System.out.println(Arrays.toString(spkStore.getKeysArray()));

   }
}


class SpecialPropertyKeysStore {

    private final Set<String> keys;

    public SpecialPropertyKeysStore(String propertiesFileName) 
                                    throws FileNotFoundException, IOException {


        // prefix of name of a special property key
        final String KEY_PREFIX = "key_";        

    Properties propertiesHandler = new Properties();
        keys = new HashSet<>();

    try (InputStream input = new FileInputStream(propertiesFileName)) {

            propertiesHandler.load(input);

            Enumeration<?> enumeration = propertiesHandler.propertyNames();
            while (enumeration.hasMoreElements()) {
                String key = (String) enumeration.nextElement();
                if (key.startsWith(KEY_PREFIX)) {
                    keys.add(key);
                }
            }
    }        
    }

    public boolean isKeyPresent(String keyName) {
        return keys.contains(keyName);
    }

    public String[] getKeysArray() {
        String[] strTypeParam = new String[0];

        return keys.toArray(strTypeParam);
    }
}

SpecialPropertyKeysStore 类过滤并将所有特殊键收集到其实例中。

你可以得到这些键的数组,或者检查键是否存在。

如果你运行这段代码,你会得到:

[key_C, key_B, key_A]

它是返回数组的字符串表示,带有特殊的键名。

根据您的要求更改此代码。

【讨论】:

  • 您可以在编译时修改您的属性文件,例如 - 使用 Apache Ant。在这种情况下,您无需更改代码。只需根据需要修改属性文件。您的代码将使用所描述的方法提取所有属性。
  • 答案不清楚。你的意思是迭代键并提取键?
  • Properties类中,有一个方法propertyNames。调用它以获取带有属性名称的Enumeration。遍历此枚举以获取属性名称并进行处理。要检查属性名称是否以key_ 开头(例如),请使用String.startsWith 方法。
  • 哦,这是获取财产的惯常做法,不是吗?在这种情况下,属性键非常容易出错。所以希望它被生成到一个接口字段,这样我们就不会使用硬编码键产生任何错误。
【解决方案2】:

我不会从属性生成类或接口,因为您将失去以下能力:

  • 记录这些属性,因为它们将由 java 元素 + javadocs 表示
  • 在您的代码中引用这些属性,因为它们将播放旧的 java 常量,并且编译器将完全了解它们。重构它们也是可能的,而使用自动名称则不可能。

您也可以使用枚举,或创建一些特殊的Property 类,名称仅作为最终字段。然后,您只需要一个get 方法,该方法将采用PropertiesMap 或其他。

对于您的请求,您可以使用maven-exec-plugin 执行代码。

您应该简单地创建一个可以读取您的属性文件的 main,并为每个键:

  • 将密钥转换为有效的java标识符(您可以使用isJavaIdentifierStartisJavaIdentifierPart将无效字符替换为_
  • 使用普通的旧 Java 编写您的类/接口/您喜欢的任何内容(不要忘记为最终的双引号或反斜杠转义!)

由于它将成为您构建的一部分,因此在构建其他依赖于这些常量的类之前,我建议您创建一个特定的 maven 项目来隔离这些构建。

不过,我真的不会这样做,而是使用加载了任何需要(CDI、Spring、静态初始化等)的 POJO。

【讨论】:

    猜你喜欢
    • 2011-03-27
    • 1970-01-01
    • 2011-05-30
    • 1970-01-01
    • 1970-01-01
    • 2021-09-12
    • 2023-02-01
    • 1970-01-01
    • 2021-05-11
    相关资源
    最近更新 更多