diff --git a/pom.xml b/pom.xml index 07481a8..6299416 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,22 @@ commons-lang3 3.8.1 + + org.apache.commons + commons-text + 1.6 + + + commons-cli + commons-cli + 1.4 + + + org.freemarker + freemarker + 2.3.28 + + org.slf4j @@ -69,6 +85,7 @@ ${org.apache.logging.log4j} runtime + org.hamcrest @@ -101,26 +118,17 @@ junit-platform-runner test - - - org.apache.commons - commons-text - 1.6 - org.mockito mockito-core 2.24.5 + test org.mockito mockito-junit-jupiter 2.24.5 - - - commons-cli - commons-cli - 1.4 + test diff --git a/src/main/java/de/kreth/property2java/FreemarkerConfig.java b/src/main/java/de/kreth/property2java/FreemarkerConfig.java new file mode 100644 index 0000000..4b85236 --- /dev/null +++ b/src/main/java/de/kreth/property2java/FreemarkerConfig.java @@ -0,0 +1,33 @@ +package de.kreth.property2java; + +import java.io.File; +import java.io.IOException; +import java.net.URL; + +import freemarker.template.Configuration; +import freemarker.template.Template; + +public enum FreemarkerConfig { + + INSTANCE; + + private final Configuration cfg; + + public Template getTemplate() throws IOException { + return cfg.getTemplate("enum_template.tpl"); + } + + private FreemarkerConfig() { + cfg = new Configuration(Configuration.VERSION_2_3_28); + URL url = getClass().getResource("/template/enum_template.tpl"); + try { + cfg.setDirectoryForTemplateLoading(new File(url.getFile()).getParentFile()); + } + catch (IOException e) { + throw new IllegalStateException("Unable to configure freemarker", e); + } + + cfg.setDefaultEncoding("UTF-8"); + } + +} diff --git a/src/main/java/de/kreth/property2java/Generator.java b/src/main/java/de/kreth/property2java/Generator.java index dd605e2..ccaee0a 100644 --- a/src/main/java/de/kreth/property2java/Generator.java +++ b/src/main/java/de/kreth/property2java/Generator.java @@ -3,21 +3,36 @@ package de.kreth.property2java; import java.io.IOException; import java.io.Reader; import java.io.Writer; +import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import de.kreth.property2java.cli.ArgumentConfiguration; +import freemarker.template.Template; +import freemarker.template.TemplateException; public class Generator { private Configuration config; + private Template template; + public Generator(Configuration config) { this.config = config; + try { + template = FreemarkerConfig.INSTANCE.getTemplate(); + } + catch (IOException e) { + + throw new IllegalStateException("Unable to load freemarker template", e); + } } - public void start() throws IOException { + public void start() throws IOException, TemplateException { for (Entry entry : config.getInput().entrySet()) { String fileName = entry.getKey(); @@ -28,30 +43,48 @@ public class Generator { } } - void generate(Properties properties, Writer out, String fileName, Configuration config) throws IOException { + void generate(Properties properties, Writer out, String fileName, Configuration config) + throws IOException, TemplateException { + + Map root = new HashMap<>(); + root.put("package", config.getPackage()); + root.put("fileName", fileName); + root.put("classname", config.mapFilenameToClassName(fileName)); + + List> entries = new ArrayList<>(); + + root.put("entries", entries); @SuppressWarnings("unchecked") Enumeration propertyNames = (Enumeration) properties.propertyNames(); - String packageName = config.getPackage(); - if (packageName != null && !packageName.isBlank()) { - out.write("package "); - out.write(packageName); - out.write(";\n\n"); - } - out.write("public interface "); - out.write(config.mapFilenameToClassName(fileName)); - out.write(" {\n"); + while (propertyNames.hasMoreElements()) { - String key = propertyNames.nextElement(); - out.write( - "\tpublic static String " + key.toUpperCase().replaceAll("[\\.-]", "_") + " = \"" + key + "\";\n"); + final String propertyKeyString = propertyNames.nextElement(); + final String propertyValue = properties.getProperty(propertyKeyString); + + Entry entry = new Entry() { + + @Override + public String getKey() { + return propertyKeyString.toUpperCase().replaceAll("[\\.-]", "_"); + } + + @Override + public String getValue() { + return propertyValue; + } + + @Override + public String setValue(String value) { + throw new UnsupportedOperationException("Set Value not supported!"); + } + }; + entries.add(entry); } - out.write(" }\n"); - out.flush(); - out.close(); + template.process(root, out); } - public static void main(String[] args) throws IOException { + public static void main(String[] args) throws IOException, TemplateException { Generator generator = new Generator(ArgumentConfiguration.parse(args)); generator.start(); } diff --git a/src/main/resources/template/enum_template.tpl b/src/main/resources/template/enum_template.tpl new file mode 100644 index 0000000..19b5379 --- /dev/null +++ b/src/main/resources/template/enum_template.tpl @@ -0,0 +1,44 @@ +<#if package??>package ${package}; + +import java.util.Properties; +import java.util.ResourceBundle; +import java.util.function.UnaryOperator; + +/** + * Property key from ${fileName} + */ +public enum ${classname} { + +<#list entries as entry> + /** + * "${entry.value}" + */ + ${entry.key} ("${entry.value}")<#sep>, + +; + + private final String value; + + private ${classname} (String value) { + this.value = value; + } + + /** + * Represented Key in property File. + * @return key + */ + public String getValue() { + return value; + } + + /** + * Resolves the value for this key from the parameter function. + *

+ * e.g. ${classname}.getString(resBundle::getString) + * @param resourceFunction {@link Properties#getProperty(String)} or {@link ResourceBundle#getString(String)} + * @return + */ + public String getString(UnaryOperator resourceFunction) { + return resourceFunction.apply(value); + } +} diff --git a/src/test/java/de/kreth/property2java/ConfigurationTest.java b/src/test/java/de/kreth/property2java/ConfigurationTest.java index 5df1040..996f21b 100644 --- a/src/test/java/de/kreth/property2java/ConfigurationTest.java +++ b/src/test/java/de/kreth/property2java/ConfigurationTest.java @@ -33,12 +33,14 @@ class ConfigurationTest { @Test void testPathMapping() { + when(config.mapFilenameToClassName(anyString())).thenCallRealMethod(); String className = config.mapFilenameToClassName("application.properties"); assertEquals("Application_Properties", className); } @Test void testPathMappingLocalized() { + when(config.mapFilenameToClassName(anyString())).thenCallRealMethod(); String className = config.mapFilenameToClassName("application_de_DE.properties"); assertEquals("Application_Properties", className); className = config.mapFilenameToClassName("application_en_US.properties"); diff --git a/src/test/java/de/kreth/property2java/GeneratorTests.java b/src/test/java/de/kreth/property2java/GeneratorTests.java index 1429197..cd339b9 100644 --- a/src/test/java/de/kreth/property2java/GeneratorTests.java +++ b/src/test/java/de/kreth/property2java/GeneratorTests.java @@ -27,6 +27,8 @@ import org.hamcrest.Matchers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import freemarker.template.TemplateException; + class GeneratorTests { private String path = "application.properties"; @@ -48,9 +50,10 @@ class GeneratorTests { } @Test - void testClassDefinition() throws IOException { + void testClassDefinition() throws IOException, TemplateException { when(config.getPackage()).thenReturn("de.kreth.property2java"); + when(config.mapFilenameToClassName(anyString())).thenCallRealMethod(); StringWriter out = new StringWriter(); when(config.outWriter(anyString())).thenReturn(out); @@ -68,7 +71,7 @@ class GeneratorTests { if (line.trim().startsWith("package")) { linePackage = line; } - else if (line.trim().startsWith("public interface")) { + else if (line.trim().startsWith("public enum")) { lineClass = line; } if (line.contains("{")) { @@ -89,12 +92,12 @@ class GeneratorTests { Matchers.stringContainsInOrder(Arrays.asList("package", "de.kreth.property2java", ";"))); assertThat(lineClass, - Matchers.stringContainsInOrder(Arrays.asList("public", "interface", "Application_Properties"))); + Matchers.stringContainsInOrder(Arrays.asList("public", "enum", "Application_Properties"))); } @Test - void testOneInputGeneratesOneOutput() throws IOException { + void testOneInputGeneratesOneOutput() throws IOException, TemplateException { Writer out = mock(Writer.class); Writer nonOut = mock(Writer.class); @@ -106,7 +109,7 @@ class GeneratorTests { } @Test - void testKeys() throws IOException { + void testKeys() throws IOException, TemplateException { StringWriter out = new StringWriter(); when(config.outWriter(anyString())).thenReturn(out);