2015-03-22 23 views
6

Ho un sacco di costanti nel mio codice per varie proprietà regolabili del mio sistema. Li sto spostando tutti in un file centrale .properties. La mia soluzione attuale è quella di avere un unico Properties.java che carica staticamente il file .properties ed espone vari metodi getter come questo:Iniezione di costanti tramite annotazione personalizzata

public class Properties { 
    private static final String FILE_NAME = "myfile.properties"; 
    private static final java.util.Properties props; 

    static { 
     InputStream in = Properties.class.getClassLoader().getResourceAsStream(
       FILE_NAME); 
     props = new java.util.Properties(); 
     try { 
      props.load(in); 
     } catch (IOException e) { 
      throw new RuntimeException(e); 
     } 
    } 

    public static String getString(Class<?> cls, String key) { 
     return props.getProperty(cls.getName() + '.' + key); 
    } 

    public static int getInteger(Class<?> cls, String key) { 
     return Integer.parseInt(getString(cls, key)); 
    } 

    public static double getDouble(Class<?> cls, String key) { 
     return Double.parseDouble(getString(cls, key)); 
    } 
} 

L'unico problema di questo è che per ogni costante che ricevo da questo file, ho un po ' boilerplate:

private final static int MY_CONSTANT = Properties.getInteger(
    ThisClass.class, "MY_CONSTANT"); 

non credo che voglio usare primavera o simili che sembra ancora più boilerplae. Speravo di usare un'annotazione personalizzata per risolvere il problema. Ho trovato this tutorial, ma non riesco davvero a capire come ottenere la funzionalità che desidero dall'elaborazione dell'annotazione. I documenti Java erano ancora meno utili. Questa dovrebbe essere una cosa che dovrei essere in grado di fare in fase di compilazione, però. Conosco i nomi della classe e del campo.

Quello che sto pensando è qualcosa di simile:

@MyAnnotation 
private static final int MY_CONSTANT; 

Qualcuno sa come vorrei andare a fare questo o almeno le migliori pratiche per quello che voglio fare?

+0

Perché pensi che i suoi carichi di codice piastra caldaia? non aggiungerebbe l'annotazione? – SMA

+0

Sono davvero costanti? O più come oggetti di configurazione? Se sono configurati, è davvero necessario scriverli come costanti? Perché il modificatore di 'final' perderebbe il suo significato (non sono nemmeno sicuro che la riflessione possa assegnare un valore a un campo' finale'). Se sono solo di configurazione, anche, perché non dovresti usare un framework di configurazione per facilitare il tuo compito (come [commons-configuration] (https://commons.apache.org/proper/commons-configuration/) o [typesafe's config] (https://github.com/typesafehub/config))? Se sono costanti, perché la necessità di essere in grado di "modificarle" ad ogni esecuzione? –

+0

Inoltre, non si chiude 'InputStream' nel blocco' try-catch-finally'. Dovresti provare a farlo. –

risposta

2

Prima di tutto, non dovresti farlo. È pratico, ma troppo hacky e se vuoi scrivere un test utilizzando impostazioni diverse, ti imbatterai in problemi. Inoltre, nessuno capirà come funziona.

Un processore di annotazioni probabilmente non può fare nulla per voi. Un processore di hacking stile Lombok può. Si vuole fare in

@MyAnnotation 
private static final int MY_CONSTANT; 

lavoro come

private final static int MY_CONSTANT = 
    Properties.getInteger(ThisClass.class, "MY_CONSTANT"); 

L'espressione originale non compila (dovuta alla variabile non inizializzata finale), ma si analizza bene e Lombok può fare il suo lavoro. C'è già qualcosa là correlati:

Quindi, in realtà, si potrebbe scrivere semplicemente

@MyAnnotation 
int MY_CONSTANT; 

e lasciate che la vostra annotazione cambia anche i modificatori. Guarderei i gestori eclipse e per @UtilityClass, suppongo che tutto ciò che serve sia generare l'inizializzatore (che è piuttosto un lavoro perché è tutto dannatamente complicato).

Non credo Lombok si intende recepire tale in qualunque momento presto, dal momento che

  • tutte le static roba non è verificabile e per lo più cattivo stile
  • e non tutti vogliono questo nel loro codice
  • non è molto boilerplate
  • anche riferisce magicamente alla classe Properties, ma questo potrebbe essere risolto tramite configuration

ma suppongo che un contributo possa essere accettato.

1

In realtà non è chiaro perché e cosa si desidera archiviare.

Come correttamente undestanding, si desidera utilizzare un tipo speciale di annotazioni per assegnare automaticamente i valori per le costanti static final da alcuni file properties. Unfortunatelly è impossibile senza hack speciali. E le annotazioni non hanno nulla a che fare con questo.

Il motivo è che i campi final devono essere inizializzati ed è la richiesta del compilatore. Non ci sono annotazioni speciali in java che forniranno lo zucchero sintattico che desideri.

Ma se ti ostini a questo ci sono due modi:

  1. modo Extrim. Inizia tutte le proprietà campo con valore predefinito. Quindi, utilizzando static, inizializzare questo valore utilizzando this hack utilizzando il meccanismo reflection e il codice tramite i valori di lettura da properties.

  2. Meno modo di trasporto: richiesta di rifiuto dei modificatori final per i campi proprietà e utilizzando solo reflection riempire questi valori dei campi.

E inoltre, per questi modi, sì è possibile utilizzare le annotazioni. Ma dovrai risolvere i seguenti problemi tecnici:

1) Trova tutti i campi di tutte le classi in classpath, che sono annotati con lo speciale annotation. Guarda: Get all of the Classes in the Classpath e Get list of fields with annotation, by using reflection

2) forzare il vostro classe Properties essere inizializzati in tutte le possibili inserire i punti della vostra applicazione. Nella sezione statica di questa classe verrà caricato il file delle proprietà e quindi utilizzando il metodo (1) con reflection e classloader, assegnare i valori a tutte le costanti.

Problemi correlati