From e6d324477fd1b8f3ba02b94d298735c5e6ec10e5 Mon Sep 17 00:00:00 2001 From: Markus Kreth Date: Sun, 31 Mar 2019 02:01:09 +0100 Subject: [PATCH] Replace in Source code started. --- .../de/kreth/property2java/Configuration.java | 12 ++ .../cli/ArgumentConfiguration.java | 22 +++ .../de/kreth/property2java/cli/CliConfig.java | 2 + .../property2java/replace/Replacement.java | 152 ++++++++++++++++ .../property2java/replace/Replacements.java | 14 ++ .../kreth/property2java/ReplacementTest.java | 168 ++++++++++++++++++ 6 files changed, 370 insertions(+) create mode 100644 src/main/java/de/kreth/property2java/replace/Replacement.java create mode 100644 src/main/java/de/kreth/property2java/replace/Replacements.java create mode 100644 src/test/java/de/kreth/property2java/ReplacementTest.java diff --git a/src/main/java/de/kreth/property2java/Configuration.java b/src/main/java/de/kreth/property2java/Configuration.java index 500f14d..f2cde02 100644 --- a/src/main/java/de/kreth/property2java/Configuration.java +++ b/src/main/java/de/kreth/property2java/Configuration.java @@ -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.file.Path; import java.util.Map; @@ -34,6 +36,16 @@ public interface Configuration { */ 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")); } diff --git a/src/main/java/de/kreth/property2java/cli/ArgumentConfiguration.java b/src/main/java/de/kreth/property2java/cli/ArgumentConfiguration.java index 88d5154..ef2d498 100644 --- a/src/main/java/de/kreth/property2java/cli/ArgumentConfiguration.java +++ b/src/main/java/de/kreth/property2java/cli/ArgumentConfiguration.java @@ -75,6 +75,13 @@ public class ArgumentConfiguration implements Configuration { String packageName; + boolean replaceUsages; + + /** + * Target Directory Path. + * @param target + * @return + */ public Builder setTarget(String target) { this.target = target; return this; @@ -85,11 +92,26 @@ public class ArgumentConfiguration implements Configuration { 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); } diff --git a/src/main/java/de/kreth/property2java/cli/CliConfig.java b/src/main/java/de/kreth/property2java/cli/CliConfig.java index 6906fc5..889425d 100644 --- a/src/main/java/de/kreth/property2java/cli/CliConfig.java +++ b/src/main/java/de/kreth/property2java/cli/CliConfig.java @@ -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); } diff --git a/src/main/java/de/kreth/property2java/replace/Replacement.java b/src/main/java/de/kreth/property2java/replace/Replacement.java new file mode 100644 index 0000000..2b7ecea --- /dev/null +++ b/src/main/java/de/kreth/property2java/replace/Replacement.java @@ -0,0 +1,152 @@ +package de.kreth.property2java.replace; + +import java.util.Arrays; +import java.util.List; + +public class Replacement { + + private static final List 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); + } + +} diff --git a/src/main/java/de/kreth/property2java/replace/Replacements.java b/src/main/java/de/kreth/property2java/replace/Replacements.java new file mode 100644 index 0000000..8d54145 --- /dev/null +++ b/src/main/java/de/kreth/property2java/replace/Replacements.java @@ -0,0 +1,14 @@ +package de.kreth.property2java.replace; + +import java.util.ArrayList; +import java.util.List; + +public class Replacements { + + private final List replacementList = new ArrayList<>(); + + public boolean add(Replacement e) { + return replacementList.add(e); + } + +} diff --git a/src/test/java/de/kreth/property2java/ReplacementTest.java b/src/test/java/de/kreth/property2java/ReplacementTest.java new file mode 100644 index 0000000..339f62a --- /dev/null +++ b/src/test/java/de/kreth/property2java/ReplacementTest.java @@ -0,0 +1,168 @@ +package de.kreth.property2java; + +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 captionInvoiceItemAdd; + + private Replacement captionUserDetails; + + @BeforeEach + void initTestItem() { + captionArticles = new Replacement("de.kreth.clubinvoice", "Application_Properties", "CAPTION_ARTICLES", + "CAPTION1_ARTICLES"); + captionInvoiceItemAdd = new Replacement("de.kreth.clubinvoice", "Application_Properties", + "CAPTION_INVOICEITEM_ADD", + "CAPTION1_INVOICEITEM_ADD"); + 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 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 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 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 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" + + ""; + } +}