diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValuePropertyReferencesProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValuePropertyReferencesProvider.java index ed0acbfe1..b110b8c12 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValuePropertyReferencesProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValuePropertyReferencesProvider.java @@ -116,10 +116,8 @@ public class ValuePropertyReferencesProvider implements ReferenceProvider { return null; } - public List findReferencesFromPropertyFiles( - Collection workspaceRoots, - String propertyKey - ) { + public List findReferencesFromPropertyFiles(Collection workspaceRoots, String propertyKey) { + for (WorkspaceFolder workspaceFolder : workspaceRoots) { try { Path workspaceRoot = Paths.get(new URI(workspaceFolder.getUri())); @@ -141,7 +139,7 @@ public class ValuePropertyReferencesProvider implements ReferenceProvider { return null; } - static boolean isPropertiesFile(Path path) { + public static boolean isPropertiesFile(Path path) { String fileName = path.getFileName().toString(); if (fileName.endsWith(BootPropertiesLanguageServerComponents.PROPERTIES)) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/AdHocSpringPropertyIndexProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/AdHocSpringPropertyIndexProvider.java index 76b1e38f4..cba5922c1 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/AdHocSpringPropertyIndexProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/AdHocSpringPropertyIndexProvider.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018, 2020 Pivotal, Inc. + * Copyright (c) 2018, 2024 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -15,14 +15,19 @@ import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.HashSet; import java.util.Properties; import java.util.Set; import java.util.concurrent.ExecutionException; +import java.util.stream.Stream; import org.eclipse.lsp4j.TextDocumentIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.ide.vscode.boot.java.value.ValuePropertyReferencesProvider; +import org.springframework.ide.vscode.boot.properties.BootPropertiesLanguageServerComponents; import org.springframework.ide.vscode.commons.java.IClasspathUtil; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; @@ -64,8 +69,9 @@ public class AdHocSpringPropertyIndexProvider implements ProjectBasedPropertyInd } if (fileObserver!=null) { fileObserver.onAnyChange(ImmutableList.of( - "**/application.properties", - "**/application.yml" + "**/application*.properties", + "**/application*.yaml", + "**/application*.yml" ), changed -> { log.debug("Files changed: {}", (Object[])changed); @@ -83,7 +89,7 @@ public class AdHocSpringPropertyIndexProvider implements ProjectBasedPropertyInd }); } - if (documents!=null) { + if (documents != null) { documents.onDidSave(saveEvent -> { LanguageId language = saveEvent.getDocument().getLanguageId(); if (language.equals(LanguageId.BOOT_PROPERTIES) || language.equals(LanguageId.BOOT_PROPERTIES_YAML)) { @@ -95,13 +101,12 @@ public class AdHocSpringPropertyIndexProvider implements ProjectBasedPropertyInd @Override public FuzzyMap getIndex(IJavaProject jp) { - if (jp!=null) { + if (jp != null) { try { return indexes.get(jp, () -> { SimplePropertyIndex index = new SimplePropertyIndex(); IClasspathUtil.getSourceFolders(jp.getClasspath()).forEach(sourceFolder -> { - processFile(this::parseProperties, new File(sourceFolder, "application.properties"), index); - processFile(this::parseYaml, new File(sourceFolder, "application.yml"), index); + getIndexFromSourceFolder(sourceFolder, index); }); return index; }); @@ -112,9 +117,28 @@ public class AdHocSpringPropertyIndexProvider implements ProjectBasedPropertyInd return SpringPropertyIndex.EMPTY_INDEX.getProperties(); } + private void getIndexFromSourceFolder(File sourceFolder, SimplePropertyIndex index) { + try (Stream walk = Files.walk(sourceFolder.toPath())) { + walk + .filter(path -> ValuePropertyReferencesProvider.isPropertiesFile(path)) + .filter(path -> path.toFile().isFile()) + .forEach(path -> { + String fileName = path.getFileName().toString(); + if (fileName.endsWith(BootPropertiesLanguageServerComponents.PROPERTIES)) { + processFile(this::parseProperties, path.toFile(), index); + } + else if (fileName.endsWith(".yml") || fileName.endsWith(".yaml")) { + processFile(this::parseYaml, path.toFile(), index); + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + private void processFile(Function parserFunction, File file, SimplePropertyIndex index) { Properties props = parserFunction.apply(file); - if (props!=null) { + if (props != null) { for (Object p : props.keySet()) { if (p instanceof String) { String filename = file.getName(); @@ -157,22 +181,25 @@ public class AdHocSpringPropertyIndexProvider implements ProjectBasedPropertyInd private void flattenProperties(String prefix, Node node, Properties props) { switch (node.getNodeId()) { + case mapping: if (!prefix.isEmpty()) { - prefix = prefix +"."; + prefix = prefix + "."; } MappingNode mapping = (MappingNode)node; for (NodeTuple tup : mapping.getValue()) { String key = NodeUtil.asScalar(tup.getKeyNode()); - if (key!=null) { - flattenProperties(prefix+key, tup.getValueNode(), props); + if (key != null) { + flattenProperties(prefix + key, tup.getValueNode(), props); } } break; + case scalar: //End of the line. props.put(prefix, NodeUtil.asScalar(node)); break; + default: if (!prefix.isEmpty()) { props.put(prefix, ""); diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/AdHocSpringPropertyIndexProviderTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/AdHocSpringPropertyIndexProviderTest.java index 4a1f317ac..84e144b31 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/AdHocSpringPropertyIndexProviderTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/value/test/AdHocSpringPropertyIndexProviderTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2024 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -10,15 +10,14 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.value.test; +import static org.junit.jupiter.api.Assertions.assertEquals; + import java.io.File; import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; import org.springframework.ide.vscode.boot.java.value.test.MockProjects.MockProject; import org.springframework.ide.vscode.boot.metadata.AdHocSpringPropertyIndexProvider; import org.springframework.ide.vscode.boot.metadata.PropertyInfo; -import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService; import org.springframework.ide.vscode.commons.languageserver.util.TextDocumentSaveChange; import org.springframework.ide.vscode.commons.util.FuzzyMap; import org.springframework.ide.vscode.commons.util.text.LanguageId; @@ -45,6 +44,38 @@ public class AdHocSpringPropertyIndexProviderTest { ); } + @Test + void parsePropertiesInSubFolder() throws Exception { + MockProject project = projects.create("test-project"); + project.ensureFile("src/main/resources/test/application.properties", + "some-adhoc-foo=somefoo\n" + + "some-adhoc-bar=somebar\n" + ); + AdHocSpringPropertyIndexProvider indexer = new AdHocSpringPropertyIndexProvider(projects.finder, projects.observer, null, documents); + + assertProperties(indexer.getIndex(project), + //alphabetic order + "some-adhoc-bar", + "some-adhoc-foo" + ); + } + + @Test + void parsePropertiesFromPropertyFileVariants() throws Exception { + MockProject project = projects.create("test-project"); + project.ensureFile("src/main/resources/application-dev.properties", + "dev-some-adhoc-foo=somefoo\n" + + "dev-some-adhoc-bar=somebar\n" + ); + AdHocSpringPropertyIndexProvider indexer = new AdHocSpringPropertyIndexProvider(projects.finder, projects.observer, null, documents); + + assertProperties(indexer.getIndex(project), + //alphabetic order + "dev-some-adhoc-bar", + "dev-some-adhoc-foo" + ); + } + @Test void parseYamlWithList() throws Exception { //Note: the LoggerNameProvider implementation relies on this behavior @@ -64,7 +95,7 @@ public class AdHocSpringPropertyIndexProviderTest { } @Test - void parseYaml() throws Exception { + void parseYml() throws Exception { MockProject project = projects.create("test-project"); project.ensureFile("src/main/resources/application.yml", "from-yaml:\n" + @@ -81,6 +112,24 @@ public class AdHocSpringPropertyIndexProviderTest { ); } + @Test + void parseYaml() throws Exception { + MockProject project = projects.create("test-project"); + project.ensureFile("src/main/resources/application.yaml", + "from-yaml:\n" + + " adhoc:\n" + + " foo: somefoo\n" + + " bar: somebar\n" + ); + AdHocSpringPropertyIndexProvider indexer = new AdHocSpringPropertyIndexProvider(projects.finder, projects.observer, null, documents); + + assertProperties(indexer.getIndex(project), + //alphabetic order + "from-yaml.adhoc.bar", + "from-yaml.adhoc.foo" + ); + } + @Test void respondsToClasspathChanges() throws Exception { MockProject project = projects.create("test-project");