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>
<version>3.8.1</version>
</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 -->
<dependency>
<groupId>org.slf4j</groupId>
@ -69,6 +85,7 @@
<version>${org.apache.logging.log4j}</version>
<scope>runtime</scope>
</dependency>
<!-- TESTING -->
<dependency>
<groupId>org.hamcrest</groupId>
@ -101,26 +118,17 @@
<artifactId>junit-platform-runner</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.24.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>2.24.5</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.4</version>
<scope>test</scope>
</dependency>
</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.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<String, Reader> 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<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")
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()) {
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<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");
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();
}

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

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

Loading…
Cancel
Save