Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to generate enum from properties file in Maven?

The original title was "How to generate enum from properties file using ant?"

I want to iterate over all properties and generate enum class that have every property.

Im thinking about writing custom task, but I think i would need to put it in extra jar :|

im using maven and i want to do it in generate-sources phase.

like image 334
IAdapter Avatar asked Jun 09 '10 07:06

IAdapter


2 Answers

Although I somewhat agree with Peter Tilemans, I was also tempted by this problem and I hacked up a solution using groovy and the GMaven-Plugin. EDIT: The great thing about GMaven is that you can access the maven object model directly without creating a plugin first and still have groovy's full programming power.

What I do in cases like this is to create a source folder called src/main/groovy that is not part of the actual build process (and hence will not contribute to the jar / war etc). There I can put groovy source files, thus allowing eclipse to use them as groovy source folders for autocompletion etc without changing the build.

So in this folder I have three files: EnumGenerator.groovy, enumTemplate.txt and enum.properties (I did this for simplicity's sake, you will probably get the properties file from somewhere else)

Here they are:

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.properties

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

Here's the pom configuration:

<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>

And here's the result:

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

}

using the template, you can customize the enum to suit your needs. and since gmaven embeds groovy in maven, you don't have to install anything or change your build configuration.

The only thing to remember is that you'll need to use the buildhelper plugin to add the generated source folder to the build.

like image 169
Sean Patrick Floyd Avatar answered Sep 18 '22 22:09

Sean Patrick Floyd


I would strongly recommend you to reconsider.

You risk ending up hard coding against values which are coming from configuration files and might change any moment.

I think a little wrapper class around a HashMap or BidiMap reading the properties file will achieve the almost the same benefits and the developers later on will not pull out their hairs why they get a gazillion compilation errors because of a small change in a property file.

I have done my share of code generation. They're great for parsers and protocol handlers but are ticking timebombs for about every other use case I had the misfortune to use them for.

like image 24
Peter Tillemans Avatar answered Sep 17 '22 22:09

Peter Tillemans