diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/PropertyNameCompletionProposalProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/PropertyNameCompletionProposalProvider.java index 7308ab19c..40e8303fa 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/PropertyNameCompletionProposalProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/PropertyNameCompletionProposalProvider.java @@ -25,7 +25,6 @@ import org.eclipse.lsp4xml.dom.parser.Scanner; import org.springframework.ide.vscode.boot.xml.XMLCompletionProvider; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.java.IMethod; -import org.springframework.ide.vscode.commons.java.IType; import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; @@ -33,6 +32,8 @@ import org.springframework.ide.vscode.commons.util.Renderable; import org.springframework.ide.vscode.commons.util.StringUtil; import org.springframework.ide.vscode.commons.util.text.TextDocument; +import reactor.core.publisher.Flux; + /** * @author Martin Lippert */ @@ -63,16 +64,12 @@ public class PropertyNameCompletionProposalProvider implements XMLCompletionProv String beanClass = identifyBeanClass(node); if (beanClass != null && beanClass.length() > 0) { - IType beanType = project.getIndex().findType(beanClass); - - if (beanType != null) { - final String searchPrefix = prefix; - return beanType.getMethods() - .filter(method -> isPropertyWriteMethod(method)) - .filter(method -> getPropertyName(method).startsWith(searchPrefix)) - .map(method -> createProposal(method, doc, offset, tokenOffset, tokenEnd)) - .collect(Collectors.toList()); - } + final String searchPrefix = prefix; + propertyNameCandidateMethods(project, beanClass) + .filter(method -> getPropertyName(method).startsWith(searchPrefix)) + .map(method -> createProposal(method, doc, offset, tokenOffset, tokenEnd)) + .toStream() + .collect(Collectors.toList()); } }; @@ -110,7 +107,7 @@ public class PropertyNameCompletionProposalProvider implements XMLCompletionProv return new TypeCompletionProposal(label, kind, edits, label, renderable, 1d); } - private boolean isPropertyWriteMethod(IMethod method) { + private static boolean isPropertyWriteMethod(IMethod method) { return method != null && method.getElementName().startsWith("set") && method.getElementName().length() > 3; @@ -126,5 +123,11 @@ public class PropertyNameCompletionProposalProvider implements XMLCompletionProv } return methodName; } + + public static Flux propertyNameCandidateMethods(IJavaProject project, String beanClassFqName) { + return project.getIndex().allSuperTypesOf(beanClassFqName, true) + .flatMap(type -> Flux.fromStream(type.getMethods())) + .filter(PropertyNameCompletionProposalProvider::isPropertyWriteMethod); + } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/hyperlinks/PropertyNameHyperlinkProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/hyperlinks/PropertyNameHyperlinkProvider.java index 92ab27ead..7e0dd9b09 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/hyperlinks/PropertyNameHyperlinkProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/hyperlinks/PropertyNameHyperlinkProvider.java @@ -18,7 +18,6 @@ import org.eclipse.lsp4xml.dom.DOMNode; import org.springframework.ide.vscode.boot.java.links.JavaElementLocationProvider; import org.springframework.ide.vscode.boot.xml.completions.PropertyNameCompletionProposalProvider; import org.springframework.ide.vscode.commons.java.IJavaProject; -import org.springframework.ide.vscode.commons.java.IType; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.util.text.TextDocument; @@ -45,15 +44,10 @@ public class PropertyNameHyperlinkProvider implements XMLHyperlinkProvider { IJavaProject project = foundProject.get(); String beanClass = PropertyNameCompletionProposalProvider.identifyBeanClass(node); if (beanClass != null && beanClass.length() > 0) { - IType beanType = project.getIndex().findType(beanClass); - - if (beanType != null) { - return beanType.getMethods() - .filter(method -> propertyName.equals(PropertyNameCompletionProposalProvider.getPropertyName(method))) - .map(method -> locationProvider.findLocation(project, method)) - .findFirst() - .orElse(null); - } + return PropertyNameCompletionProposalProvider.propertyNameCandidateMethods(project, beanClass) + .filter(method -> propertyName.equals(PropertyNameCompletionProposalProvider.getPropertyName(method))) + .map(method -> locationProvider.findLocation(project, method)) + .blockFirst(); } } return null; diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/XmlBeansHyperlinkTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/XmlBeansHyperlinkTest.java index 310081d88..e58e789d7 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/XmlBeansHyperlinkTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/XmlBeansHyperlinkTest.java @@ -116,6 +116,24 @@ public class XmlBeansHyperlinkTest { definitionLinkAsserts.assertLinkTargets(editor, "age", project, DefinitionLinkAsserts.method("u.t.r.TestBean", "setAge", "int")); } + @Test + public void testBeanPropertyNameFromSuperClassHyperlink() throws Exception { + Path xmlFilePath = Paths.get(project.getLocationUri()).resolve("beans.xml"); + Editor editor = harness.newEditor(LanguageId.XML, + "\n" + + "\n" + + + "\n" + + "\n" + + "\n", + UriUtil.toUri(xmlFilePath.toFile()).toString() + ); + definitionLinkAsserts.assertLinkTargets(editor, "message", project, DefinitionLinkAsserts.method("u.t.r.SuperTestBean", "setMessage", "java.lang.String")); + } + @Test public void testBeanRefHyperlink() throws Exception { Path xmlFilePath = Paths.get(project.getLocationUri()).resolve("beans.xml"); diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-xml-hyperlinks/src/main/java/u/t/r/TestBean.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-xml-hyperlinks/src/main/java/u/t/r/TestBean.java index 23f3d04cf..8746b7d9b 100644 --- a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-xml-hyperlinks/src/main/java/u/t/r/TestBean.java +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-xml-hyperlinks/src/main/java/u/t/r/TestBean.java @@ -1,6 +1,6 @@ package u.t.r; -public class TestBean { +public class TestBean extends SuperTestBean { private int age = 5;