动态填充字符串';从Java中的属性文件中删除

动态填充字符串';从Java中的属性文件中删除,java,properties,Java,Properties,有人知道加载属性文件并动态创建与键值同名的字符串的方法吗 我试图通过将所有系统消息等从逻辑中移出并放入属性文件来清理代码,但希望避免使用由几十行组成的类,如下所示: final String COMMS_ERROR = properties.getProperty(COMMS_ERROR); 我正在努力实现的一个例子: for (String key : properties.getPropertyValues()) { final String <key> = prope

有人知道加载属性文件并动态创建与键值同名的字符串的方法吗

我试图通过将所有系统消息等从逻辑中移出并放入属性文件来清理代码,但希望避免使用由几十行组成的类,如下所示:

final String COMMS_ERROR = properties.getProperty(COMMS_ERROR);
我正在努力实现的一个例子:

for (String key : properties.getPropertyValues()) {
    final String <key> = properties.getProperty(key)
}
其中HM是com.x.y.messages中的HashMap

理想情况下,我只希望能够做到:

import com.x.y.messages;
....
    throw new Exception(COMMS_ERROR);

任何想法/建议都值得赞赏。

您不能动态声明局部变量,但可以使用映射:

Map<String, String> messages = new HashMap<String, String>();

for (String key : properties.getPropertyValues()) {
    messages.put(key, properties.getProperty(key));
}

但事实上,正如Thomas在上面指出的,您不需要一个新的HashMap

throw new Exception( properties.getProperties(key) );

如果这些属性在编译后可以更改(如果不能,那么为什么要使用它们),您就没有机会动态创建和使用这些字符串。当然,有一些方法可以动态创建代码(如AOP运行时编织),但这些代码在正常编译过程中不可用

那么编译器如何知道
COMMS\u ERROR
实际上存在于这一行
抛出新异常(COMMS\u ERROR)?它不能,因此您需要使用
HashMap
方法。请注意,
Properties
实际上是一个
Map
(好的,从Java6开始,它是一个
Hashtable
,但它的行为类似于
Map
),因此无需创建新的映射

编辑:您可以这样使用静态导入:

package yourpackage;

public class Props
{
  private static Properties props;

  public static String prop(String prop)
  {
    return props.getProperty( prop );
  }
}
import static yourpackage.Props.prop;

....

prop("someKey");
public final class Constants{

    private Constants(){}
    public static final String SOME_PROPERTY_NAME = "some.property.name";
    public static final String THIS_ONE_NOT_SET_YET = null;
    public static final String PROPERTY_NOT_DEFINED = "property.not.defined";

}
some.property.name=Hello World
no.constant.for.this.yet=Hello again
像这样使用它:

package yourpackage;

public class Props
{
  private static Properties props;

  public static String prop(String prop)
  {
    return props.getProperty( prop );
  }
}
import static yourpackage.Props.prop;

....

prop("someKey");
public final class Constants{

    private Constants(){}
    public static final String SOME_PROPERTY_NAME = "some.property.name";
    public static final String THIS_ONE_NOT_SET_YET = null;
    public static final String PROPERTY_NOT_DEFINED = "property.not.defined";

}
some.property.name=Hello World
no.constant.for.this.yet=Hello again

请注意,静态导入有它的缺点,比如看起来方法好像是它使用的类的一部分,所以我只想提供一个替代方案,让您决定是否使用它。

我不知道有什么工具可以做到这一点,而且它不适合正常的Java方式。(在Java中,不能动态添加新变量……例如,与Javascript不同。)

从理论上讲,可以按照这些思路实现一些东西,但可能需要为每种属性文件生成和编译一个类,并根据这些类API重新编译其余代码。除非您有大量的这些属性文件,否则手工编写类就更容易了。(如果您确实有大量这些属性文件,我倾向于看看是否有更好的方法来处理这些文件中的信息。)



是的,这就是我所希望的——一个包含必要魔法的图书馆

