Skip to content

Commit 133516b

Browse files
committed
GH-1041: removed feign-specific symbol addon information and rebased implementation on spring index
1 parent d30dea8 commit 133516b

File tree

6 files changed

+70
-147
lines changed

6 files changed

+70
-147
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.springframework.context.annotation.Bean;
1717
import org.springframework.context.annotation.Conditional;
1818
import org.springframework.context.annotation.Configuration;
19+
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
1920
import org.springframework.ide.vscode.boot.java.cron.CronExpressionsInlayHintsProvider;
2021
import org.springframework.ide.vscode.boot.java.cron.CronReconciler;
2122
import org.springframework.ide.vscode.boot.java.cron.CronSemanticTokens;
@@ -63,8 +64,8 @@ public class JdtConfig {
6364
return new BeanMethodNotPublicReconciler(server.getQuickfixRegistry());
6465
}
6566

66-
@Bean AddConfigurationIfBeansPresentReconciler addConfigurationIfBeansPresentReconciler(SimpleLanguageServer server) {
67-
return new AddConfigurationIfBeansPresentReconciler(server.getQuickfixRegistry());
67+
@Bean AddConfigurationIfBeansPresentReconciler addConfigurationIfBeansPresentReconciler(SimpleLanguageServer server, SpringMetamodelIndex springIndex) {
68+
return new AddConfigurationIfBeansPresentReconciler(server.getQuickfixRegistry(), springIndex);
6869
}
6970

7071
@Bean AutowiredFieldIntoConstructorParameterReconciler autowiredFieldIntoConstructorParameterReconciler(SimpleLanguageServer server) {

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

Lines changed: 0 additions & 22 deletions
This file was deleted.

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

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,16 @@
1313
import java.util.Arrays;
1414
import java.util.Collection;
1515
import java.util.HashSet;
16-
import java.util.List;
17-
import java.util.Objects;
1816
import java.util.Set;
1917
import java.util.stream.Collectors;
2018
import java.util.stream.Stream;
2119

2220
import org.eclipse.jdt.core.dom.Annotation;
23-
import org.eclipse.jdt.core.dom.ArrayInitializer;
2421
import org.eclipse.jdt.core.dom.ITypeBinding;
2522
import org.eclipse.jdt.core.dom.MemberValuePair;
2623
import org.eclipse.jdt.core.dom.NormalAnnotation;
2724
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
2825
import org.eclipse.jdt.core.dom.TypeDeclaration;
29-
import org.eclipse.jdt.core.dom.TypeLiteral;
3026
import org.eclipse.lsp4j.Location;
3127
import org.eclipse.lsp4j.SymbolKind;
3228
import org.eclipse.lsp4j.WorkspaceSymbol;
@@ -86,7 +82,7 @@ private Two<EnhancedSymbolInformation, Bean> createSymbol(Annotation node, IType
8682
beanLabel("+", annotationTypeName, metaAnnotationNames, beanName, beanType == null ? "" : beanType.getName()), SymbolKind.Interface,
8783
Either.forLeft(location));
8884

89-
SymbolAddOnInformation[] addon = new SymbolAddOnInformation[] {new FeignClientBeanSymbolAddOnInformation(beanName, beanType == null ? "" : beanType.getQualifiedName(), getConfigClass(node))};
85+
SymbolAddOnInformation[] addon = new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(beanName, beanType == null ? "" : beanType.getQualifiedName())};
9086

9187
InjectionPoint[] injectionPoints = ASTUtils.findInjectionPoints(type, doc);
9288

@@ -159,31 +155,4 @@ private String getBeanName(Annotation node, TypeDeclaration typeDecl) {
159155
return BeanUtils.getBeanNameFromType(typeDecl.getName().getIdentifier());
160156
}
161157

162-
private String[] getConfigClass(Annotation node) {
163-
if (node.isNormalAnnotation()) {
164-
NormalAnnotation normalAnnotation = (NormalAnnotation) node;
165-
for (Object o : normalAnnotation.values()) {
166-
if (o instanceof MemberValuePair) {
167-
MemberValuePair pair = (MemberValuePair) o;
168-
if ("configuration".equals(pair.getName().getIdentifier())) {
169-
if (pair.getValue() instanceof TypeLiteral) {
170-
ITypeBinding b = ((TypeLiteral) pair.getValue()).getType().resolveBinding();
171-
return new String[] { b.getQualifiedName() };
172-
} else if (pair.getValue() instanceof ArrayInitializer){
173-
List<?> expressions = (List<?>) ((ArrayInitializer) pair.getValue()).expressions();
174-
return expressions.stream()
175-
.filter(TypeLiteral.class::isInstance)
176-
.map(TypeLiteral.class::cast)
177-
.map(tl -> tl.getType().resolveBinding())
178-
.filter(Objects::nonNull)
179-
.map(b -> b.getQualifiedName())
180-
.toArray(String[]::new);
181-
}
182-
}
183-
}
184-
}
185-
}
186-
return new String[0];
187-
}
188-
189158
}

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

