2013-07-23 4 views
5

Ich habe einen Code, der eine Klasse verwendet, die eine große Menge hardcoded Constans enthält. Dies ist, wie es aussieht:Wie wird von einer fest codierten statischen Konfigurationsdatei in eine .properties-Datei gewechselt?

class Constants{ 
    public static final String name1 = "value1"; 
    public static final String name2 = "value2"; 
    public static final Integer value3 = 3; 
    ... and so on 
} 

Diese Konstanten überall in dem Code wie Constants.name1 verwendet werden.

Was ich jetzt tun muss, ist es möglich, Werte für diese Konstanten in einer Konfigurationsdatei, wahrscheinlich eine *.properties Datei, anzugeben.

Meine Frage ist: Was ist der beste Weg, es zu tun, so wenig Code wie möglich neu schreiben?

Ich dachte an die Verwendung einer einzigen Konfigurationsklasse, die Eigenschaften aus Datei liest, wenn instanziiert, aber dann muss ich alle statischen Aufrufe von Werten zu Aufrufen zu einer Instanz dieser Klasse ersetzen und ich muss bestehende ändern Methoden, um diese Konfigurationsinstanz an sie zu übergeben. Gibt es einen besseren Weg?

+0

Ich denke, Ihr Konzept kann mit dem NLS-Konzept von Eclipse erreicht werden. Obwohl es osgi jar ist, kann es in Nicht-OSGI-Projekten verwendet werden. –

Antwort

4

hier ein Stück eines Codes, die ich in der Vergangenheit verwendet habe -, die Ihr Beispiel angepasst werden kann:

public enum Configuration { 

    PROPERTY1("property1.name", "default_value_1"), 
    PROPERTY2("property2.name", "default_value_2"); 

    private final String key; 
    private String defaultValue; 

    Configuration(String key) { 
     this(key, NA); 
    } 

    Configuration(String key, String defaultValue) { 
     this.key = key; 
     this.defaultValue = defaultValue; 
    } 
    private final static Logger logger = LoggerFactory.getLogger(Configuration.class); 
    private final static String NA = "n.a."; 
    private final static String CONFIG_FILE = "properties/config.properties"; 
    private final static String NOT_A_VALID_KEY = "Not a valid property key"; 
    private final static Map<Configuration, String> configuration = new EnumMap<>(Configuration.class); 

    static { 
     readConfigurationFrom(CONFIG_FILE); 
    } 

    private static void readConfigurationFrom(String fileName) { 
     logger.info("Reading resource: {}", fileName); 
     try (InputStream resource = Configuration.class.getClassLoader().getResourceAsStream(fileName);) { 
      Properties properties = new Properties(); 
      properties.load(resource); //throws a NPE if resource not founds 
      for (String key : properties.stringPropertyNames()) { 
       configuration.put(getConfigurationKey(key), properties.getProperty(key)); 
      } 
     } catch (IllegalArgumentException | IOException | NullPointerException e) { 
      logger.error("Error while reading the properties file {}", fileName, e); 
      populateDefaultValues(); 
     } 
    } 

    private static Configuration getConfigurationKey(String key) { 
     for (Configuration c : values()) { 
      if (c.key.equals(key)) { 
       return c; 
      } 
     } 
     throw new IllegalArgumentException(NOT_A_VALID_KEY + ": " + key); 
    } 

    private static void populateDefaultValues() { 
     for (Configuration c : values()) { 
      configuration.put(c, c.defaultValue); 
     } 
    } 

    /** 
    * @return the property corresponding to the key or null if not found 
    */ 
    public String get() { 
     return configuration.get(this); 
    } 
} 
+0

+1; Ich mag die Verwendung von Enum über Klasse, obwohl es auf den ersten Blick Config-Typen verschiebt und/oder ignoriert. –

+0

@DaveNewton Ja, es ist nur String basiert. Das gleiche Prinzip kann jedoch auch auf private statische Endelemente angewendet werden, die im statischen Block initialisiert werden können. – assylias

+0

Dies ist die einzige nicht manuelle Lösung, +1 dafür – skiwi

3

Laden Sie die Eigenschaften aus der Datei mit Properties.load(...) und weisen Sie die Konstanten aus diesen Eigenschaften zu.

class Constants{ 
    public static final String name1; 
    public static final String name2; 
    public static final Integer value3; 

    static{ 
    Properties p = new Properties(); 
    try (FileInputStream stream = new FileInputStream(new File("path/to/file.properties"))) {   
     p.load(stream); 
    }catch(Exception e){ 
     //handle exceptions 
    } 

    name1 = p.getProperty("name1"); 
    name2 = p.getProperty("name2"); 
    value3 = Integer.valueOf(p.getProperty("value3")); 
} 

Beachten Sie, dass dies nur eine schnelle und schmutzige Lösung ist und eine Menge Annahmen trifft. Es wäre besser, die einzelnen Ausnahmen zu behandeln, und Sie müssen auch die NumberFormatException behandeln, die von Integer.valueOf(...) ausgelöst werden kann, wenn die Konfiguration entweder leer ist oder keine Nummer.

Noch ein Hinweis: Sie können auch versuchen, einige nicht statische oder zumindest nicht endgültige Konfigurationen zu verwenden, um Eigenschaften zur Laufzeit ändern zu können.

Bearbeiten: Ich habe autoclose für den Stream hinzugefügt, aber beachten Sie, dass vor Java 7 Sie selbst damit umgehen müssen.

+0

@DaveNewton oder ich könnte ihm einfach sagen, was zu tun ist und es so lassen. Das (Codebeispiel kommt) sollte ihm eine schnelle Antwort geben und ihn dazu bringen, es in einigen Augenblicken noch einmal zu überprüfen. – Thomas

+0

Hält 'p.load()' sich darum, den 'FileInputStream' zu schließen? – skiwi

+0

@skiwi nein, tut es nicht. Ich werde einen Hinweis hinzufügen. – Thomas

2

Als schnellen Hack können Sie die Eigenschaftendatei im static Initialisierer der Klasse lesen, dann müssen Sie die statische Natur der Klassenfelder nicht sofort ändern, aber ich schlage vor, dass Sie das sowieso im Laufe der Zeit tun.

Erstellen Sie eine neue Klasse, die alle Ihre alten konstanten Werte enthält. Von nun an injizieren Sie dieses Konfigurationsobjekt in Ihren neuen Code.

class NewConstants { 
    public final String name1; 
    public final String name2; 
    public final Integer value3; 
    ... and so on 

    public NewConstants (Properties props) 
    { 
     name1 = props.getProperty("name1"); 
     ... 
    } 
} 

Jetzt Refactoring alte Constants Klasse

class Constants (
    public static final String name1; 
    public static final String name2; 
    public static final Integer value3; 

    static { 
     Properties props = new Poperties(); 
     props.load(...); 

     NewConstants newConstants = new NewConstants(props); 

     name1 = newConstants.getName1(); 
     name2 = newConstants.getName2(); 

     ... 
    } 
} 
Verwandte Themen