不幸的是,没有一个普通的图书馆能做到这一点。生成/重新编译必须在构建时进行。(库可以在运行时生成类,甚至编译和加载它们。但是让它在运行时重新编译应用程序的其余部分充其量是困难的,而且通常是不可能的……因为源代码不可用。)

有什么问题吗

        Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources( "com/x/y/message.properties" );

        while( resources.hasMoreElements() ) {
            URL url = resources.nextElement();
            Properties p = new Properties();
            p.load( url.openStream() );
            ...
        }

我以前自己编写过帮助器类,使属性文件与常量类保持同步。但这只有在你坚持传统的情况下才有效

假设您有这样一个类:

package yourpackage;

public class Props
{
  private static Properties props;

  public static String prop(String prop)
  {
    return props.getProperty( prop );
  }
}
import static yourpackage.Props.prop;

....

prop("someKey");
public final class Constants{

    private Constants(){}
    public static final String SOME_PROPERTY_NAME = "some.property.name";
    public static final String THIS_ONE_NOT_SET_YET = null;
    public static final String PROPERTY_NOT_DEFINED = "property.not.defined";

}
some.property.name=Hello World
no.constant.for.this.yet=Hello again
以及类似以下内容的属性文件:

package yourpackage;

public class Props
{
  private static Properties props;

  public static String prop(String prop)
  {
    return props.getProperty( prop );
  }
}
import static yourpackage.Props.prop;

....

prop("someKey");
public final class Constants{

    private Constants(){}
    public static final String SOME_PROPERTY_NAME = "some.property.name";
    public static final String THIS_ONE_NOT_SET_YET = null;
    public static final String PROPERTY_NOT_DEFINED = "property.not.defined";

}
some.property.name=Hello World
no.constant.for.this.yet=Hello again
我的helper类要做的是循环所有属性和常量,进行匹配并识别那些与任何内容都不对应的内容

因此,在这种情况下:

(a)

在Constants.java中

public static final String THIS_ONE_NOT_SET_YET = null;
将更改为

public static final String THIS_ONE_NOT_SET_YET = "this.one.not.set.yet";
在属性文件中,将引入以下行:

this.one.not.set.yet=
(b)

在属性文件中,将添加此行

property.not.defined=
(c)

在Constants.java中,将添加以下行:

public static final String NO_CONSTANT_FOR_THIS_YET = "no.constant.for.this.yet";
这并不完美,但这样可以获得伪编译时安全性。您根据常量进行编译,您的助手将这些常量与属性保持同步

显然,如果有更高级的场景,这种方法会变得更加复杂。 例如

  • 以“foo.”开头的属性存储在“foo.Properties”中,而名为“bar.”的属性存储在“bar.Properties”中
  • 国际化:现在有了foo.properties、foo.properties.es、foo.properties.de等。保持同步是一个重要的优点

可能需要考虑的是,在构建过程中,从一个或多个属性文件动态创建常数类。您的代码生成器(主类、Groovy脚本甚至shell脚本)基本上只需执行以下操作(伪代码):


它看起来几乎和我的图书馆一样!请查看:

例如:

# Properties file (call it the same name as the Java class and put 
# it in the same package
port=80
hostname=foobar.com
maxThreads=100

//properties mapper interface
public interface ServerConfig extends Config {
    int port();
    String hostname();
    int maxThreads();
}

// how you use it:

ServerConfig cfg = ConfigFactory.create(ServerConfig.class);
System.out.println("Server " + cfg.hostname() + ":" + cfg.port() + " will run " + cfg.maxThreads());

但是,您可以使用OWNER库做更多的工作。

一个设计,其中必须有与它们包含的值同名的字符串引用,这似乎是一个有问题的设计。嗯?字符串不是以它们包含的值命名的,也就是说,我没有执行字符串COMMS_ERROR=“COMMS_ERROR”,这会很奇怪。是的,这就是我所希望的——一个包含必要魔法的库。通常Apache有一些适合的东西,我想HashMap必须这样做。一个有效的观点——我想这样做的唯一原因是简洁,即get()而不是getProperty()。谢谢你的反馈。