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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With