问题
The problem here is that the property file we use has insanely huge name as the key and most of us run into incorrect key naming issues . so it got me thinking if there's a way to generate the following interface based on the property file. Every change we make to the property file will auto-adjust the Properties interface. Or is there other solution?
Property File
A=Apple
B=Bannana
C=Cherry
Should Generate The following Interface
interface Properties{
public static final String A = "A" // keys
public static final String B = "B";
public static final String C = "C";
}
So in my application code
String a_value = PROP.getString(Properties.A);
回答1:
There is an old rule about programming and not only about it, if something looks beautiful, then most probably it is the right way to do.
This approach does not look good, from my point of view.
The first thing:
Do not declare constants in interfaces. It violates the incapsulation approach. Check this article please: http://en.wikipedia.org/wiki/Constant_interface
The second thing:
Use a prefix for name part of your properties which are somehow special, let say: key_
And when you load your properties file, iterate over keys and extract keys with name that starts with key_
and use values of these keys as you planned to use those constants in your question.
UPDATE
Assume, we generate a huge properties file upon compilation process, using our Apache Ant script.
For example, let's properties file (myapp.properties
) looks like that:
key_A = Apple
key_B = Banana
key_C = Cherry
anotherPropertyKey1 = blablabla1
anotherPropertyKey2 = blablabla2
our special properties which we want to handle have key names start with key_
prefix.
So, we write the following code (please note, it is not optimized, it is just proof of concept):
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);
}
}
Class SpecialPropertyKeysStore
filters and collects all special keys into its instance.
And you can get an array of these keys, or check whether is key present or not.
If you run this code, you will get:
[key_C, key_B, key_A]
It is a string representation of returned array with special key names.
Change this code as you want to meet your requirements.
回答2:
I would not generate a class or interface from properties because you would lose the abilities to :
- document those properties, as they would be represented by a java element + javadocs
- references those properties in your code, as they would be play old java constant, and the compiler would have full knowledge of them. Refactoring them would also be possible while it would not be possible with automatic names.
You can also use enums, or create some special Property
class, with a name as only and final field. Then, you only need a get
method that would take a Properties
, a Map
or whatever.
As for your request, you can execute code with the maven-exec-plugin.
You should simply create a main that would read your properties file, and for each keys:
- convert the key to a valid java identifier (you can use isJavaIdentifierStart and isJavaIdentifierPart to replace invalid char by a
_
) - write your class/interface/whatever you like using plain old Java (and don't forget to escape for eventual doublequote or backslashes !)
Since it would be a part of your build, say before building other classes that would depends on those constants, I would recommend you to create a specific maven project to isolate those build.
Still, I would really don't do that and use a POJO loaded with whatever need (CDI, Spring, Static initialization, etc).
来源:https://stackoverflow.com/questions/25377900/how-to-create-a-dynamic-interface-with-properties-file-at-compile-time