Using Freemarker Template for generation.

REL-BRANCH-PropertyToJavaGenerator-0.0.1
Markus Kreth 7 years ago
parent 04c12896d1
commit 02f54b22c6
  1. 30
      pom.xml
  2. 33
      src/main/java/de/kreth/property2java/FreemarkerConfig.java
  3. 69
      src/main/java/de/kreth/property2java/Generator.java
  4. 44
      src/main/resources/template/enum_template.tpl
  5. 2
      src/test/java/de/kreth/property2java/ConfigurationTest.java
  6. 13
      src/test/java/de/kreth/property2java/GeneratorTests.java

@ -45,6 +45,22 @@
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang3</artifactId>
<version>3.8.1</version> <version>3.8.1</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
<!-- LOGGING --> <!-- LOGGING -->
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
@ -69,6 +85,7 @@
<version>${org.apache.logging.log4j}</version> <version>${org.apache.logging.log4j}</version>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
<!-- TESTING --> <!-- TESTING -->
<dependency> <dependency>
<groupId>org.hamcrest</groupId> <groupId>org.hamcrest</groupId>
@ -101,26 +118,17 @@
<artifactId>junit-platform-runner</artifactId> <artifactId>junit-platform-runner</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.6</version>
</dependency>
<dependency> <dependency>
<groupId>org.mockito</groupId> <groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId> <artifactId>mockito-core</artifactId>
<version>2.24.5</version> <version>2.24.5</version>
<scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.mockito</groupId> <groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId> <artifactId>mockito-junit-jupiter</artifactId>
<version>2.24.5</version> <version>2.24.5</version>
</dependency> <scope>test</scope>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
</dependency> </dependency>
</dependencies> </dependencies>

@ -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");
}
}

@ -3,21 +3,36 @@ package de.kreth.property2java;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.io.Writer; import java.io.Writer;
import java.util.ArrayList;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Properties; import java.util.Properties;
import de.kreth.property2java.cli.ArgumentConfiguration; import de.kreth.property2java.cli.ArgumentConfiguration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
public class Generator { public class Generator {
private Configuration config; private Configuration config;
private Template template;
public Generator(Configuration config) { public Generator(Configuration config) {
this.config = 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<String, Reader> entry : config.getInput().entrySet()) { for (Entry<String, Reader> entry : config.getInput().entrySet()) {
String fileName = entry.getKey(); 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<String, Object> root = new HashMap<>();
root.put("package", config.getPackage());
root.put("fileName", fileName);
root.put("classname", config.mapFilenameToClassName(fileName));
List<Entry<String, String>> entries = new ArrayList<>();
root.put("entries", entries);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Enumeration<String> propertyNames = (Enumeration<String>) properties.propertyNames(); Enumeration<String> propertyNames = (Enumeration<String>) 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()) { while (propertyNames.hasMoreElements()) {
String key = propertyNames.nextElement(); final String propertyKeyString = propertyNames.nextElement();
out.write( final String propertyValue = properties.getProperty(propertyKeyString);
"\tpublic static String " + key.toUpperCase().replaceAll("[\\.-]", "_") + " = \"" + key + "\";\n");
Entry<String, String> entry = new Entry<String, String>() {
@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"); template.process(root, out);
out.flush();
out.close();
} }
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 generator = new Generator(ArgumentConfiguration.parse(args));
generator.start(); generator.start();
} }

@ -0,0 +1,44 @@
<#if package??>package ${package};
</#if>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>,
</#sep>
</#list>;
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.
* <p>
* e.g. <code>${classname}.getString(resBundle::getString)</code>
* @param resourceFunction {@link Properties#getProperty(String)} or {@link ResourceBundle#getString(String)}
* @return
*/
public String getString(UnaryOperator<String> resourceFunction) {
return resourceFunction.apply(value);
}
}

@ -33,12 +33,14 @@ class ConfigurationTest {
@Test @Test
void testPathMapping() { void testPathMapping() {
when(config.mapFilenameToClassName(anyString())).thenCallRealMethod();
String className = config.mapFilenameToClassName("application.properties"); String className = config.mapFilenameToClassName("application.properties");
assertEquals("Application_Properties", className); assertEquals("Application_Properties", className);
} }
@Test @Test
void testPathMappingLocalized() { void testPathMappingLocalized() {
when(config.mapFilenameToClassName(anyString())).thenCallRealMethod();
String className = config.mapFilenameToClassName("application_de_DE.properties"); String className = config.mapFilenameToClassName("application_de_DE.properties");
assertEquals("Application_Properties", className); assertEquals("Application_Properties", className);
className = config.mapFilenameToClassName("application_en_US.properties"); className = config.mapFilenameToClassName("application_en_US.properties");

@ -27,6 +27,8 @@ import org.hamcrest.Matchers;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import freemarker.template.TemplateException;
class GeneratorTests { class GeneratorTests {
private String path = "application.properties"; private String path = "application.properties";
@ -48,9 +50,10 @@ class GeneratorTests {
} }
@Test @Test
void testClassDefinition() throws IOException { void testClassDefinition() throws IOException, TemplateException {
when(config.getPackage()).thenReturn("de.kreth.property2java"); when(config.getPackage()).thenReturn("de.kreth.property2java");
when(config.mapFilenameToClassName(anyString())).thenCallRealMethod();
StringWriter out = new StringWriter(); StringWriter out = new StringWriter();
when(config.outWriter(anyString())).thenReturn(out); when(config.outWriter(anyString())).thenReturn(out);
@ -68,7 +71,7 @@ class GeneratorTests {
if (line.trim().startsWith("package")) { if (line.trim().startsWith("package")) {
linePackage = line; linePackage = line;
} }
else if (line.trim().startsWith("public interface")) { else if (line.trim().startsWith("public enum")) {
lineClass = line; lineClass = line;
} }
if (line.contains("{")) { if (line.contains("{")) {
@ -89,12 +92,12 @@ class GeneratorTests {
Matchers.stringContainsInOrder(Arrays.asList("package", "de.kreth.property2java", ";"))); Matchers.stringContainsInOrder(Arrays.asList("package", "de.kreth.property2java", ";")));
assertThat(lineClass, assertThat(lineClass,
Matchers.stringContainsInOrder(Arrays.asList("public", "interface", "Application_Properties"))); Matchers.stringContainsInOrder(Arrays.asList("public", "enum", "Application_Properties")));
} }
@Test @Test
void testOneInputGeneratesOneOutput() throws IOException { void testOneInputGeneratesOneOutput() throws IOException, TemplateException {
Writer out = mock(Writer.class); Writer out = mock(Writer.class);
Writer nonOut = mock(Writer.class); Writer nonOut = mock(Writer.class);
@ -106,7 +109,7 @@ class GeneratorTests {
} }
@Test @Test
void testKeys() throws IOException { void testKeys() throws IOException, TemplateException {
StringWriter out = new StringWriter(); StringWriter out = new StringWriter();
when(config.outWriter(anyString())).thenReturn(out); when(config.outWriter(anyString())).thenReturn(out);

Loading…
Cancel
Save