2010-06-09 14 views
6

Il titolo originale era "Come generare enum dal file delle proprietà utilizzando formica?"Come generare enum dal file delle proprietà in Maven?

Desidero eseguire un'iterazione su tutte le proprietà e generare una classe di enumerazione con tutte le proprietà.

Sto pensando di scrivere attività personalizzate, ma penso che avrei bisogno di metterlo in un vaso extra: |

im utilizzando Maven e voglio farlo in fase di generazione-fonti.

+1

in realtà dovresti modificare il titolo della domanda, dal momento che il tuo ambiente è esperto e formica è solo una possibile opzione –

+0

So che questo è vecchio, ma perché non buttare semplicemente i file delle proprietà e usare semplicemente le enumerazioni? –

risposta

8

Anche se ho un po 'd'accordo con Peter Tilemans, sono stato tentato anche da questo problema e ho inciso su una soluzione che utilizza Groovy e il GMaven-Plugin. EDIT: Il bello di GMaven è che è possibile accedere direttamente al modello di oggetti Maven senza creare prima un plug-in e avere ancora il pieno potere di programmazione di Groovy.

Quello che faccio in casi come questo è creare una cartella sorgente chiamata src/main/groovy che non faccia parte del processo di compilazione reale (e quindi non contribuisca al jar/war etc). Lì posso mettere i file sorgente groovy, permettendo così a eclipse di usarli come cartelle di origine groovy per il completamento automatico ecc. Senza modificare la build.

Quindi, in questa cartella ho tre file: EnumGenerator.groovy, enumTemplate.txt e enum.properties (Ho fatto questo per semplicità, si avrà probabilmente ottenere il file delle proprietà da qualche altra parte)

Eccoli :

EnumGenerator.groovy

import java.util.Arrays; 
import java.util.HashMap; 
import java.util.TreeMap; 
import java.io.File; 
import java.util.Properties; 

class EnumGenerator{ 

    public EnumGenerator(
     File targetDir, 
     File propfile, 
     File templateFile, 
     String pkgName, 
     String clsName 
    ) { 
     def properties = new Properties(); 
     properties.load(propfile.newInputStream()); 
     def bodyText = generateBody(new TreeMap(properties)); 
     def enumCode = templateFile.getText(); 
     def templateMap = [ body:bodyText, packageName:pkgName, className: clsName ]; 
     templateMap.each{ key, value -> 
           enumCode = enumCode.replace("\${$key}", value) } 
     writeToFile(enumCode, targetDir, pkgName, clsName) 
    } 

    void writeToFile(code, dir, pkg, cls) { 
     def parentDir = new File(dir, pkg.replace('.','/')) 
     parentDir.mkdirs(); 
     def enumFile = new File (parentDir, cls + '.java') 
     enumFile.write(code) 
     System.out.println("Wrote file $enumFile successfully") 
    } 

    String generateBody(values) { 

     // create constructor call PROPERTY_KEY("value") 
     // from property.key=value 
     def body = ""; 
     values.eachWithIndex{ 
      key, value, index -> 
       body += 
       ( 
        (index > 0 ? ",\n\t" : "\t") 
        + toConstantCase(key) + '("' + value + '")' 
       ) 
     } 
     body += ";"; 
     return body; 

    } 

    String toConstantCase(value) { 
     // split camelCase and dot.notation to CAMEL_CASE and DOT_NOTATION 
     return Arrays.asList( 
      value.split("(?:(?=\\p{Upper})|\\.)") 
     ).join('_').toUpperCase(); 
    } 

} 

enumTemplate.txt

package ${packageName}; 

public enum ${className} { 

${body} 

    private ${className}(String value){ 
     this.value = value; 
    } 

    private String value; 

    public String getValue(){ 
     return this.value; 
    } 

} 

enum.proprietà

simple=value 
not.so.simple=secondvalue 
propertyWithCamelCase=thirdvalue 

