diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/QualifierReferencesProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/QualifierReferencesProvider.java index 79f5e21d7..41a7403d2 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/QualifierReferencesProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/QualifierReferencesProvider.java @@ -16,9 +16,9 @@ import java.util.stream.Stream; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.Annotation; +import org.eclipse.jdt.core.dom.Expression; 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.jsonrpc.CancelChecker; import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; @@ -46,18 +46,18 @@ public class QualifierReferencesProvider implements ReferenceProvider { cancelToken.checkCanceled(); try { + while (node != null && !(node.getParent() instanceof Annotation) && !(node.getParent() instanceof MemberValuePair)) { + node = node.getParent(); + } + // case: @Value("prefix<*>") - if (node instanceof StringLiteral && node.getParent() instanceof Annotation) { - if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) { - return provideReferences(project, ASTUtils.getLiteralValue((StringLiteral) node)); - } + if (node instanceof Expression expression && node.getParent() instanceof Annotation) { + return provideReferences(project, ASTUtils.getExpressionValueAsString(expression, v -> {})); } // case: @Value(value="prefix<*>") - else if (node instanceof StringLiteral && node.getParent() instanceof MemberValuePair + else if (node instanceof Expression expression && node.getParent() instanceof MemberValuePair && "value".equals(((MemberValuePair)node.getParent()).getName().toString())) { - if (node.toString().startsWith("\"") && node.toString().endsWith("\"")) { - return provideReferences(project, ASTUtils.getLiteralValue((StringLiteral) node)); - } + return provideReferences(project, ASTUtils.getExpressionValueAsString(expression, v -> {})); } } catch (Exception e) { diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/QualifierReferencesProviderTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/QualifierReferencesProviderTest.java index 647c8f7c9..865a6dfef 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/QualifierReferencesProviderTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/QualifierReferencesProviderTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2024 Broadcom + * Copyright (c) 2024, 2025 Broadcom * 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 @@ -99,6 +99,36 @@ public class QualifierReferencesProviderTest { assertEquals(expectedLocation, foundLocation); } + @Test + public void testQualifierRefersToBeanFromNameAttribute() throws Exception { + String tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString(); + + Editor editor = harness.newEditor(LanguageId.JAVA, """ + package org.test; + + import org.springframework.stereotype.Component; + import org.springframework.beans.factory.annotation.Qualifier; + + @Component + @Qualifier(value = "be<*>an1") + public class TestDependsOnClass { + }""", tempJavaDocUri); + + String expectedDefinitionUri = directory.toPath().resolve("src/main/java/org/test/MainClass.java").toUri().toString(); + + Bean[] beans = springIndex.getBeansWithName(project.getElementName(), "bean1"); + assertEquals(1, beans.length); + + Location expectedLocation = new Location(expectedDefinitionUri, + beans[0].getLocation().getRange()); + + List references = editor.getReferences(); + assertEquals(1, references.size()); + + Location foundLocation = references.get(0); + assertEquals(expectedLocation, foundLocation); + } + @Test public void testQualifierRefersToOtherQualifier() throws Exception { String tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString(); @@ -126,6 +156,63 @@ public class QualifierReferencesProviderTest { assertEquals(expectedLocation, foundLocation); } + @Test + public void testQualifierWithConcatenatedStrings() throws Exception { + String tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString(); + + Editor editor = harness.newEditor(LanguageId.JAVA, """ + package org.test; + + import org.springframework.stereotype.Component; + import org.springframework.beans.factory.annotation.Qualifier; + + @Component + @Qualifier("qual" + "if<*>ier") + public class TestDependsOnClass { + }""", tempJavaDocUri); + + String expectedDefinitionUri = directory.toPath().resolve("src/main/java/org/test/injections/ConfigurationWithInjectionsAndAnnotations.java").toUri().toString(); + + Location expectedLocation = new Location(expectedDefinitionUri, + new Range(new Position(12, 11), new Position(12, 22))); + + List references = editor.getReferences(); + assertEquals(1, references.size()); + + Location foundLocation = references.get(0); + assertEquals(expectedLocation, foundLocation); + } + + @Test + public void testQualifierRefersToBeanFromNameAttributeWithConcatenatedStrings() throws Exception { + String tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString(); + + Editor editor = harness.newEditor(LanguageId.JAVA, """ + package org.test; + + import org.springframework.stereotype.Component; + import org.springframework.beans.factory.annotation.Qualifier; + + @Component + @Qualifier(value = "be" + "<*>an1") + public class TestDependsOnClass { + }""", tempJavaDocUri); + + String expectedDefinitionUri = directory.toPath().resolve("src/main/java/org/test/MainClass.java").toUri().toString(); + + Bean[] beans = springIndex.getBeansWithName(project.getElementName(), "bean1"); + assertEquals(1, beans.length); + + Location expectedLocation = new Location(expectedDefinitionUri, + beans[0].getLocation().getRange()); + + List references = editor.getReferences(); + assertEquals(1, references.size()); + + Location foundLocation = references.get(0); + assertEquals(expectedLocation, foundLocation); + } + @Test public void testQualifierRefersToNothing() throws Exception { String tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString();