diff --git a/vscode-extensions/vscode-boot-java/pom.xml b/vscode-extensions/vscode-boot-java/pom.xml index de3f34aba..e3aa1fb4a 100644 --- a/vscode-extensions/vscode-boot-java/pom.xml +++ b/vscode-extensions/vscode-boot-java/pom.xml @@ -48,6 +48,11 @@ commons-language-server ${project.version} + + org.springframework.ide.vscode + java-properties + ${project.version} + diff --git a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/references/ValuePropertyReferencesProvider.java b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/references/ValuePropertyReferencesProvider.java index cd1fe58bd..1457e685d 100644 --- a/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/references/ValuePropertyReferencesProvider.java +++ b/vscode-extensions/vscode-boot-java/src/main/java/org/springframework/ide/vscode/boot/java/references/ValuePropertyReferencesProvider.java @@ -10,8 +10,11 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.references; +import java.io.File; +import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -19,14 +22,22 @@ import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.commons.io.FileUtils; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.Annotation; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.MemberValuePair; import org.eclipse.jdt.core.dom.StringLiteral; import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; import org.springframework.ide.vscode.commons.languageserver.util.SimpleLanguageServer; +import org.springframework.ide.vscode.commons.util.BadLocationException; import org.springframework.ide.vscode.commons.util.text.TextDocument; +import org.springframework.ide.vscode.java.properties.antlr.parser.AntlrParser; +import org.springframework.ide.vscode.java.properties.parser.ParseResults; +import org.springframework.ide.vscode.java.properties.parser.Parser; +import org.springframework.ide.vscode.java.properties.parser.PropertiesAst.KeyValuePair; /** * @author Martin Lippert @@ -89,7 +100,7 @@ public class ValuePropertyReferencesProvider { List locations = walk .filter(path -> isPropertiesFile(path)) .filter(path -> path.toFile().isFile()) - .map(path -> findReferences(path)) + .map(path -> findReferences(path, propertyKey)) .flatMap(Collection::stream) .collect(Collectors.toList()); @@ -103,13 +114,20 @@ public class ValuePropertyReferencesProvider { } private boolean isPropertiesFile(Path path) { - return path.toString().endsWith("application.properties"); + Path fileName = path.getFileName(); + + if (fileName.toString().endsWith(".properties") || path.toString().endsWith(".yml")) { + return fileName.toString().contains("application"); + } + else { + return false; + } } - private List findReferences(Path path) { + private List findReferences(Path path, String propertyKey) { String filePath = path.toString(); if (filePath.endsWith(".properties")) { - // do the real work + return findReferencesInPropertiesFile(filePath, propertyKey); } else if (filePath.endsWith(".yml")) { // do the real work @@ -117,6 +135,55 @@ public class ValuePropertyReferencesProvider { return new ArrayList(); } + private List findReferencesInPropertiesFile(String filePath, String propertyKey) { + List foundLocations = new ArrayList<>(); + + try { + String fileContent = FileUtils.readFileToString(new File(filePath)); + + Parser parser = new AntlrParser(); + ParseResults parseResults = parser.parse(fileContent); + + if (parseResults != null && parseResults.ast != null) { + parseResults.ast.getNodes(KeyValuePair.class).forEach(pair -> { + if (pair.getKey() != null && pair.getKey().decode().equals(propertyKey)) { + URI docURI = Paths.get(filePath).toUri(); + TextDocument doc = new TextDocument(docURI.toString(), null); + doc.setText(fileContent); + + try { + int line = doc.getLineOfOffset(pair.getKey().getOffset()); + int startInLine = pair.getKey().getOffset() - doc.getLineOffset(line); + int endInLine = startInLine + (pair.getKey().getLength()); + + Position start = new Position(); + start.setLine(line); + start.setCharacter(startInLine); + + Position end = new Position(); + end.setLine(line); + end.setCharacter(endInLine); + + Range range = new Range(); + range.setStart(start); + range.setEnd(end); + + Location location = new Location(docURI.toString(), range); + foundLocations.add(location); + + } catch (BadLocationException e) { + e.printStackTrace(); + } + } + }); + } + + } catch (Exception e) { + e.printStackTrace(); + } + return foundLocations; + } + public LocalRange getPropertyRange(String value, int offset) { int start = -1; int end = -1; diff --git a/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/references/test/PropertyReferenceFinderTest.java b/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/references/test/PropertyReferenceFinderTest.java index a507b2fc8..5df4c925b 100644 --- a/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/references/test/PropertyReferenceFinderTest.java +++ b/vscode-extensions/vscode-boot-java/src/test/java/org/springframework/ide/vscode/boot/java/references/test/PropertyReferenceFinderTest.java @@ -10,8 +10,10 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.references.test; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import java.net.URI; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; @@ -28,13 +30,79 @@ import org.springframework.ide.vscode.project.harness.ProjectsHarness; public class PropertyReferenceFinderTest { @Test - public void testFindReferences() throws Exception { + public void testFindReferenceAtBeginning() throws Exception { ValuePropertyReferencesProvider provider = new ValuePropertyReferencesProvider(null); Path root = Paths.get(ProjectsHarness.class.getResource("/test-property-files/simple-case/").toURI()); - CompletableFuture> locations = provider.findReferencesFromPropertyFiles(root, "test.property"); + CompletableFuture> resultFuture = provider.findReferencesFromPropertyFiles(root, "test.property"); - assertNotNull(locations); + assertNotNull(resultFuture); + List locations = resultFuture.get(); + assertEquals(1, locations.size()); + Location location = locations.get(0); + + URI docURI = Paths.get(root.toString(), "application.properties").toUri(); + assertEquals(docURI.toString(), location.getUri()); + assertEquals(0, location.getRange().getStart().getLine()); + assertEquals(0, location.getRange().getStart().getCharacter()); + assertEquals(0, location.getRange().getEnd().getLine()); + assertEquals(13, location.getRange().getEnd().getCharacter()); + } + + @Test + public void testFindReferenceWithinTheDocument() throws Exception { + ValuePropertyReferencesProvider provider = new ValuePropertyReferencesProvider(null); + + Path root = Paths.get(ProjectsHarness.class.getResource("/test-property-files/simple-case/").toURI()); + CompletableFuture> resultFuture = provider.findReferencesFromPropertyFiles(root, "server.port"); + + assertNotNull(resultFuture); + List locations = resultFuture.get(); + assertEquals(1, locations.size()); + Location location = locations.get(0); + + URI docURI = Paths.get(root.toString(), "application.properties").toUri(); + assertEquals(docURI.toString(), location.getUri()); + assertEquals(2, location.getRange().getStart().getLine()); + assertEquals(0, location.getRange().getStart().getCharacter()); + assertEquals(2, location.getRange().getEnd().getLine()); + assertEquals(11, location.getRange().getEnd().getCharacter()); + } + + @Test + public void testFindReferenceWithinMultipleFiles() throws Exception { + ValuePropertyReferencesProvider provider = new ValuePropertyReferencesProvider(null); + + Path root = Paths.get(ProjectsHarness.class.getResource("/test-property-files/multiple-files/").toURI()); + CompletableFuture> resultFuture = provider.findReferencesFromPropertyFiles(root, "appl1.prop"); + + assertNotNull(resultFuture); + List locations = resultFuture.get(); + assertEquals(3, locations.size()); + + Location location = locations.get(0); + URI docURI = Paths.get(root.toString(), "application-dev.properties").toUri(); + assertEquals(docURI.toString(), location.getUri()); + assertEquals(1, location.getRange().getStart().getLine()); + assertEquals(0, location.getRange().getStart().getCharacter()); + assertEquals(1, location.getRange().getEnd().getLine()); + assertEquals(10, location.getRange().getEnd().getCharacter()); + + location = locations.get(1); + docURI = Paths.get(root.toString(), "application.properties").toUri(); + assertEquals(docURI.toString(), location.getUri()); + assertEquals(1, location.getRange().getStart().getLine()); + assertEquals(0, location.getRange().getStart().getCharacter()); + assertEquals(1, location.getRange().getEnd().getLine()); + assertEquals(10, location.getRange().getEnd().getCharacter()); + + location = locations.get(2); + docURI = Paths.get(root.toString(), "prod-application.properties").toUri(); + assertEquals(docURI.toString(), location.getUri()); + assertEquals(1, location.getRange().getStart().getLine()); + assertEquals(0, location.getRange().getStart().getCharacter()); + assertEquals(1, location.getRange().getEnd().getLine()); + assertEquals(10, location.getRange().getEnd().getCharacter()); } } diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/multiple-files/application-dev.properties b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/multiple-files/application-dev.properties new file mode 100644 index 000000000..9937ca7e6 --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/multiple-files/application-dev.properties @@ -0,0 +1,2 @@ +something.else=true +appl1.prop=test diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/multiple-files/application.non-properties b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/multiple-files/application.non-properties new file mode 100644 index 000000000..9937ca7e6 --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/multiple-files/application.non-properties @@ -0,0 +1,2 @@ +something.else=true +appl1.prop=test diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/multiple-files/application.properties b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/multiple-files/application.properties new file mode 100644 index 000000000..9937ca7e6 --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/multiple-files/application.properties @@ -0,0 +1,2 @@ +something.else=true +appl1.prop=test diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/multiple-files/non-app-props.properties b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/multiple-files/non-app-props.properties new file mode 100644 index 000000000..9937ca7e6 --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/multiple-files/non-app-props.properties @@ -0,0 +1,2 @@ +something.else=true +appl1.prop=test diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/multiple-files/prod-application.properties b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/multiple-files/prod-application.properties new file mode 100644 index 000000000..9937ca7e6 --- /dev/null +++ b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/multiple-files/prod-application.properties @@ -0,0 +1,2 @@ +something.else=true +appl1.prop=test diff --git a/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/simple-case/application.properties b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/simple-case/application.properties index 72b67a7be..1c9ede71f 100644 --- a/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/simple-case/application.properties +++ b/vscode-extensions/vscode-boot-java/src/test/resources/test-property-files/simple-case/application.properties @@ -1 +1,5 @@ test.property=Hey there + +server.port=8080 + +another.property=moretests diff --git a/vscode-extensions/vscode-boot-properties/src/test/resources/test-projects/enums-boot-1.3.2-app/src/main/java/demo/DemoEnumApplication.java b/vscode-extensions/vscode-boot-properties/src/test/resources/test-projects/enums-boot-1.3.2-app/src/main/java/demo/DemoEnumApplication.java index b484e936f..bd7ecf7de 100644 --- a/vscode-extensions/vscode-boot-properties/src/test/resources/test-projects/enums-boot-1.3.2-app/src/main/java/demo/DemoEnumApplication.java +++ b/vscode-extensions/vscode-boot-properties/src/test/resources/test-projects/enums-boot-1.3.2-app/src/main/java/demo/DemoEnumApplication.java @@ -3,6 +3,7 @@ package demo; import java.util.Map.Entry; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -18,6 +19,7 @@ public class DemoEnumApplication implements CommandLineRunner { @Autowired + @Value("${server.port}") FooProperties foo; @Override