Ecco la configurazione pom:

<plugin> 
    <groupId>org.codehaus.groovy.maven</groupId> 
    <artifactId>gmaven-plugin</artifactId> 
    <version>1.0</version> 
    <executions> 
     <execution> 
      <id>create-enum</id> 
      <phase>generate-sources</phase> 
      <goals> 
       <goal>execute</goal> 
      </goals> 
      <configuration> 
       <scriptpath> 
        <element>${pom.basedir}/src/main/groovy</element> 
       </scriptpath> 
       <source> 
        import java.io.File 
        import EnumGenerator 

        File groovyDir = new File(pom.basedir, 
         "src/main/groovy") 
        new EnumGenerator(
         new File(pom.build.directory, 
          "generated-sources/enums"), 
         new File(groovyDir, 
          "enum.properties"), 
         new File(groovyDir, 
          "enumTemplate.txt"), 
         "com.mycompany.enums", 
         "ServiceProperty" 
        ); 

       </source> 
      </configuration> 
     </execution> 
    </executions> 
</plugin> 

Ed ecco il risultato:

package com.mycompany.enums; 

public enum ServiceProperty { 

    NOT_SO_SIMPLE("secondvalue"), 
    PROPERTY_WITH_CAMEL_CASE("thirdvalue"), 
    SIMPLE("value"); 

    private ServiceProperty(String value){ 
     this.value = value; 
    } 

    private String value; 

    public String getValue(){ 
     return this.value; 
    } 

} 

utilizzando il modello, è possibile personalizzare l'enum in base alle proprie esigenze . e dal momento che gmaven incorpora groovy in maven, non devi installare nulla o modificare la configurazione della build.

L'unica cosa da ricordare è che è necessario utilizzare il plug-in buildhelper su add the generated source folder per la compilazione.

+0

bella idea, grazie. – IAdapter

+0

+1 per la creatività (di nuovo) –

+0

@pascal (ne vedremo di più, spero :-)) –

3

Consiglio vivamente di riconsiderare.

Si rischia di finire con una codifica rigida contro valori provenienti da file di configurazione e che potrebbero cambiare in qualsiasi momento.

Penso che una piccola classe di wrapper attorno a una HashMap o BidiMap che legge il file delle proprietà otterrà quasi gli stessi benefici e gli sviluppatori in seguito non tireranno fuori i capelli perché ottengono un errore di compilazione di gazillion a causa di un piccolo cambiamento nel un file di proprietà.

Ho fatto la mia parte di generazione del codice. Sono grandi per parser e gestori di protocolli, ma stanno facendo il ticchettio di timebomb per ogni altro caso di utilizzo per il quale ho avuto la sfortuna di usarli.

+0

l'ho usato per i selettori jQuery per i test. Perché pensi che sia una cattiva idea? se qualcuno rimuove il selettore di quanto dovrebbe anche rimuovere/aggiornare il test che lo sta usando. Ho appena scambiato errori di runtime con errori di compilazione. inoltre in questo modo posso facilmente sfuggire: nei selettori (funziona solo come \\ :). – IAdapter

+0

Penso che tu abbia avuto un problema con questo perché non hai mantenuto le classi generate sotto il controllo del codice sorgente, quindi quando qualcosa si è rotto è stato davvero difficile risolverlo. – IAdapter

+0

Fintanto che il codice generato è autonomo non è un problema, i problemi iniziano se si inizia la codifica in classi che non sono generate contro funzioni con firme generate. E no, le classi generate non erano sotto il controllo del codice sorgente, solo i file da cui sono state generate, e la generazione è stata fatta dal sistema di compilazione. Potrebbe funzionare molto bene se il codice è veramente ben testato e tutti i membri del team di sviluppo e manutenzione lo sanno. In realtà sembra un buon caso d'uso: generare un codice di "stupido" reptitivo che ha un caso d'uso limitato. –

Problemi correlati