Lines changed: 36 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212

1313
import java.lang.reflect.Modifier;
1414
import java.net.URI;
15+
import java.util.Arrays;
1516
import java.util.Iterator;
1617
import java.util.List;
18+
import java.util.stream.Stream;
1719

1820
import org.eclipse.jdt.core.dom.ASTNode;
1921
import org.eclipse.jdt.core.dom.ASTVisitor;
@@ -23,37 +25,32 @@
2325
import org.eclipse.jdt.core.dom.SimpleName;
2426
import org.eclipse.jdt.core.dom.TypeDeclaration;
2527
import org.openrewrite.java.spring.boot2.AddConfigurationAnnotationIfBeansPresent;
26-
import org.springframework.beans.BeansException;
27-
import org.springframework.context.ApplicationContext;
28-
import org.springframework.context.ApplicationContextAware;
29-
import org.springframework.ide.vscode.boot.app.SpringSymbolIndex;
28+
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
3029
import org.springframework.ide.vscode.boot.java.Annotations;
3130
import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType;
3231
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
33-
import org.springframework.ide.vscode.boot.java.beans.BeansSymbolAddOnInformation;
34-
import org.springframework.ide.vscode.boot.java.beans.FeignClientBeanSymbolAddOnInformation;
35-
import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation;
36-
import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation;
3732
import org.springframework.ide.vscode.commons.Version;
3833
import org.springframework.ide.vscode.commons.java.IJavaProject;
3934
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
4035
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
4136
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
4237
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemType;
4338
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
39+
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
4440
import org.springframework.ide.vscode.commons.rewrite.config.RecipeScope;
4541
import org.springframework.ide.vscode.commons.rewrite.java.FixDescriptor;
4642

