Compare commits

..

8 Commits

  1. 37
      .classpath
  2. 24
      .github/workflows/maven.yml
  3. 6
      .gitignore
  4. 23
      .project
  5. 1
      META-INF/services/javax.annotation.processing.Processor
  6. 82
      pom.xml
  7. 83
      src/main/java/de/kreth/property2java/Configuration.java
  8. 35
      src/main/java/de/kreth/property2java/Entry.java
  9. 173
      src/main/java/de/kreth/property2java/Generator.java
  10. 8
      src/main/java/de/kreth/property2java/GeneratorException.java
  11. 147
      src/main/java/de/kreth/property2java/cli/ArgumentConfiguration.java
  12. 2
      src/main/java/de/kreth/property2java/cli/CliConfig.java
  13. 34
      src/main/java/de/kreth/property2java/config/FreemarkerConfig.java
  14. 24
      src/main/java/de/kreth/property2java/config/FreemarkerConfigImpl.java
  15. 27
      src/main/java/de/kreth/property2java/processor/Format.java
  16. 42
      src/main/java/de/kreth/property2java/processor/GenerateProperty2Java.java
  17. 46
      src/main/java/de/kreth/property2java/processor/GenerateResourceBundleProperty2Java.java
  18. 21
      src/main/java/de/kreth/property2java/processor/GenerateResourceBundleProperty2Javas.java
  19. 116
      src/main/java/de/kreth/property2java/processor/ProcessorConfiguration.java
  20. 91
      src/main/java/de/kreth/property2java/processor/Property2JavaGenerator.java
  21. 152
      src/main/java/de/kreth/property2java/replace/Replacement.java
  22. 14
      src/main/java/de/kreth/property2java/replace/Replacements.java
  23. 1
      src/main/resources/META-INF/services/javax.annotation.processing.Processor
  24. 2
      src/main/resources/template/enum_template.tpl
  25. 62
      src/main/resources/template/enum_template_with_initializer.tpl
  26. 48
      src/main/resources/template/enum_template_with_inner_properties.tpl
  27. 50
      src/main/resources/template/enum_template_with_inner_propertyresourcebundle.tpl
  28. 308
      src/test/java/de/kreth/property2java/GeneratorTests.java
  29. 55
      src/test/java/de/kreth/property2java/cli/ArgumentConfigurationTest.java
  30. 46
      src/test/java/de/kreth/property2java/processor/Property2JavaGeneratorTest.java
  31. 163
      src/test/java/de/kreth/property2java/replace/ReplacementTest.java

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="test" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="test" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry exported="true" kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

@ -1,24 +0,0 @@
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
name: PropertyToJavaGenerator Library and console programm
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 11
- name: Build with Maven
run: mvn -B package --file pom.xml

6
.gitignore vendored

@ -1,5 +1,3 @@
.classpath
.project
.factorypath
.settings
\.settings/
target

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>PropertyToJavaGenerator</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

@ -1 +0,0 @@
de.kreth.property2java.processor.Property2JavaGenerator

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.kreth.property2java</groupId>
<artifactId>PropertyToJavaGenerator</artifactId>
<version>2.0.3-SNAPSHOT</version>
<modelVersion>4.0.0</modelVersion>
<groupId>de.kreth.property2java</groupId>
<artifactId>PropertyToJavaGenerator</artifactId>
<version>0.0.3</version>
<properties>
@ -12,12 +12,20 @@
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>11</java.version>
<org.junit.jupiter>5.3.0-M1</org.junit.jupiter>
<org.slf4j>1.7.36</org.slf4j>
<org.apache.logging.log4j>2.17.2</org.apache.logging.log4j>
<org.slf4j>1.7.21</org.slf4j>
<org.apache.logging.log4j>2.11.0</org.apache.logging.log4j>
<timestamp>${maven.build.timestamp}</timestamp>
<maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
<project.scm.id>github</project.scm.id>
<sonar.login>3f3a1fa86ea83226b564895f3a8503f67e855440</sonar.login>
<sonar.jacoco.reportPaths>target/surefire-reports</sonar.jacoco.reportPaths>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
<sonar.jacoco.reportPath>${project.basedir}/target/jacoco.exec</sonar.jacoco.reportPath>
<sonar.exclusions>**/src/main/webapp/VAADIN/**/*</sonar.exclusions>
</properties>
<dependencies>
@ -42,7 +50,7 @@
<version>2.3.28</version>
</dependency>
<!-- LOGGING -->
<!-- LOGGING -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
@ -71,32 +79,30 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.3.2</version>
<version>5.3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.3.2</version>
<version>5.3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.3.2</version>
<version>5.3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.5.0-M1</version>
<scope>test</scope>
<version>1.5.0-M1</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<version>1.5.0-M1</version>
<scope>test</scope>
<version>1.5.0-M1</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
@ -114,22 +120,9 @@
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>2.1-rc4</version>
<scope>test</scope>
</dependency>
</dependencies>
<distributionManagement>
<snapshotRepository>
<id>kreth.snapshots</id>
<url>https://nexus.kreth-development.de/repository/maven-snapshots/</url>
</snapshotRepository>
<repository>
<id>kreth.releases</id>
<url>https://nexus.kreth-development.de/repository/maven-releases/</url>
</repository>
</distributionManagement>
<build>
<plugins>
<plugin>
@ -138,14 +131,35 @@
<version>3.8.0</version>
<configuration>
<release>${java.version}</release>
<compilerArgs>-proc:none</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.2</version>
<executions>
<execution>
<id>default-jacoco-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>default-jacoco-report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<scm>
<developerConnection>scm:git:https://gitea.kreth-development.de/markus/PropertyToJavaGenerator_migration.git</developerConnection>
<connection>scm:git:https://gitea.kreth-development.de/markus/PropertyToJavaGenerator_migration.git</connection>
<tag>HEAD</tag>
</scm>
</project>

