Skip to content

Commit 54d7ee4

Browse files
committed
GH-1381: support Go To Definition for ConditionalOnMissingBean, focus in name attribute, and support value arrays
1 parent 1d02a04 commit 54d7ee4

File tree

2 files changed

+206
-10
lines changed

2 files changed

+206
-10
lines changed

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ConditionalOnBeanDefinitionProvider.java

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import org.eclipse.jdt.core.dom.Annotation;
2020
import org.eclipse.jdt.core.dom.CompilationUnit;
2121
import org.eclipse.jdt.core.dom.IAnnotationBinding;
22+
import org.eclipse.jdt.core.dom.ITypeBinding;
23+
import org.eclipse.jdt.core.dom.MemberValuePair;
2224
import org.eclipse.jdt.core.dom.StringLiteral;
2325
import org.eclipse.lsp4j.LocationLink;
2426
import org.eclipse.lsp4j.TextDocumentIdentifier;
@@ -51,19 +53,62 @@ public List<LocationLink> getDefinitions(CancelChecker cancelToken, IJavaProject
5153
if (parent != null && parent instanceof Annotation) {
5254
Annotation a = (Annotation) parent;
5355
IAnnotationBinding binding = a.resolveAnnotationBinding();
54-
if (binding != null && binding.getAnnotationType() != null && Annotations.CONDITIONAL_ON_BEAN.equals(binding.getAnnotationType().getQualifiedName())) {
55-
String beanName = valueNode.getLiteralValue();
5656

57-
if (beanName != null && beanName.length() > 0) {
58-
return findBeansWithName(project, beanName);
59-
}
57+
if (binding != null) {
58+
ITypeBinding annotationType = binding.getAnnotationType();
59+
if (annotationType != null) {
60+
String annotationTypeQualifiedName = annotationType.getQualifiedName();
61+
62+
if (Annotations.CONDITIONAL_ON_BEAN.equals(annotationTypeQualifiedName)
63+
|| Annotations.CONDITIONAL_ON_MISSING_BEAN.equals(annotationTypeQualifiedName)) {
64+
65+
return getDefinitions(project, valueNode);
66+
}
67+
}
6068
}
6169
}
6270
}
6371
return Collections.emptyList();
6472
}
6573