47-
public class AddConfigurationIfBeansPresentReconciler implements JdtAstReconciler, ApplicationContextAware {
43+
public class AddConfigurationIfBeansPresentReconciler implements JdtAstReconciler {
4844

4945
private static final String PROBLEM_LABEL = "'@Configuration' is missing on a class defining Spring Beans";
5046
private static final String FIX_LABEL = "Add missing '@Configuration' annotations over classes";
5147

52-
private QuickfixRegistry quickfixRegistry;
53-
private ApplicationContext applicationContext;
48+
private final QuickfixRegistry quickfixRegistry;
49+
private final SpringMetamodelIndex springIndex;
5450

55-
public AddConfigurationIfBeansPresentReconciler(QuickfixRegistry quickfixRegistry) {
51+
public AddConfigurationIfBeansPresentReconciler(QuickfixRegistry quickfixRegistry, SpringMetamodelIndex springIndex) {
5652
this.quickfixRegistry = quickfixRegistry;
53+
this.springIndex = springIndex;
5754
}
5855

5956
@Override
@@ -67,11 +64,6 @@ public ProblemType getProblemType() {
6764
return Boot2JavaProblemType.MISSING_CONFIGURATION_ANNOTATION;
6865
}
6966

70-
@Override
71-
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
72-
this.applicationContext = applicationContext;
73-
}
74-
7567
@Override
7668
public ASTVisitor createVisitor(IJavaProject project, URI docUri, CompilationUnit cu, IProblemCollector problemCollector, boolean isCompleteAst) {
7769
return new ASTVisitor() {
@@ -146,33 +138,34 @@ private boolean isApplicableClass(IJavaProject project, CompilationUnit cu, Type
146138
}
147139

148140
private boolean isException(IJavaProject project, TypeDeclaration classDecl) {
149-
if (applicationContext != null) {
150-
SpringSymbolIndex index = applicationContext.getBean(SpringSymbolIndex.class);
151-
if (index != null) {
152-
final String beanClassName = ReconcileUtils.getDeepErasureType(classDecl.resolveBinding()).getQualifiedName();
153-
for (EnhancedSymbolInformation s : index.getEnhancedSymbols(project)) {
154-
SymbolAddOnInformation[] additionalInformation = s.getAdditionalInformation();
155-
if (additionalInformation != null) {
156-
for (SymbolAddOnInformation info : additionalInformation) {
157-
if (info instanceof BeansSymbolAddOnInformation) {
158-
BeansSymbolAddOnInformation info2 = (BeansSymbolAddOnInformation) info;
159-
if (beanClassName.equals(info2.getBeanType())) {
160-
return true;
161-
}
162-
if (info instanceof FeignClientBeanSymbolAddOnInformation) {
163-
FeignClientBeanSymbolAddOnInformation feign = (FeignClientBeanSymbolAddOnInformation) info;
164-
for (String configBean : feign.configClasses) {
165-
if (beanClassName.equals(configBean)) {
166-
return true;
167-
}
168-
}
169-
}
170-
}
171-
}
172-
}
173-
}
174-
}
141+
if (springIndex == null) {
142+
return false;
175143
}
144+
145+
final String beanClassName = ReconcileUtils.getDeepErasureType(classDecl.resolveBinding()).getQualifiedName();
146+
147+
Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName());
148+
149+
if (beans == null || beans.length == 0) {
150+
return false;
151+
}
152+
153+
// look for beans with that type
154+
if (Arrays.stream(beans).anyMatch(bean -> bean.getType().equals(beanClassName))) {
155+
return true;
156+
}
157+
158+
boolean isConfiguredAsfeignConfigClass = Arrays.stream(beans)
159+
.flatMap(bean -> Arrays.stream(bean.getAnnotations()))
160+
.filter(annotation -> annotation.getAnnotationType().equals(Annotations.FEIGN_CLIENT))
161+
.map(annotation -> annotation.getAttributes().get("configuration"))
162+
.flatMap(attributeValues -> attributeValues != null ? Arrays.stream(attributeValues) : Stream.empty())
163+
.anyMatch(attributeValue -> attributeValue.getName().equals(beanClassName));
164+
165+
if (isConfiguredAsfeignConfigClass) {
166+
return true;
167+
}
168+
176169
return false;
177170
}
178171

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public static enum SCAN_PASS {
9393

9494
// whenever the implementation of the indexer changes in a way that the stored data in the cache is no longer valid,
9595
// we need to change the generation - this will result in a re-indexing due to no up-to-date cache data being found
96-
private static final String GENERATION = "GEN-8";
96+
private static final String GENERATION = "GEN-9";
9797
private static final String INDEX_FILES_TASK_ID = "index-java-source-files-task-";
9898

9999
private static final String SYMBOL_KEY = "symbols";

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

Lines changed: 29 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2023 VMware, Inc.
2+
* Copyright (c) 2023, 2024 VMware, Inc.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -11,32 +11,23 @@
1111
package org.springframework.ide.vscode.boot.java.reconcilers.test;
1212

1313
import static org.junit.jupiter.api.Assertions.assertEquals;
14-
import static org.mockito.ArgumentMatchers.any;
15-
import static org.mockito.Mockito.mock;
16-
import static org.mockito.Mockito.when;
1714

1815
import java.util.List;
16+
import java.util.Map;
1917

20-
import org.eclipse.lsp4j.Location;
21-
import org.eclipse.lsp4j.Range;
22-
import org.eclipse.lsp4j.SymbolKind;
23-
import org.eclipse.lsp4j.WorkspaceSymbol;
24-
import org.eclipse.lsp4j.jsonrpc.messages.Either;
2518
import org.junit.jupiter.api.AfterEach;
2619
import org.junit.jupiter.api.BeforeEach;
2720
import org.junit.jupiter.api.Test;
28-
import org.springframework.context.ApplicationContext;
29-
import org.springframework.ide.vscode.boot.app.SpringSymbolIndex;
21+
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
22+
import org.springframework.ide.vscode.boot.java.Annotations;
3023
import org.springframework.ide.vscode.boot.java.Boot2JavaProblemType;
31-
import org.springframework.ide.vscode.boot.java.beans.ConfigBeanSymbolAddOnInformation;
32-
import org.springframework.ide.vscode.boot.java.beans.FeignClientBeanSymbolAddOnInformation;
33-
import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation;
34-
import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation;
3524
import org.springframework.ide.vscode.boot.java.reconcilers.AddConfigurationIfBeansPresentReconciler;
3625
import org.springframework.ide.vscode.boot.java.reconcilers.JdtAstReconciler;
37-
import org.springframework.ide.vscode.commons.java.IJavaProject;
3826
import org.springframework.ide.vscode.commons.languageserver.quickfix.QuickfixRegistry;
3927
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem;
28+
import org.springframework.ide.vscode.commons.protocol.spring.AnnotationAttributeValue;
29+
import org.springframework.ide.vscode.commons.protocol.spring.AnnotationMetadata;
30+
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
4031

4132
public class AddConfigurationIfBeansPresentReconcilerTest extends BaseReconcilerTest {
4233

@@ -52,7 +43,7 @@ protected String getProjectName() {
5243

5344
@Override
5445
protected JdtAstReconciler getReconciler() {
55-
return new AddConfigurationIfBeansPresentReconciler(new QuickfixRegistry());
46+
return new AddConfigurationIfBeansPresentReconciler(new QuickfixRegistry(), null);
5647
}
5748

5849
@BeforeEach
@@ -81,7 +72,11 @@ String myBean() {
8172
8273
}
8374
""";
84-
List<ReconcileProblem> problems = reconcile("A.java", source, false);
75+
List<ReconcileProblem> problems = reconcile(() -> {
76+
SpringMetamodelIndex springIndex = new SpringMetamodelIndex();
77+
AddConfigurationIfBeansPresentReconciler r = new AddConfigurationIfBeansPresentReconciler(new QuickfixRegistry(), springIndex);
78+
return r;
79+
}, "A.java", source, false);
8580

8681
assertEquals(1, problems.size());
8782

@@ -93,7 +88,6 @@ String myBean() {
9388
assertEquals("A", markedStr);
9489

9590
assertEquals(2, problem.getQuickfixes().size());
96-
9791
}
9892

9993
@Test
@@ -113,26 +107,20 @@ String myBean() {
113107
}
114108
""";
115109
List<ReconcileProblem> problems = reconcile(() -> {
116-
AddConfigurationIfBeansPresentReconciler r = new AddConfigurationIfBeansPresentReconciler(new QuickfixRegistry());
117-
118-
WorkspaceSymbol workspaceSymbol = new WorkspaceSymbol("testConfig", SymbolKind.Class, Either.forLeft(new Location("file:///someUri", new Range())));
119-
ConfigBeanSymbolAddOnInformation beanSymbolAddOn = new ConfigBeanSymbolAddOnInformation("a", "example.demo.A");
120-
EnhancedSymbolInformation beanSymbol = new EnhancedSymbolInformation(workspaceSymbol, new SymbolAddOnInformation[] { beanSymbolAddOn });
121-
122-
SpringSymbolIndex mockSymbolIndex = mock(SpringSymbolIndex.class);
123-
124-
when(mockSymbolIndex.getEnhancedSymbols(any(IJavaProject.class))).thenReturn(List.of(beanSymbol));
125-
126-
ApplicationContext context = mock(ApplicationContext.class);
127-
when(context.getBean(SpringSymbolIndex.class)).thenReturn(mockSymbolIndex);
128-
129-
r.setApplicationContext(context);
110+
SpringMetamodelIndex springIndex = new SpringMetamodelIndex();
111+
112+
AnnotationMetadata annotationMetadata = new AnnotationMetadata(Annotations.CONFIGURATION, false, null, Map.of());
113+
AnnotationMetadata[] annotations = new AnnotationMetadata[] {annotationMetadata};
114+
Bean configBean = new Bean("a", "example.demo.A", null, null, null, annotations);
115+
Bean[] beans = new Bean[] {configBean};
116+
springIndex.updateBeans(getProjectName(), beans);
117+
118+
AddConfigurationIfBeansPresentReconciler r = new AddConfigurationIfBeansPresentReconciler(new QuickfixRegistry(), springIndex);
130119

131120
return r;
132121
}, "A.java", source, false);
133122

134123
assertEquals(0, problems.size());
135-
136124
}
137125

138126
@Test
@@ -152,25 +140,19 @@ String myBean() {
152140
}
153141
""";
154142
List<ReconcileProblem> problems = reconcile(() -> {
155-
AddConfigurationIfBeansPresentReconciler r = new AddConfigurationIfBeansPresentReconciler(new QuickfixRegistry());
143+
SpringMetamodelIndex springIndex = new SpringMetamodelIndex();
156144

157-
WorkspaceSymbol workspaceSymbol = new WorkspaceSymbol("testConfig", SymbolKind.Class, Either.forLeft(new Location("file:///someUri", new Range())));
158-
FeignClientBeanSymbolAddOnInformation beanSymbolAddOn = new FeignClientBeanSymbolAddOnInformation("b", "example.demo.B", "example.demo.A");
159-
EnhancedSymbolInformation beanSymbol = new EnhancedSymbolInformation(workspaceSymbol, new SymbolAddOnInformation[] { beanSymbolAddOn });
145+
AnnotationMetadata annotationMetadata = new AnnotationMetadata(Annotations.FEIGN_CLIENT, false, null, Map.of("configuration", new AnnotationAttributeValue[] {new AnnotationAttributeValue("example.demo.A", null)}));
146+
AnnotationMetadata[] annotations = new AnnotationMetadata[] {annotationMetadata};
147+
Bean configBean = new Bean("feignClient", "example.demo.FeignClientExample", null, null, null, annotations);
148+
Bean[] beans = new Bean[] {configBean};
149+
springIndex.updateBeans(getProjectName(), beans);
160150

161-
SpringSymbolIndex mockSymbolIndex = mock(SpringSymbolIndex.class);
162-
163-
when(mockSymbolIndex.getEnhancedSymbols(any(IJavaProject.class))).thenReturn(List.of(beanSymbol));
164-
165-
ApplicationContext context = mock(ApplicationContext.class);
166-
when(context.getBean(SpringSymbolIndex.class)).thenReturn(mockSymbolIndex);
167-
168-
r.setApplicationContext(context);
151+
AddConfigurationIfBeansPresentReconciler r = new AddConfigurationIfBeansPresentReconciler(new QuickfixRegistry(), springIndex);
169152

170153
return r;
171154
}, "A.java", source, false);
172155

173156
assertEquals(0, problems.size());
174-
175157
}
176158
}

0 commit comments

Comments
 (0)