@ -1,9 +1,11 @@
package de.kreth.property2java;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.file.Path;
@ -11,55 +13,58 @@ import java.util.Map;
import org.apache.commons.text.WordUtils;
import de.kreth.property2java.config.FreemarkerConfigImpl;
import de.kreth.property2java.config.Regex;
import de.kreth.property2java.processor.Format;
import freemarker.template.Template;
public interface Configuration {
/**
* Package for generated Java Classes eg. "de.kreth.property2java". If null - no
* package line is generated.
*
* @return
*/
String getPackage();
/**
* Package for generated Java Classes eg. "de.kreth.property2java". If null - no package line is generated.
* @return
*/
String getPackage();
default Format getFormat() {
return Format.WithUnaryOperatorParameter;
}
/**
* Filename to InputReader Entries
* @return
*/
Map<String, Reader> getInput();
/**
* Filename to InputReader Entries
*
* @return
*/
Map<String, Reader> getInput();
/**
* Path of java source folder.
* @return
*/
Path getRootPath();
/**
* Path of java source folder.
*
* @return
*/
Path getRootPath();
default Reader previousGenerated(String fileName) throws IOException {
File file = new File(getRootPath().toFile(), mapFilenameToClassName(fileName) + ".java");
if (file.exists()) {
return new FileReader(file);
}
else {
return new StringReader("");
}
}
default Writer outWriter(String fileName) throws IOException {
return new FileWriter(new File(getRootPath().toFile(), mapFilenameToClassName(fileName) + ".java"),
outputCharset());
}
default Writer outWriter(String fileName) throws IOException {
return new FileWriter(new File(getRootPath().toFile(), mapFilenameToClassName(fileName) + ".java"),
outputCharset());
}
default Charset outputCharset() {
return Charset.defaultCharset();
}
default Charset outputCharset() {
return Charset.defaultCharset();
}
default String mapFilenameToClassName(String fileName) {
default String mapFilenameToClassName(String fileName) {
String path = Regex.PATTERN.matcher(fileName)
.replaceAll(".")
.replaceAll("\\.", "_")
.replaceAll(" ", "_")
.replaceAll("/", "_");
path = WordUtils.capitalize(path, '_');
return path;
}
String path = Regex.PATTERN.matcher(fileName).replaceAll(".").replaceAll("\\.", "_").replaceAll(" ", "_");
path = WordUtils.capitalize(path, '_');
return path;
}
default Template getTemplate() throws IOException {
return FreemarkerConfigImpl.INSTANCE.getTemplate();
}
}

@ -0,0 +1,35 @@
package de.kreth.property2java;
public class Entry {
public final String constant;
public final String key;
public final String value;
public Entry(String constant, String key, String value) {
super();
this.constant = constant;
this.key = key;
this.value = value;
}
public String getConstant() {
return constant;
}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
@Override
public String toString() {
return "Entry [constant=" + constant + ", key=" + key + ", value=" + value + "]";
}
}

