/ / Come passare da un file di configurazione statica codificato ad un file .properties? - java, refactoring

Come passare da un file di configurazione statico hardcoded a un file .properties? - java, refactoring

Ho del codice che usa una classe che contiene un sacco di costanti hardcoded. Ecco come appare:

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

Queste costanti sono usate ovunque nel codice come Constants.name1.

Quello che devo fare ora è rendere possibile specificare i valori per queste costanti in un file di configurazione, probabilmente a *.properties file.

La mia domanda è: qual è il modo migliore per farlo, dovendo riscrivere il minor codice possibile?

Ho pensato di utilizzare una singola classe di configurazioneche legge le proprietà dal file quando viene istanziato, ma poi dovrò sostituire tutte le chiamate statiche di valori alle chiamate a un'istanza di quella classe e dovrò modificare i metodi esistenti per passare questa istanza di configurazione in esse. Esiste un modo migliore?

risposte:

4 per risposta № 1

Ecco una parte di un codice che ho usato in passato, che può essere adattato al tuo esempio:

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);
}
}

3 per risposta № 2

Carica le proprietà dal file usando Properties.load(...) e assegnare le costanti da quelle proprietà.

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" ) );
}

Si noti che questa è solo una soluzione rapida e sporca e fa molte ipotesi. Sarebbe meglio gestire le singole eccezioni e dovresti anche gestire NumberFormatException che potrebbe essere lanciato da Integer.valueOf(...) se la configurazione è vuota o non è un numero.

Un'altra nota: potresti anche provare a utilizzare una configurazione non statica o almeno non definitiva per poter modificare le proprietà in fase di esecuzione.

modificare: Ho aggiunto autoclose per lo stream, ma nota che prima di Java 7 avresti dovuto gestirlo da solo.


2 per risposta № 3

Come hack rapido, puoi leggere il file delle proprietà in static inizializzatore della classe, quindi non è necessario modificare immediatamente la natura statica dei campi della classe, ma ti suggerisco di farlo comunque nel tempo.

Crea una nuova classe che contiene tutti i tuoi vecchi valori costanti. D'ora in poi, iniettare questo oggetto di configurazione nel nuovo codice.

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" );
...
}
}

Ora rifatti il ​​tuo vecchio Constants classe

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( );

...
}
}