66-
private List<LocationLink> findBeansWithName(IJavaProject project, String beanName) {
74+
private List<LocationLink> getDefinitions(IJavaProject project, StringLiteral valueNode) {
75+
String value = valueNode.getLiteralValue();
76+
77+
if (value != null && value.length() > 0) {
78+
return getDefinitionsForValue(project, valueNode, value);
79+
}
80+
else {
81+
return Collections.emptyList();
82+
}
83+
}
84+
85+
private List<LocationLink> getDefinitionsForValue(IJavaProject project, StringLiteral valueNode, String value) {
86+
ASTNode parent = valueNode.getParent();
87+
if (parent != null && !(parent instanceof MemberValuePair)) {
88+
parent = parent.getParent();
89+
}
90+
91+
if (parent != null && parent instanceof MemberValuePair) {
92+
MemberValuePair pair = (MemberValuePair) parent;
93+
String name = pair.getName().toString();
94+
95+
if ("name".equals(name)) {
96+
return findBeansWithName(project, value);
97+
}
98+
else if ("type".equals(name) ||"ignoredType".equals(name)) {
99+
return findBeanTypesWithName(project, value);
100+
}
101+
}
102+
103+
return Collections.emptyList();
104+
}
105+
106+
private List<LocationLink> findBeanTypesWithName(IJavaProject project, String value) {
107+
// TODO
108+
return Collections.emptyList();
109+
}
110+
111+
private List<LocationLink> findBeansWithName(IJavaProject project, String beanName) {
67112
Bean[] beans = this.springIndex.getBeansWithName(project.getElementName(), beanName);
68113

69114
return Arrays.stream(beans)

headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/conditionalonbean/test/ConditionalOnBeanDefinitionProviderTest.java

Lines changed: 155 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,24 +79,109 @@ public void testConditionalOnBeanWithNameRefersToBeanDefinitionLink() throws Exc
7979
8080
@Configuration
8181
public class TestConditionalOnBeanCompletion {
82-
@ConditionalOnBean(name="bean1")
82+
@ConditionalOnBean(name = "bean1")
8383
@Bean
8484
public void method() {
8585
}
8686
}""", tempJavaDocUri);
8787

88-
String expectedDefinitionUri = directory.toPath().resolve("src/main/java/org/test/MainClass.java").toUri().toString();
88+
Bean[] beans = springIndex.getBeansWithName(project.getElementName(), "bean1");
89+
assertEquals(1, beans.length);
90+
91+
LocationLink expectedLocation = new LocationLink(beans[0].getLocation().getUri(),
92+
beans[0].getLocation().getRange(), beans[0].getLocation().getRange(),
93+
null);
94+
95+
editor.assertLinkTargets("bean1", List.of(expectedLocation));
96+
}
97+
98+
@Test
99+
public void testConditionalOnMissingBeanWithNameRefersToBeanDefinitionLink() throws Exception {
100+
String tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString();
101+
102+
Editor editor = harness.newEditor(LanguageId.JAVA, """
103+
package org.test;
104+
105+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
106+
import org.springframework.context.annotation.Bean;
107+
import org.springframework.context.annotation.Configuration;
108+
109+
@Configuration
110+
public class TestConditionalOnBeanCompletion {
111+
@ConditionalOnMissingBean(name = "bean1")
112+
@Bean
113+
public void method() {
114+
}
115+
}""", tempJavaDocUri);
89116

90117
Bean[] beans = springIndex.getBeansWithName(project.getElementName(), "bean1");
91118
assertEquals(1, beans.length);
92119

93-
LocationLink expectedLocation = new LocationLink(expectedDefinitionUri,
120+
LocationLink expectedLocation = new LocationLink(beans[0].getLocation().getUri(),
94121
beans[0].getLocation().getRange(), beans[0].getLocation().getRange(),
95122
null);
96123

97124
editor.assertLinkTargets("bean1", List.of(expectedLocation));
98125
}
99126

127+
@Test
128+
public void testConditionalOnBeanWithNameArrayRefersToBeanDefinitionLink() throws Exception {
129+
String tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString();
130+
131+
Editor editor = harness.newEditor(LanguageId.JAVA, """
132+
package org.test;
133+
134+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
135+
import org.springframework.context.annotation.Bean;
136+
import org.springframework.context.annotation.Configuration;
137+
138+
@Configuration
139+
public class TestConditionalOnBeanCompletion {
140+
@ConditionalOnBean(name = {"bean1", "bean2"})
141+
@Bean
142+
public void method() {
143+
}
144+
}""", tempJavaDocUri);
145+
146+
Bean[] beans = springIndex.getBeansWithName(project.getElementName(), "bean2");
147+
assertEquals(1, beans.length);
148+
149+
LocationLink expectedLocation = new LocationLink(beans[0].getLocation().getUri(),
150+
beans[0].getLocation().getRange(), beans[0].getLocation().getRange(),
151+
null);
152+
153+
editor.assertLinkTargets("bean2", List.of(expectedLocation));
154+
}
155+
156+
@Test
157+
public void testConditionalOnMissingBeanWithNameArrayRefersToBeanDefinitionLink() throws Exception {
158+
String tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString();
159+
160+
Editor editor = harness.newEditor(LanguageId.JAVA, """
161+
package org.test;
162+
163+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
164+
import org.springframework.context.annotation.Bean;
165+
import org.springframework.context.annotation.Configuration;
166+
167+
@Configuration
168+
public class TestConditionalOnBeanCompletion {
169+
@ConditionalOnMissingBean(name = {"bean1", "bean2"})
170+
@Bean
171+
public void method() {
172+
}
173+
}""", tempJavaDocUri);
174+
175+
Bean[] beans = springIndex.getBeansWithName(project.getElementName(), "bean2");
176+
assertEquals(1, beans.length);
177+
178+
LocationLink expectedLocation = new LocationLink(beans[0].getLocation().getUri(),
179+
beans[0].getLocation().getRange(), beans[0].getLocation().getRange(),
180+
null);
181+
182+
editor.assertLinkTargets("bean2", List.of(expectedLocation));
183+
}
184+
100185
@Test
101186
public void testConditionalOnBeanRefersToRandomBeanWithoutDefinitionLink() throws Exception {
102187
String tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString();
@@ -110,7 +195,29 @@ public void testConditionalOnBeanRefersToRandomBeanWithoutDefinitionLink() throw
110195
111196
@Configuration
112197
public class TestConditionalOnBeanCompletion {
113-
@ConditionalOnBean(name="bean5")
198+
@ConditionalOnBean(name = "bean5")
199+
@Bean
200+
public void method() {
201+
}
202+
}""", tempJavaDocUri);
203+
204+
editor.assertNoLinkTargets("bean5");
205+
}
206+
207+
@Test
208+
public void testConditionalOnMissingBeanRefersToRandomBeanWithoutDefinitionLink() throws Exception {
209+
String tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString();
210+
211+
Editor editor = harness.newEditor(LanguageId.JAVA, """
212+
package org.test;
213+
214+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
215+
import org.springframework.context.annotation.Bean;
216+
import org.springframework.context.annotation.Configuration;
217+
218+
@Configuration
219+
public class TestConditionalOnBeanCompletion {
220+
@ConditionalOnMissingBean(name = "bean5")
114221
@Bean
115222
public void method() {
116223
}
@@ -119,4 +226,48 @@ public void method() {
119226
editor.assertNoLinkTargets("bean5");
120227
}
121228

229+
@Test
230+
public void testConditionalOnBeanUsesTypeInsteadOfBeanNameSoNoDefinitionLink() throws Exception {
231+
String tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString();
232+
233+
Editor editor = harness.newEditor(LanguageId.JAVA, """
234+
package org.test;
235+
236+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
237+
import org.springframework.context.annotation.Bean;
238+
import org.springframework.context.annotation.Configuration;
239+
240+
@Configuration
241+
public class TestConditionalOnBeanCompletion {
242+
@ConditionalOnBean(type = "bean1")
243+
@Bean
244+
public void method() {
245+
}
246+
}""", tempJavaDocUri);
247+
248+
editor.assertNoLinkTargets("bean1");
249+
}
250+
251+
@Test
252+
public void testConditionalOnMissingBeanUsesTypeInsteadOfBeanNameSoNoDefinitionLink() throws Exception {
253+
String tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString();
254+
255+
Editor editor = harness.newEditor(LanguageId.JAVA, """
256+
package org.test;
257+
258+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
259+
import org.springframework.context.annotation.Bean;
260+
import org.springframework.context.annotation.Configuration;
261+
262+
@Configuration
263+
public class TestConditionalOnBeanCompletion {
264+
@ConditionalOnMissingBean(type = "bean1")
265+
@Bean
266+
public void method() {
267+
}
268+
}""", tempJavaDocUri);
269+
270+
editor.assertNoLinkTargets("bean1");
271+
}
272+
122273
}

0 commit comments

Comments
 (0)