@ -1,13 +1,10 @@
package de.kreth.property2java;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.net.URL;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
@ -16,149 +13,75 @@ import java.util.Map;
import java.util.Properties;
import de.kreth.property2java.cli.ArgumentConfiguration;
import de.kreth.property2java.config.FreemarkerConfig;
import freemarker.template.Template;
import freemarker.template.TemplateException;
public class Generator {
private static final DateFormat dateTimeInstance = DateFormat.getDateTimeInstance();
private static final DateFormat dateTimeInstance = DateFormat.getDateTimeInstance();
private final Configuration config;
private final Configuration config;
private final Template template;
private final Template template;
public Generator(Configuration config) {
this.config = config;
try {
template = FreemarkerConfig.INSTANCE.getTemplate(config.getFormat());
} catch (IOException e) {
throw new IllegalStateException("Unable to load freemarker template", e);
}
}
public void start() throws IOException, GeneratorException {
for (Map.Entry<String, Reader> entry : config.getInput().entrySet()) {
String fileName = entry.getKey();
try (Writer out = config.outWriter(fileName)) {
Properties properties = new Properties();
properties.load(entry.getValue());
public Generator(Configuration config) {
this.config = config;
try {
generate(properties, out, fileName, config);
} catch (TemplateException e) {
throw new GeneratorException("Error configuring Engine", e);
template = config.getTemplate();
}
catch (IOException e) {
throw new IllegalStateException("Unable to load freemarker template", e);
}
}
}
}
void generate(Properties properties, Writer out, String fileName, Configuration config)
throws IOException, TemplateException {
Map<String, Object> root = new HashMap<>();
root.put("generator_name", getClass().getName());
root.put("generation_date", dateTimeInstance.format(new Date()));
root.put("package", config.getPackage());
root.put("fileName", fileName);
root.put("bundle_base_name", fileName.substring(0, min(fileName.length(), fileName.lastIndexOf('.'))));
root.put("classname", config.mapFilenameToClassName(fileName));
List<Entry> entries = new ArrayList<>();
root.put("entries", entries);
public void start() throws IOException, GeneratorException {
for (Map.Entry<String, Reader> entry : config.getInput().entrySet()) {
String fileName = entry.getKey();
try (Writer out = config.outWriter(fileName)) {
Properties properties = new Properties();
properties.load(entry.getValue());
try {
generate(properties, out, fileName, config);
}
catch (TemplateException e) {
throw new GeneratorException("Error configuring Engine", e);
}
}
}
}
@SuppressWarnings("unchecked")
List<String> propertyNames = Collections.list((Enumeration<String>) properties.propertyNames());
Collections.sort(propertyNames);
void generate(Properties properties, Writer out, String fileName, Configuration config)
throws IOException, TemplateException {
for (String propertyKeyString : propertyNames) {
final String propertyValue = properties.getProperty(propertyKeyString);
Map<String, Object> root = new HashMap<>();
root.put("generator_name", getClass().getName());
root.put("generation_date", dateTimeInstance.format(new Date()));
root.put("package", config.getPackage());
root.put("fileName", fileName);
root.put("classname", config.mapFilenameToClassName(fileName));
entries.add(new Entry(propertyKeyString.toUpperCase().replaceAll("[\\.-]", "_"), propertyKeyString,
propertyValue));
}
template.process(root, out);
}
List<Entry> entries = new ArrayList<>();
int min(int a, int b) {
int result = Math.min(a, b);
if (result < 0) {
result = Math.max(a, b);
}
return result;
}
public static void main(String[] args) throws IOException, GeneratorException {
Generator generator = new Generator(ArgumentConfiguration.parse(args));
generator.start();
}
public static void generateFor(Class<?> locationClass, List<URL> rescources, String relativeTargetDir)
throws IOException, GeneratorException {
ArgumentConfiguration.Builder config = new ArgumentConfiguration.Builder();
rescources
.stream()
.map(URL::getFile)
.map(File::new)
.map(File::getAbsolutePath)
.forEach(config::addPropFile);
config.setPackageName(locationClass.getPackageName())
.setTarget(relativeTargetDir);
Generator g = new Generator(config.build());
g.start();
}
/**
* Represents an Property Entry for the generated java class.
*
* @author markus
*
*/
public class Entry {
public final String constant;
public final String key;
public final String value;
/**
* Creates Property Entry data for the generated java class.
*
* @param constant name for the created constant.
* @param key property key
* @param value property value
*/
public Entry(String constant, String key, String value) {
super();
this.constant = constant;
this.key = key;
this.value = value;
}
root.put("entries", entries);
public String getConstant() {
return constant;
}
@SuppressWarnings("unchecked")
Enumeration<String> propertyNames = (Enumeration<String>) properties.propertyNames();
public String getKey() {
return key;
}
while (propertyNames.hasMoreElements()) {
final String propertyKeyString = propertyNames.nextElement();
final String propertyValue = properties.getProperty(propertyKeyString);
public String getValue() {
return value;
entries.add(new Entry(propertyKeyString.toUpperCase().replaceAll("[\\.-]", "_"), propertyKeyString,
propertyValue));
}
template.process(root, out);
}
@Override
public String toString() {
return "Entry [constant=" + constant + ", key=" + key + ", value=" + value + "]";
public static void main(String[] args) throws IOException, GeneratorException {
Generator generator = new Generator(ArgumentConfiguration.parse(args));
generator.start();
}
}
}

@ -8,12 +8,4 @@ public class GeneratorException extends Exception {
super(message, cause);
}
public GeneratorException(String message) {
super(message);
}
public GeneratorException(Throwable cause) {
super(cause);
}
}

@ -16,81 +16,104 @@ import de.kreth.property2java.Configuration;
public class ArgumentConfiguration implements Configuration {
private final String packageName;
private final String packageName;
private final Map<String, Reader> files;
private final Map<String, Reader> files;
private final Path rootPath;
private final Path rootPath;
private ArgumentConfiguration(Builder builder) throws IOException {
this.packageName = builder.packageName;
rootPath = new File(builder.target).toPath();
files = new HashMap<>();
for (String filePath : builder.propFiles) {
File f = new File(filePath);
files.put(f.getName(), new FileReader(f));
}
private ArgumentConfiguration(Builder builder) throws IOException {
this.packageName = builder.packageName;
rootPath = new File(builder.target).toPath();
files = new HashMap<>();
for (String filePath : builder.propFiles) {
File f = new File(filePath);
files.put(f.getName(), new FileReader(f));
}
}
@Override
public String getPackage() {
return packageName;
}
@Override
public Map<String, Reader> getInput() {
return files;
}
@Override
public Path getRootPath() {
return rootPath;
}
@Override
public Writer outWriter(String fileName) throws IOException {
File dir;
if (packageName != null && packageName.isBlank() == false) {
dir = new File(rootPath.toFile(), packageName.replace('.', File.separatorChar));
} else {
dir = rootPath.toFile();
}
return new FileWriter(new File(dir, mapFilenameToClassName(fileName) + ".java"), false);
}
public static Configuration parse(String[] args) throws IOException {
CliConfig cliConfig = new CliConfig();
Builder builder = new Builder();
cliConfig.fill(builder, args);
return builder.build();
}
public static class Builder {
String target;
List<String> propFiles = new ArrayList<>();
@Override
public String getPackage() {
return packageName;
}
String packageName;
@Override
public Map<String, Reader> getInput() {
return files;
}
public Builder setTarget(String target) {
this.target = target;
return this;
@Override
public Path getRootPath() {
return rootPath;
}
public Builder addPropFile(String propFile) {
this.propFiles.add(propFile);
return this;
@Override
public Writer outWriter(String fileName) throws IOException {
File dir;
if (packageName != null && packageName.isBlank() == false) {
dir = new File(rootPath.toFile(), packageName.replace('.', File.separatorChar));
}
else {
dir = rootPath.toFile();
}
return new FileWriter(new File(dir, mapFilenameToClassName(fileName) + ".java"), false);
}
public Builder setPackageName(String packageName) {
this.packageName = packageName;
return this;
public static Configuration parse(String[] args) throws IOException {
CliConfig cliConfig = new CliConfig();
Builder builder = new Builder();
cliConfig.fill(builder, args);
return builder.build();
}
public Configuration build() throws IOException {
return new ArgumentConfiguration(this);
static class Builder {
String target;
List<String> propFiles = new ArrayList<>();
String packageName;
boolean replaceUsages;
/**
* Target Directory Path.
* @param target
* @return
*/
public Builder setTarget(String target) {
this.target = target;
return this;
}
public Builder addPropFile(String propFile) {
this.propFiles.add(propFile);
return this;
}
/**
* Package to be used in generated Sources
* @param packageName
* @return
*/
public Builder setPackageName(String packageName) {
this.packageName = packageName;
return this;
}
/**
* Search and replace usages of generated sources.
* @param replaceUsages
* @return
*/
public Builder setReplaceUsages(boolean replaceUsages) {
this.replaceUsages = replaceUsages;
return this;
}
public Configuration build() throws IOException {
return new ArgumentConfiguration(this);
}
}
}
}

@ -22,6 +22,7 @@ public class CliConfig {
retVal.addOption(Option.builder("t").longOpt("targetSourcePath").hasArg().required().build());
retVal.addOption(Option.builder("f").longOpt("files").hasArgs().required().valueSeparator(',').build());
retVal.addOption(Option.builder("p").longOpt("package").hasArg().required(false).build());
retVal.addOption(Option.builder("u").longOpt("replaceUsages").hasArg(false).required(false).build());
return retVal;
}
@ -32,6 +33,7 @@ public class CliConfig {
CommandLine cmd = parser.parse(options, args);
builder.setTarget(cmd.getOptionValue("t", "."));
builder.setPackageName(cmd.getOptionValue("p"));
builder.setReplaceUsages(cmd.hasOption("u"));
for (String value : cmd.getOptionValues("f")) {
builder.addPropFile(value);
}

@ -1,37 +1,5 @@
package de.kreth.property2java.config;
import java.io.IOException;
import de.kreth.property2java.processor.Format;
import freemarker.template.Configuration;
import freemarker.template.Template;
public enum FreemarkerConfig {
INSTANCE;
private final Configuration cfg;
public Template getTemplate(Format format) throws IOException {
switch (format) {
case WithInitializer:
return cfg.getTemplate("enum_template_with_initializer.tpl");
case WithInnerPropertyLoader:
return cfg.getTemplate("enum_template_with_inner_properties.tpl");
case WithInnerPropertyResourceBundle:
return cfg.getTemplate("enum_template_with_inner_propertyresourcebundle.tpl");
case WithUnaryOperatorParameter:
return cfg.getTemplate("enum_template.tpl");
default:
throw new IllegalArgumentException("Format " + format + " is not supported.");
}
}
private FreemarkerConfig() {
cfg = new Configuration(Configuration.VERSION_2_3_28);
cfg.setClassForTemplateLoading(this.getClass(), "/template/");
cfg.setDefaultEncoding("UTF-8");
}
public interface FreemarkerConfig {
}

@ -0,0 +1,24 @@
package de.kreth.property2java.config;
import java.io.IOException;
import freemarker.template.Configuration;
import freemarker.template.Template;
public enum FreemarkerConfigImpl implements FreemarkerConfig {
INSTANCE;
private final Configuration cfg;
public Template getTemplate() throws IOException {
return cfg.getTemplate("enum_template.tpl");
}
private FreemarkerConfigImpl() {
cfg = new Configuration(Configuration.VERSION_2_3_28);
cfg.setClassForTemplateLoading(this.getClass(), "/template/");
cfg.setDefaultEncoding("UTF-8");
}
}

@ -1,27 +0,0 @@
package de.kreth.property2java.processor;
import java.util.PropertyResourceBundle;
public enum Format {
/**
* Offers a getString(UnaryOperator<String> resourceFunction) method to access
* the String value
*/
WithUnaryOperatorParameter,
/**
* Generates {@link PropertyResourceBundle} to offer a getText() method without
* parameters.
*/
WithInnerPropertyResourceBundle,
/**
* Offers a generated {@link PropertyResourceBundle} to offer a getText() method
* without parameters.
*/
WithInnerPropertyLoader,
/**
* Offers a static init(UnaryOperator<String> resourceFunction) method to offer
* a getText() method. The init method must be called before any getText() call.
*/
WithInitializer
}

@ -1,42 +0,0 @@
package de.kreth.property2java.processor;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(TYPE)
@Retention(RetentionPolicy.SOURCE)
/**
* Für die konfigurierten Resourcen wird jeweils eine Java Klasse erzeugt. Es
* muss nur die Abhängigkeit eingebunden werden und die Annotation in einer
* Klasse verwendet werden, in deren Package die neuen Klassen generiert werden.
*
* Für die Ausgabe der Prozessornachrichten muss folgendes im maven compiler
* konfiguriert werden:
*
* <pre>
&lt;build&gt;
&lt;plugins&gt;
&lt;plugin&gt;
&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
&lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
&lt;version&gt;3.8.0&lt;/version&gt;
&lt;configuration&gt;
&lt;release&gt;${java.version}&lt;/release&gt;
<b>&lt;showWarnings&gt;true&lt;/showWarnings&gt;</b>
&lt;/configuration&gt;
&lt;/plugin&gt;
&lt;/plugins&gt;
&lt;/build&gt;
* </pre>
*
* @author Markus
*
*/
public @interface GenerateProperty2Java {
String[] resources();
Format format() default Format.WithUnaryOperatorParameter;
}

@ -1,46 +0,0 @@
package de.kreth.property2java.processor;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(TYPE)
@Retention(RetentionPolicy.SOURCE)
@Repeatable(value = GenerateResourceBundleProperty2Javas.class)
/**
* Für die konfigurierten Resourcen wird jeweils eine Java Klasse erzeugt. Es
* muss nur die Abhängigkeit eingebunden werden und die Annotation in einer
* Klasse verwendet werden, in deren Package die neuen Klassen generiert werden.
* Wenn mehrere Resourcen verarbeitet werden sollen, kann diese Annotation
* mehrfach parallel angegeben werden.
*
* Für die Ausgabe der Prozessornachrichten muss folgendes im maven compiler
* konfiguriert werden:
*
* <pre>
&lt;build&gt;
&lt;plugins&gt;
&lt;plugin&gt;
&lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
&lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
&lt;version&gt;3.8.0&lt;/version&gt;
&lt;configuration&gt;
&lt;release&gt;${java.version}&lt;/release&gt;
<b>&lt;showWarnings&gt;true&lt;/showWarnings&gt;</b>
&lt;/configuration&gt;
&lt;/plugin&gt;
&lt;/plugins&gt;
&lt;/build&gt;
* </pre>
*
* @author Markus
*
*/
public @interface GenerateResourceBundleProperty2Java {
String resource();
Format format();
}

@ -1,21 +0,0 @@
package de.kreth.property2java.processor;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Diese Annotation sollte nicht verwendet werden. Sie sammelt nur
* {@link GenerateResourceBundleProperty2Java} wenn diese mehrfach verwendet
* wird.
*
* @author Markus
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface GenerateResourceBundleProperty2Javas {
GenerateResourceBundleProperty2Java[] value();
}

@ -1,116 +0,0 @@
package de.kreth.property2java.processor;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.annotation.processing.Filer;
import javax.lang.model.element.Element;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import de.kreth.property2java.Configuration;
import de.kreth.property2java.Generator;
import de.kreth.property2java.GeneratorException;
public class ProcessorConfiguration implements Configuration {
private final Filer filer;
private final Element element;
private final Map<String, Reader> input;
private final Format format;
ProcessorConfiguration(Builder builder) throws IOException {
this.filer = builder.filer;
this.element = builder.element;
this.format = Objects.requireNonNullElse(builder.format, Format.WithUnaryOperatorParameter);
this.input = new HashMap<>();
for (String resource : builder.resourcenames) {
FileObject ressource = filer.getResource(StandardLocation.CLASS_PATH, "", resource);
input.put(resource, ressource.openReader(false));
}
}
@Override
public String getPackage() {
String packageName = "";
if (element instanceof TypeElement) {
TypeElement typeElement = (TypeElement) element;
PackageElement packageElement = (PackageElement) typeElement.getEnclosingElement();
packageName = packageElement.getQualifiedName().toString();
}
return packageName;
}
@Override
public Format getFormat() {
return format;
}
@Override
public Map<String, Reader> getInput() {
return input;
}
@Override
public Path getRootPath() {
throw new UnsupportedOperationException(
"For Annotation Processor this is not supported as outWriter is overwritten.");
}
@Override
public Writer outWriter(String fileName) throws IOException {
String packageName = getPackage();
if (packageName != null && !packageName.isBlank()) {
fileName = packageName + "." + mapFilenameToClassName(fileName);
}
return filer.createSourceFile(fileName, element).openWriter();
}
static Builder builder(Filer filer, Element element) {
return new Builder(filer, element);
}
static class Builder {
private final Filer filer;
private final Element element;
private final List<String> resourcenames;
private Format format = Format.WithUnaryOperatorParameter;
private Builder(Filer filer, Element element) {
this.filer = filer;
this.element = element;
this.resourcenames = new ArrayList<>();
}
public Builder withFormat(Format format) {
this.format = format;
return this;
}
public Builder addAll(String[] resourceNames) {
this.resourcenames.addAll(Arrays.asList(resourceNames));
return this;
}
public Builder addAll(List<String> resourceNames) {
this.resourcenames.addAll(resourceNames);
return this;
}
public void startGeneration() throws IOException, GeneratorException {
Generator g = new Generator(new ProcessorConfiguration(this));
g.start();
}
}
}

@ -1,91 +0,0 @@
package de.kreth.property2java.processor;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
import de.kreth.property2java.GeneratorException;
@SupportedAnnotationTypes({ "de.kreth.property2java.processor.GenerateProperty2Java",
"de.kreth.property2java.processor.GenerateResourceBundleProperty2Javas",
"de.kreth.property2java.processor.GenerateResourceBundleProperty2Java" })
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class Property2JavaGenerator extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (!roundEnv.processingOver()) {
processGenerateProperty2Java(roundEnv);
processGenerateResourceBundleProperty2Javas(roundEnv);
} else {
processingEnv.getMessager().printMessage(Kind.NOTE,
"finished working on annotation " + annotations);
}
return true;
}
private void processGenerateProperty2Java(RoundEnvironment roundEnv) {
processingEnv.getMessager().printMessage(Kind.NOTE,
"Processing annotation " + GenerateProperty2Java.class);
Set<? extends Element> elementsAnnotatedWith = roundEnv
.getElementsAnnotatedWith(GenerateProperty2Java.class);
for (Element element : elementsAnnotatedWith) {
GenerateProperty2Java generateAnnotation = element.getAnnotation(GenerateProperty2Java.class);
String[] resources = generateAnnotation.resources();
Format format = generateAnnotation.format();
generateElementProperties(element, Arrays.asList(resources), format);
}
}
private void processGenerateResourceBundleProperty2Javas(RoundEnvironment roundEnv) {
processingEnv.getMessager().printMessage(Kind.NOTE,
"Processing annotation " + GenerateResourceBundleProperty2Javas.class);
Set<? extends Element> elementsAnnotatedWith = roundEnv
.getElementsAnnotatedWith(GenerateResourceBundleProperty2Javas.class);
for (Element element : elementsAnnotatedWith) {
GenerateResourceBundleProperty2Java[] value = element
.getAnnotation(GenerateResourceBundleProperty2Javas.class).value();
for (GenerateResourceBundleProperty2Java generateResourceBundleProperty2Java : value) {
List<String> resources = Arrays.asList(generateResourceBundleProperty2Java.resource());
generateElementProperties(element, resources, generateResourceBundleProperty2Java.format());
}
}
}
private void generateElementProperties(Element element, List<String> resources, Format format) {
processingEnv.getMessager().printMessage(Kind.NOTE,
"Generating Java for " + Arrays.asList(resources));
try {
ProcessorConfiguration
.builder(processingEnv.getFiler(), element)
.addAll(resources)
.withFormat(format)
.startGeneration();
} catch (IOException | GeneratorException e) {
StringWriter out = new StringWriter();
e.printStackTrace(new PrintWriter(out));
out.flush();
processingEnv.getMessager().printMessage(Kind.ERROR, "Exception " + e + "\n" + out.toString(),
element);
}
}
}

@ -0,0 +1,152 @@
package de.kreth.property2java.replace;
import java.util.Arrays;
import java.util.List;
public class Replacement {
private static final List<Character> CHARS_NOT_ALLOWED_BEFORE_PROPERTY = Arrays.asList('.');
private final String packageName;
private final String simpleClassName;
private final String oldPropertyName;
private final String newPropertyName;
private String qualifiedClassName;
private String qualifiedOldProperty;
public Replacement(String packageName, String simpleClassName, String oldPropertyName, String newPropertyName) {
super();
this.packageName = packageName;
this.simpleClassName = simpleClassName;
this.oldPropertyName = oldPropertyName;
this.newPropertyName = newPropertyName;
this.qualifiedClassName = packageName + "." + simpleClassName;
this.qualifiedOldProperty = qualifiedClassName + "." + oldPropertyName;
}
public String getOldPropertyName() {
return oldPropertyName;
}
public String getNewPropertyName() {
return newPropertyName;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((newPropertyName == null) ? 0 : newPropertyName.hashCode());
result = prime * result + ((oldPropertyName == null) ? 0 : oldPropertyName.hashCode());
result = prime * result + ((packageName == null) ? 0 : packageName.hashCode());
result = prime * result + ((simpleClassName == null) ? 0 : simpleClassName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Replacement other = (Replacement) obj;
if (newPropertyName == null) {
if (other.newPropertyName != null) {
return false;
}
}
else if (!newPropertyName.equals(other.newPropertyName)) {
return false;
}
if (oldPropertyName == null) {
if (other.oldPropertyName != null) {
return false;
}
}
else if (!oldPropertyName.equals(other.oldPropertyName)) {
return false;
}
if (packageName == null) {
if (other.packageName != null) {
return false;
}
}
else if (!packageName.equals(other.packageName)) {
return false;
}
if (simpleClassName == null) {
if (other.simpleClassName != null) {
return false;
}
}
else if (!simpleClassName.equals(other.simpleClassName)) {
return false;
}
return true;
}
@Override
public String toString() {
return "Replacement [packageName=" + packageName + ", simpleClassName=" + simpleClassName + ", oldPropertyName="
+ oldPropertyName + ", newPropertyName=" + newPropertyName + "]";
}
public String replaceOccurrences(String sourceCode) {
if (sourceCode.contains("import static " + qualifiedOldProperty)) {
sourceCode = replaceStaticImportedUsages(sourceCode);
}
if (sourceCode.contains(qualifiedOldProperty)) {
sourceCode = replaceFullQualifiedUnimported(sourceCode);
}
if (sourceCode.contains("import " + qualifiedClassName)) {
sourceCode = replaceClassUsages(sourceCode);
}
return sourceCode;
}
private String replaceClassUsages(String sourceCode) {
String search = this.simpleClassName + "." + oldPropertyName;
String replacement = this.simpleClassName + "." + newPropertyName;
int index = sourceCode.indexOf(search);
while (index > 0) {
if (!CHARS_NOT_ALLOWED_BEFORE_PROPERTY.contains(sourceCode.charAt(index - 1))) {
StringBuilder source = new StringBuilder(sourceCode);
source.replace(index, index + search.length(), replacement);
sourceCode = source.toString();
}
index = sourceCode.indexOf(search, index + 1);
}
return sourceCode;
}
private String replaceStaticImportedUsages(String sourceCode) {
int index = sourceCode.indexOf(oldPropertyName);
while (index > 0) {
if (!CHARS_NOT_ALLOWED_BEFORE_PROPERTY.contains(sourceCode.charAt(index - 1))) {
StringBuilder source = new StringBuilder(sourceCode);
source.replace(index, index + oldPropertyName.length(), newPropertyName);
sourceCode = source.toString();
}
index = sourceCode.indexOf(oldPropertyName, index + 1);
}
return sourceCode;
}
private String replaceFullQualifiedUnimported(String sourceCode) {
return sourceCode.replace(qualifiedOldProperty,
qualifiedClassName + "." + newPropertyName);
}
}

@ -0,0 +1,14 @@
package de.kreth.property2java.replace;
import java.util.ArrayList;
import java.util.List;
public class Replacements {
private final List<Replacement> replacementList = new ArrayList<>();
public boolean add(Replacement e) {
return replacementList.add(e);
}
}

@ -1 +0,0 @@
de.kreth.property2java.processor.Property2JavaGenerator

@ -8,8 +8,6 @@ import javax.annotation.processing.Generated;
/**
* Property keys from ${fileName}
* {@link #getValue()} gives the key for the entry, with {@link #getString(UnaryOperator<String>)}
* the value is given directly.
*/
@Generated(date = "${generation_date}", value = "${generator_name}")
public enum ${classname} {

@ -1,62 +0,0 @@
<#if package??>package ${package};
</#if>import java.util.Properties;
import java.util.ResourceBundle;
import java.util.function.UnaryOperator;
import javax.annotation.processing.Generated;
/**
* Property keys from ${fileName}
* {@link #getValue()} gives the key for the entry, with {@link #getText()} the value for the key is given directly.
* This enum needs to be initialized before any use by {@link #init(UnaryOperator)}.
*/
@Generated(date = "${generation_date}", value = "${generator_name}")
public enum ${classname} {
<#list entries as e>
/**
* ${e.key} = "${e.value}"
*/
${e.constant} ("${e.key}")<#sep>,
</#sep>
</#list>;
private static UnaryOperator<String> function;
private final String value;
private ${classname} (String value) {
this.value = value;
}
public static void init(UnaryOperator<String> resourceFunction) {
function = resourceFunction;
}
/**
* Represented Key in property File.
* @return key
*/
public String getValue() {
return value;
}
/**
* Resolves the value for this key.
* {@link #init(UnaryOperator<String>)} must be called before.
*/
public String getText() {
return function.apply(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);
}
}

@ -1,48 +0,0 @@
<#if package??>package ${package};
</#if>import java.util.Properties;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
import java.util.function.UnaryOperator;
import javax.annotation.processing.Generated;
/**
* Property keys from ${fileName}
*/
@Generated(date = "${generation_date}", value = "${generator_name}")
public enum ${classname} {
<#list entries as e>
/**
* ${e.key} = "${e.value}"
*/
${e.constant} ("${e.key}")<#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;
}
private static ResourceBundle bundle = PropertyResourceBundle.getBundle("${bundle_base_name}");
/**
* The Text for this Key from PropertyResourceBundle
* @return human readable text
*/
public String getText() {
return bundle.getString(value);
}
}

@ -1,50 +0,0 @@
<#if package??>package ${package};
</#if>import java.util.Properties;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
import java.util.function.UnaryOperator;
import javax.annotation.processing.Generated;
/**
* Property keys from ${fileName}
* {@link #getValue()} gives the key for the entry, with {@link #getText()} the value for the key is given directly.
* Initializationis generated also.
*/
@Generated(date = "${generation_date}", value = "${generator_name}")
public enum ${classname} {
<#list entries as e>
/**
* ${e.key} = "${e.value}"
*/
${e.constant} ("${e.key}")<#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;
}
private static ResourceBundle bundle = PropertyResourceBundle.getBundle("${bundle_base_name}");
/**
* The Text for this Key from PropertyResourceBundle
* @return human readable text
*/
public String getText() {
return bundle.getString(value);
}
}

@ -3,8 +3,11 @@ package de.kreth.property2java;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@ -27,151 +30,170 @@ import org.hamcrest.Matchers;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import freemarker.template.Template;
import freemarker.template.TemplateException;
class GeneratorTests {
private String path = "application.properties";
private Configuration config;
private Generator generator;
@BeforeEach
void setUp() throws Exception {
Map<String, Reader> input = new HashMap<>();
input.put(path, testProperties());
config = mock(Configuration.class);
when(config.getInput()).thenReturn(input);
when(config.mapFilenameToClassName(anyString())).thenCallRealMethod();
when(config.outputCharset()).thenCallRealMethod();
generator = new Generator(config);
}
@Test
void testClassDefinition() throws IOException, GeneratorException {
when(config.getPackage()).thenReturn("de.kreth.property2java");
when(config.mapFilenameToClassName(anyString())).thenCallRealMethod();
StringWriter out = new StringWriter();
when(config.outWriter(anyString())).thenReturn(out);
generator.start();
String sourceCode = out.toString().trim();
StringTokenizer sourceTokenizer = new StringTokenizer(sourceCode, "\n");
String linePackage = null;
String lineClass = null;
int countOpenBaces = 0;
int countCloseBaces = 0;
while (sourceTokenizer.hasMoreTokens()) {
String line = sourceTokenizer.nextToken();
if (line.trim().startsWith("package")) {
linePackage = line;
} else if (line.trim().startsWith("public enum")) {
lineClass = line;
}
if (line.contains("{")) {
countOpenBaces++;
}
if (line.contains("}")) {
countCloseBaces++;
}
private String path = "application.properties";
private Configuration config;
private Generator generator;
@BeforeEach
void setUp() throws Exception {
Map<String, Reader> input = new HashMap<>();
input.put(path, testProperties());
config = mock(Configuration.class);
when(config.getInput()).thenReturn(input);
when(config.mapFilenameToClassName(anyString())).thenCallRealMethod();
when(config.getTemplate()).thenCallRealMethod();
generator = new Generator(config);
}
@Test
void testClassDefinition() throws IOException, GeneratorException {
when(config.getPackage()).thenReturn("de.kreth.property2java");
when(config.mapFilenameToClassName(anyString())).thenCallRealMethod();
StringWriter out = new StringWriter();
when(config.outWriter(anyString())).thenReturn(out);
generator.start();
String sourceCode = out.toString().trim();
StringTokenizer sourceTokenizer = new StringTokenizer(sourceCode, "\n");
String linePackage = null;
String lineClass = null;
int countOpenBaces = 0;
int countCloseBaces = 0;
while (sourceTokenizer.hasMoreTokens()) {
String line = sourceTokenizer.nextToken();
if (line.trim().startsWith("package")) {
linePackage = line;
}
else if (line.trim().startsWith("public enum")) {
lineClass = line;
}
if (line.contains("{")) {
countOpenBaces++;
}
if (line.contains("}")) {
countCloseBaces++;
}
}
assertEquals(countCloseBaces, countOpenBaces,
"Count of Braces doesn't match. Open = " + countOpenBaces + ", Close = " + countCloseBaces);
assertNotNull(linePackage);
assertNotNull(lineClass);
assertThat(linePackage,
Matchers.stringContainsInOrder(Arrays.asList("package", "de.kreth.property2java", ";")));
assertThat(lineClass,
Matchers.stringContainsInOrder(Arrays.asList("public", "enum", "Application_Properties")));
}
assertEquals(countCloseBaces, countOpenBaces,
"Count of Braces doesn't match. Open = " + countOpenBaces + ", Close = " + countCloseBaces);
assertNotNull(linePackage);
assertNotNull(lineClass);
assertThat(linePackage,
Matchers.stringContainsInOrder(Arrays.asList("package", "de.kreth.property2java", ";")));
assertThat(lineClass,
Matchers.stringContainsInOrder(Arrays.asList("public", "enum", "Application_Properties")));
}
@Test
void testOneInputGeneratesOneOutput() throws IOException, GeneratorException {
Writer out = mock(Writer.class);
Writer nonOut = mock(Writer.class);
when(config.outWriter(anyString())).thenReturn(out, nonOut);
generator.start();
verify(out).close();
verify(nonOut, never()).close();
verify(nonOut, never()).flush();
}
@Test
void testKeys() throws IOException, GeneratorException {
StringWriter out = new StringWriter();
when(config.outWriter(anyString())).thenReturn(out);
generator.start();
List<String> lines = out.toString().lines().filter(line -> line.contains(" (\""))
.collect(Collectors.toList());
assertEquals(21, lines.size());
assertLineMatch(lines, "label", "label");
assertLineMatch(lines, "label_addarticle", "label.addarticle");
assertLineMatch(lines, "label_user_register", "label.user.register");
assertLineMatch(lines, "message_article_priceerror", "message.article.priceerror");
assertLineMatch(lines, "message_invoiceitem_startbeforeend",
"message.invoiceitem.startbeforeend");
assertLineMatch(lines, "message_invoiceitem_allfieldsmustbeset",
"message.invoiceitem.allfieldsmustbeset");
}
private void assertLineMatch(List<String> lines, String key, String expected) {
Optional<String> found = lines.stream().filter(line -> keyMatches(line, key))
.findFirst();
assertTrue(found.isPresent(), "No line found with key = " + key);
final String line = found.get().trim();
int indexEquals = line.indexOf('(');
String value = line.substring(indexEquals + 1).trim().substring(1);
value = value.substring(0, value.length() - 3);
assertEquals(expected, value, "Line \"" + line + "\" don't match expected Value \"" + expected + "\"");
}
private boolean keyMatches(String line, String key) {
line = line.toLowerCase();
key = key.toLowerCase();
return line.contains("\t" + key + " ");
}
private StringReader testProperties() {
return new StringReader("\r\n" +
"label = \r\n" +
"\r\n" +
"label.addarticle = Add Article\r\n" +
"label.cancel = Cancel\r\n" +
"label.close = Close\r\n" +
"label.delete = Delete\r\n" +
"label.discart = Discart\r\n" +
"label.loggedin = Logged in:\r\n" +
"label.logout = Logout\r\n" +
"label.ok = OK\r\n" +
"label.store = Store\r\n" +
"label.preview = Preview\r\n" +
"label.open = Open\r\n" +
"label.user.register = Register\r\n" +
"\r\n" +
"message.article.priceerror = Please set the price.\r\n" +
"message.delete.text = Delete {0}?\r\n" +
"message.delete.title = Really delete?\r\n" +
"message.invoiceitem.allfieldsmustbeset = Start, end and article must not be \\r\\n" +
" empty!\r\n" +
"message.invoiceitem.startbeforeend = End must be later than start.\r\n" +
"message.user.create.success = Thanks {0} created!\r\n" +
"message.user.loginfailure = Login Error! Wrong user or password?\r\n" +
"message.user.passwordmissmatch = Passwords don't match.\r\n" +
"");
}
@Test()
void testTemplateException() throws IOException, GeneratorException, TemplateException {
Writer out = mock(Writer.class);
when(config.outWriter(anyString())).thenReturn(out);
Template template = mock(Template.class);
when(config.getTemplate()).thenReturn(template);
doThrow(TemplateException.class).when(template).process(any(), any());
generator = new Generator(config);
assertThrows(GeneratorException.class, () -> generator.start());
}
@Test
void testOneInputGeneratesOneOutput() throws IOException, GeneratorException {
Writer out = mock(Writer.class);
Writer nonOut = mock(Writer.class);
when(config.outWriter(anyString())).thenReturn(out, nonOut);
generator.start();
verify(out).close();
verify(nonOut, never()).close();
verify(nonOut, never()).flush();
}
@Test
void testKeys() throws IOException, GeneratorException {
StringWriter out = new StringWriter();
when(config.outWriter(anyString())).thenReturn(out);
generator.start();
List<String> lines = out.toString().lines().filter(line -> line.contains(" (\""))
.collect(Collectors.toList());
assertEquals(21, lines.size());
assertLineMatch(lines, "label", "label");
assertLineMatch(lines, "label_addarticle", "label.addarticle");
assertLineMatch(lines, "label_user_register", "label.user.register");
assertLineMatch(lines, "message_article_priceerror", "message.article.priceerror");
assertLineMatch(lines, "message_invoiceitem_startbeforeend",
"message.invoiceitem.startbeforeend");
assertLineMatch(lines, "message_invoiceitem_allfieldsmustbeset",
"message.invoiceitem.allfieldsmustbeset");
}
private void assertLineMatch(List<String> lines, String key, String expected) {
Optional<String> found = lines.stream().filter(line -> keyMatches(line, key))
.findFirst();
assertTrue(found.isPresent(), "No line found with key = " + key);
final String line = found.get().trim();
int indexEquals = line.indexOf('(');
String value = line.substring(indexEquals + 1).trim().substring(1);
value = value.substring(0, value.length() - 3);
assertEquals(expected, value, "Line \"" + line + "\" don't match expected Value \"" + expected + "\"");
}
private boolean keyMatches(String line, String key) {
line = line.toLowerCase();
key = key.toLowerCase();
return line.contains("\t" + key + " ");
}
private StringReader testProperties() {
return new StringReader("\r\n" +
"label = \r\n" +
"\r\n" +
"label.addarticle = Add Article\r\n" +
"label.cancel = Cancel\r\n" +
"label.close = Close\r\n" +
"label.delete = Delete\r\n" +
"label.discart = Discart\r\n" +
"label.loggedin = Logged in:\r\n" +
"label.logout = Logout\r\n" +
"label.ok = OK\r\n" +
"label.store = Store\r\n" +
"label.preview = Preview\r\n" +
"label.open = Open\r\n" +
"label.user.register = Register\r\n" +
"\r\n" +
"message.article.priceerror = Please set the price.\r\n" +
"message.delete.text = Delete {0}?\r\n" +
"message.delete.title = Really delete?\r\n" +
"message.invoiceitem.allfieldsmustbeset = Start, end and article must not be \\r\\n" +
" empty!\r\n" +
"message.invoiceitem.startbeforeend = End must be later than start.\r\n" +
"message.user.create.success = Thanks {0} created!\r\n" +
"message.user.loginfailure = Login Error! Wrong user or password?\r\n" +
"message.user.passwordmissmatch = Passwords don't match.\r\n" +
"");
}
}

@ -0,0 +1,55 @@
package de.kreth.property2java.cli;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.util.Map;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import de.kreth.property2java.Configuration;
class ArgumentConfigurationTest {
private static File target;
private static File input;
private static File input2;
@BeforeAll
static void createTargetDir() throws IOException {
target = new File("testTargetDir");
target.mkdir();
input = new File(target, "application.properties");
input.createNewFile();
input2 = new File(target, "application2.properties");
input2.createNewFile();
}
@AfterAll
static void deleteTestfiles() {
target.delete();
input.delete();
input2.delete();
}
@Test
void testArgumentParser() throws IOException {
String[] args = { "-t", target.getAbsolutePath(),
"-f",
input.getAbsolutePath() + "," + input2.getAbsolutePath(),
"-p", "de.kreth.clubinvoice" };
Configuration config = ArgumentConfiguration.parse(args);
assertEquals("de.kreth.clubinvoice", config.getPackage());
assertEquals(target.getAbsolutePath(), config.getRootPath().toFile().getAbsolutePath());
Map<String, Reader> inputMap = config.getInput();
assertEquals(2, inputMap.size());
}
}

@ -1,46 +0,0 @@
package de.kreth.property2java.processor;
import static org.mockito.Mockito.when;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.TypeElement;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class Property2JavaGeneratorTest {
private Property2JavaGenerator processor;
@Mock
private ProcessingEnvironment processingEnv;
@Mock
private RoundEnvironment roundEnv;
private Set<TypeElement> annotations;
@Mock
private Messager messanger;
@BeforeEach
void initProcesor() {
MockitoAnnotations.initMocks(this);
annotations = new HashSet<>();
processor = new Property2JavaGenerator();
processor.init(processingEnv);
when(processingEnv.getMessager()).thenReturn(messanger);
}
@Test
void testGeneratorInitializedCorrectly() {
when(roundEnv.getElementsAnnotatedWith(ArgumentMatchers.any(Class.class)))
.thenReturn(annotations);
processor.process(annotations, roundEnv);
}
}

@ -0,0 +1,163 @@
package de.kreth.property2java.replace;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import de.kreth.property2java.replace.Replacement;
class ReplacementTest {
private Replacement captionArticles;
private Replacement labelLogout;
private Replacement captionUserDetails;
@BeforeEach
void initTestItem() {
captionArticles = new Replacement("de.kreth.clubinvoice", "Application_Properties", "CAPTION_ARTICLES",
"CAPTION1_ARTICLES");
captionUserDetails = new Replacement("de.kreth.clubinvoice", "Application_Properties",
"CAPTION_USER_DETAILS",
"CAPTION1_USER_DETAILS");
labelLogout = new Replacement("de.kreth.clubinvoice", "Application_Properties", "LABEL_LOGOUT",
"LABEL1_LOGOUT");
}
@Test
void testReplaceStaticImported() {
String exampleSourceCode = getExampleSourceCode();
String result = captionArticles.replaceOccurrences(exampleSourceCode);
assertNotNull(result);
Optional<String> firstLine = result.lines()
.filter(line -> line.contains("de.kreth.clubinvoice.Application_Properties")).findFirst();
assertTrue(firstLine.isPresent());
String captionArticlesLine = firstLine.get();
assertEquals("import static de.kreth.clubinvoice.Application_Properties.CAPTION1_ARTICLES;",
captionArticlesLine.trim());
firstLine = result.lines().filter(l -> l.contains("new Button(CAPTION1_ARTICLES.getString(")).findFirst();
assertTrue(firstLine.isPresent(), "CAPTION1_ARTICLES usage not found");
}
@Test
void testReplaceClassImport() {
String exampleSourceCode = getExampleSourceCode();
String result = labelLogout.replaceOccurrences(exampleSourceCode);
Optional<String> line = result.lines()
.filter(l -> l.contains(".getString(Application_Properties.LABEL1_LOGOUT"))
.findFirst();
assertTrue(line.isPresent());
}
@Test
void testReplaceUnimportedOccurrence() {
String exampleSourceCode = getExampleSourceCode();
String result = captionUserDetails.replaceOccurrences(exampleSourceCode);
Optional<String> line = result.lines()
.filter(l -> l.contains("new Button(de.kreth.clubinvoice.Application_Properties")
&& l.contains("_USER_DETAILS"))
.findFirst();
assertTrue(line.isPresent());
assertTrue(line.get().contains("de.kreth.clubinvoice.Application_Properties.CAPTION1_USER_DETAILS"),
"absoulute class field CAPTION1_USER_DETAILS not found in : " + line.get());
}
@Test
void testReplaceUnimportedOccurrenceWithLinebreak() {
String exampleSourceCode = getExampleSourceCode();
String result = captionUserDetails.replaceOccurrences(exampleSourceCode);
List<String> lines = result.lines()
.filter(l -> l.contains(".Application_Properties")
&& l.contains("_USER_DETAILS"))
.collect(Collectors.toList());
assertEquals(2, lines.size());
//
// assertTrue(line.get().contains("de.kreth.clubinvoice.Application_Properties.CAPTION1_USER_DETAILS"),
// "absoulute class field CAPTION1_USER_DETAILS not found in : " + line.get());
}
String getExampleSourceCode() {
return "package de.kreth.clubinvoice.ui;\r\n" +
"\r\n" +
"import static de.kreth.clubinvoice.Application_Properties.CAPTION_ARTICLES;\r\n" +
"import static de.kreth.clubinvoice.Application_Properties.CAPTION_INVOICEITEM_ADD;\r\n" +
"" +
"import static de.kreth.clubinvoice.Application_Properties.CAPTION_INVOICE_PATTERN;\r\n" +
"\r\n" +
"import org.slf4j.Logger;\r\n" +
"import org.slf4j.LoggerFactory;\r\n" +
"\r\n" +
"\r\n" +
"import de.kreth.clubinvoice.Application_Properties;\r\n" +
"\r\n" +
"public class OverviewUi extends VerticalLayout implements InvoiceUi {\r\n" +
"\r\n" +
" public void setContent(UI ui, VaadinRequest vaadinRequest) {\r\n" +
"\r\n" +
" }\r\n" +
"\r\n" +
" public VerticalLayout createInvoicesView(final UI ui) {\r\n" +
"\r\n" +
" createInvoice = new Button(CAPTION_INVOICE_CREATE.getString(resBundle::getString));\r\n" +
" return right;\r\n" +
" }\r\n" +
"\r\n" +
" public VerticalLayout createItemsView(final UI ui) {\r\n" +
"\r\n" +
" addItem = new Button(de.kreth.clubinvoice.Application_Properties.CAPTION_INVOICE_CREATE.getString(resBundle::getString));\r\n"
+
"\r\n" +
" VerticalLayout left = new VerticalLayout();\r\n" +
" addItem = new Button(de.kreth.clubinvoice"
+ " \t.Application_Properties.CAPTION_INVOICE_CREATE.getString(resBundle::getString));\r\n" +
" left.addComponents(addItem, gridItems);\r\n" +
" left.setStyleName(STYLE_BORDERED);\r\n" +
" return left;\r\n" +
" }\r\n" +
"\r\n" +
" public HorizontalLayout createHeadView(final UI ui, VaadinRequest vaadinRequest) {\r\n" +
" Label l2 = new Label(String.format(\"%s %s\", user.getPrename(), user.getSurname()));\r\n" +
"\r\n" +
" Button addArticle = new Button(CAPTION_ARTICLES.getString(resBundle::getString));\r\n" +
" Button logoutButton = new Button(resBundle.getString(Application_Properties.LABEL_LOGOUT.getValue()));\r\n"
+
" logoutButton.addClickListener(ev -> {\r\n" +
" LOGGER.warn(\"Logging out.\");\r\n" +
" logout(ui, vaadinRequest);\r\n" +
" });\r\n" +
"\r\n" +
" Button userDetail = new Button(de.kreth.clubinvoice.Application_Properties.CAPTION_USER_DETAILS.getString(resBundle::getString), ev -> {\r\n"
+
" Button userDetail2 = new Button(de.kreth.clubinvoice"
+ " \t.Application_Properties.CAPTION_USER_DETAILS.getString(resBundle::getString), ev -> {\r\n"
+
" showUserDetailDialog(ui);\r\n" +
" });\r\n" +
"\r\n" +
" return head;\r\n" +
" }\r\n" +
"\r\n" +
"}\r\n" +
"";
}
}
Loading…
Cancel
Save