How to create a dynamic Interface with properties file at compile time?

蹲街弑〆低调 提交于 2019-12-19 10:21:27

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!