diff --git a/headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/spring/AnnotationAttributeValue.java b/headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/spring/AnnotationAttributeValue.java new file mode 100644 index 0000000000..dd82d162b6 --- /dev/null +++ b/headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/spring/AnnotationAttributeValue.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2024 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 + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Broadcom - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.commons.protocol.spring; + +import java.util.Objects; + +import org.eclipse.lsp4j.Location; + +/** + * @author Martin Lippert + */ +public class AnnotationAttributeValue { + + private final String name; + private final Location location; + + public AnnotationAttributeValue(String name, Location location) { + this.name = name; + this.location = location; + } + + public String getName() { + return name; + } + + public Location getLocation() { + return location; + } + + @Override + public int hashCode() { + return Objects.hash(location, name); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + AnnotationAttributeValue other = (AnnotationAttributeValue) obj; + return Objects.equals(location, other.location) && Objects.equals(name, other.name); + } + +} diff --git a/headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/spring/AnnotationMetadata.java b/headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/spring/AnnotationMetadata.java index a04a79c7a5..6f645691a1 100644 --- a/headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/spring/AnnotationMetadata.java +++ b/headless-services/commons/commons-lsp-extensions/src/main/java/org/springframework/ide/vscode/commons/protocol/spring/AnnotationMetadata.java @@ -12,6 +12,8 @@ import java.util.Map; +import org.eclipse.lsp4j.Location; + /** * @author Martin Lippert */ @@ -19,11 +21,13 @@ public class AnnotationMetadata { private final String annotationType; private final boolean isMetaAnnotation; - private final Map attributes; + private final Location location; + private final Map attributes; - public AnnotationMetadata(String annotationType, boolean isMetaAnnotation, Map attributes) { + public AnnotationMetadata(String annotationType, boolean isMetaAnnotation, Location location, Map attributes) { this.annotationType = annotationType; this.isMetaAnnotation = isMetaAnnotation; + this.location = location; this.attributes = attributes; } @@ -34,9 +38,13 @@ public String getAnnotationType() { public boolean isMetaAnnotation() { return isMetaAnnotation; } + + public Location getLocation() { + return location; + } - public Map getAttributes() { + public Map getAttributes() { return attributes; } - + } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java index 4956d30999..c5e4207643 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java @@ -96,16 +96,8 @@ protected void addSymbolsPass1(Annotation node, ITypeBinding annotationType, Col ASTUtils.findSupertypes(beanType, supertypes); Collection annotationsOnMethod = ASTUtils.getAnnotations(method); - AnnotationMetadata[] annotations = annotationsOnMethod.stream() - .map(an -> an.resolveAnnotationBinding()) - .map(t -> new AnnotationMetadata(t.getAnnotationType().getQualifiedName(), false, ASTUtils.getAttributes(t))) - .toArray(AnnotationMetadata[]::new); + AnnotationMetadata[] annotations = ASTUtils.getAnnotationsMetadata(annotationsOnMethod, doc); -// AnnotationMetadata[] annotations = AnnotationHierarchies -// .findTransitiveSuperAnnotationBindings(node.resolveAnnotationBinding()) -// .map(t -> new AnnotationMetadata(t.getAnnotationType().getQualifiedName(), false, getAttributes(t))) -// .toArray(AnnotationMetadata[]::new); - Bean beanDefinition = new Bean(nameAndRegion.getT1(), beanType.getQualifiedName(), location, injectionPoints, supertypes, annotations); context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol)); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentSymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentSymbolProvider.java index 759356cd88..5c8488f5f7 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentSymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentSymbolProvider.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.beans; +import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -105,12 +106,10 @@ protected Tuple.Two createSymbol(Annotation nod Collection annotationsOnType = ASTUtils.getAnnotations(type); AnnotationMetadata[] annotations = Stream.concat( - annotationsOnType.stream() - .map(an -> an.resolveAnnotationBinding()) - .map(t -> new AnnotationMetadata(t.getAnnotationType().getQualifiedName(), false, ASTUtils.getAttributes(t))) + Arrays.stream(ASTUtils.getAnnotationsMetadata(annotationsOnType, doc)) , metaAnnotations.stream() - .map(an -> new AnnotationMetadata(an.getQualifiedName(), true, null))) + .map(an -> new AnnotationMetadata(an.getQualifiedName(), true, null, null))) .toArray(AnnotationMetadata[]::new); Bean beanDefinition = new Bean(beanName, beanType.getQualifiedName(), location, injectionPoints, supertypes, annotations); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/FeignClientSymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/FeignClientSymbolProvider.java index b824295f41..2aef9b77b6 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/FeignClientSymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/FeignClientSymbolProvider.java @@ -10,6 +10,7 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.beans; +import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.List; @@ -95,12 +96,10 @@ private Two createSymbol(Annotation node, IType Collection annotationsOnType = ASTUtils.getAnnotations(type); AnnotationMetadata[] annotations = Stream.concat( - annotationsOnType.stream() - .map(an -> an.resolveAnnotationBinding()) - .map(t -> new AnnotationMetadata(t.getAnnotationType().getQualifiedName(), false, ASTUtils.getAttributes(t))) + Arrays.stream(ASTUtils.getAnnotationsMetadata(annotationsOnType, doc)) , metaAnnotations.stream() - .map(an -> new AnnotationMetadata(an.getQualifiedName(), true, null))) + .map(an -> new AnnotationMetadata(an.getQualifiedName(), true, null, null))) .toArray(AnnotationMetadata[]::new); Bean beanDefinition = new Bean(beanName, beanType == null ? "" : beanType.getQualifiedName(), location, injectionPoints, supertypes, annotations); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/NamedCompletionProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/NamedCompletionProvider.java index c42a8bf545..7c6553f6bd 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/NamedCompletionProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/NamedCompletionProvider.java @@ -54,7 +54,7 @@ private Stream findAllNamedValues(Bean[] beans) { .flatMap(bean -> Arrays.stream(bean.getAnnotations())) .filter(annotation -> Annotations.NAMED_ANNOTATIONS.contains(annotation.getAnnotationType())) .filter(annotation -> annotation.getAttributes() != null && annotation.getAttributes().containsKey("value") && annotation.getAttributes().get("value").length == 1) - .map(annotation -> annotation.getAttributes().get("value")[0]); + .map(annotation -> annotation.getAttributes().get("value")[0].getName()); Stream qualifiersFromInjectionPoints = Arrays.stream(beans) // annotations from beans themselves @@ -64,7 +64,7 @@ private Stream findAllNamedValues(Bean[] beans) { .flatMap(injectionPoint -> Arrays.stream(injectionPoint.getAnnotations())) .filter(annotation -> Annotations.NAMED_ANNOTATIONS.contains(annotation.getAnnotationType())) .filter(annotation -> annotation.getAttributes() != null && annotation.getAttributes().containsKey("value") && annotation.getAttributes().get("value").length == 1) - .map(annotation -> annotation.getAttributes().get("value")[0]); + .map(annotation -> annotation.getAttributes().get("value")[0].getName()); return Stream.concat(qualifiersFromBeans, qualifiersFromInjectionPoints); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ProfileCompletionProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ProfileCompletionProvider.java index 26a1ca92a4..225c04a74d 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ProfileCompletionProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ProfileCompletionProvider.java @@ -52,7 +52,8 @@ private Stream findAllProfiles(Bean[] beans) { .flatMap(bean -> Arrays.stream(bean.getAnnotations())) .filter(annotation -> Annotations.PROFILE.equals(annotation.getAnnotationType())) .filter(annotation -> annotation.getAttributes() != null && annotation.getAttributes().containsKey("value")) - .flatMap(annotation -> Arrays.stream(annotation.getAttributes().get("value"))); + .flatMap(annotation -> Arrays.stream(annotation.getAttributes().get("value"))) + .map(attributeValue -> attributeValue.getName()); Stream profilesFromInjectionPoints = Arrays.stream(beans) // annotations from beans themselves @@ -62,7 +63,8 @@ private Stream findAllProfiles(Bean[] beans) { .flatMap(injectionPoint -> Arrays.stream(injectionPoint.getAnnotations())) .filter(annotation -> Annotations.PROFILE.equals(annotation.getAnnotationType())) .filter(annotation -> annotation.getAttributes() != null && annotation.getAttributes().containsKey("value")) - .flatMap(annotation -> Arrays.stream(annotation.getAttributes().get("value"))); + .flatMap(annotation -> Arrays.stream(annotation.getAttributes().get("value"))) + .map(attributeValue -> attributeValue.getName()); return Stream.concat(profilesFromBeans, profilesFromInjectionPoints); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/QualifierCompletionProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/QualifierCompletionProvider.java index 20d17017bf..eca5aa318c 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/QualifierCompletionProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/QualifierCompletionProvider.java @@ -64,7 +64,7 @@ private Stream findAllQualifiers(Bean[] beans) { .flatMap(bean -> Arrays.stream(bean.getAnnotations())) .filter(annotation -> Annotations.QUALIFIER.equals(annotation.getAnnotationType())) .filter(annotation -> annotation.getAttributes() != null && annotation.getAttributes().containsKey("value") && annotation.getAttributes().get("value").length == 1) - .map(annotation -> annotation.getAttributes().get("value")[0]); + .map(annotation -> annotation.getAttributes().get("value")[0].getName()); Stream qualifiersFromInjectionPoints = Arrays.stream(beans) // annotations from beans themselves @@ -74,7 +74,7 @@ private Stream findAllQualifiers(Bean[] beans) { .flatMap(injectionPoint -> Arrays.stream(injectionPoint.getAnnotations())) .filter(annotation -> Annotations.QUALIFIER.equals(annotation.getAnnotationType())) .filter(annotation -> annotation.getAttributes() != null && annotation.getAttributes().containsKey("value") && annotation.getAttributes().get("value").length == 1) - .map(annotation -> annotation.getAttributes().get("value")[0]); + .map(annotation -> annotation.getAttributes().get("value")[0].getName()); return Stream.concat(qualifiersFromBeans, qualifiersFromInjectionPoints); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/DataRepositorySymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/DataRepositorySymbolProvider.java index 5000631534..d214c976d1 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/DataRepositorySymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/DataRepositorySymbolProvider.java @@ -78,10 +78,7 @@ protected void addSymbolsPass1(TypeDeclaration typeDeclaration, SpringIndexerJav String concreteRepoType = concreteBeanTypeBindung.getQualifiedName(); Collection annotationsOnMethod = ASTUtils.getAnnotations(typeDeclaration); - AnnotationMetadata[] annotations = annotationsOnMethod.stream() - .map(an -> an.resolveAnnotationBinding()) - .map(t -> new AnnotationMetadata(t.getAnnotationType().getQualifiedName(), false, ASTUtils.getAttributes(t))) - .toArray(AnnotationMetadata[]::new); + AnnotationMetadata[] annotations = ASTUtils.getAnnotationsMetadata(annotationsOnMethod, doc); Bean beanDefinition = new Bean(beanName, concreteRepoType, location, injectionPoints, supertypes, annotations); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java index 104cc1b678..389ae80cf4 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java @@ -40,9 +40,10 @@ import org.eclipse.jdt.core.dom.QualifiedName; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.SingleMemberAnnotation; +import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.StringLiteral; import org.eclipse.jdt.core.dom.TypeDeclaration; -import org.eclipse.jdt.core.dom.VariableDeclaration; +import org.eclipse.jdt.core.dom.TypeLiteral; import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.Range; @@ -51,6 +52,7 @@ import org.springframework.ide.vscode.boot.java.Annotations; import org.springframework.ide.vscode.boot.java.jdt.imports.ImportRewrite; import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; +import org.springframework.ide.vscode.commons.protocol.spring.AnnotationAttributeValue; import org.springframework.ide.vscode.commons.protocol.spring.AnnotationMetadata; import org.springframework.ide.vscode.commons.protocol.spring.DefaultValues; import org.springframework.ide.vscode.commons.protocol.spring.InjectionPoint; @@ -269,6 +271,14 @@ public static Collection getAnnotations(MethodDeclaration methodDecl return getAnnotationsFromModifiers(methodDeclaration.getStructuralProperty(MethodDeclaration.MODIFIERS2_PROPERTY)); } + public static Collection getAnnotations(FieldDeclaration fieldDeclaration) { + return getAnnotationsFromModifiers(fieldDeclaration.getStructuralProperty(FieldDeclaration.MODIFIERS2_PROPERTY)); + } + + public static Collection getAnnotations(SingleVariableDeclaration variableDeclaration) { + return getAnnotationsFromModifiers(variableDeclaration.getStructuralProperty(SingleVariableDeclaration.MODIFIERS2_PROPERTY)); + } + private static Collection getAnnotationsFromModifiers(Object modifiersObj) { if (modifiersObj instanceof List) { ImmutableList.Builder annotations = ImmutableList.builder(); @@ -285,7 +295,7 @@ private static Collection getAnnotationsFromModifiers(Object modifie public static String getAnnotationType(Annotation annotation) { ITypeBinding binding = annotation.resolveTypeBinding(); - if (binding!=null) { + if (binding != null) { return binding.getQualifiedName(); } return null; @@ -339,30 +349,30 @@ public static Optional getImportsEdit(CompilationUnit cu, Collect return edit != null ? Optional.of(edit) : Optional.empty(); } - public static Collection getInjectionPointsFromMethodParams(MethodDeclaration method, TextDocument doc) throws BadLocationException { - List result = new ArrayList<>(); - - List parameters = method.parameters(); - for (Object object : parameters) { - if (object instanceof VariableDeclaration) { - VariableDeclaration variable = (VariableDeclaration) object; - String name = variable.getName().toString(); - - IVariableBinding variableBinding = variable.resolveBinding(); - String type = variableBinding.getType().getQualifiedName(); - - DocumentRegion region = ASTUtils.nodeRegion(doc, variable.getName()); - Range range = doc.toRange(region); - - Location location = new Location(doc.getUri(), range); - AnnotationMetadata[] annotations = ASTUtils.getAnnotationsMetadata(variableBinding.getAnnotations()); - - result.add(new InjectionPoint(name, type, location, annotations)); - } - } - return result; - } - +// public static Collection getInjectionPointsFromMethodParams(MethodDeclaration method, TextDocument doc) throws BadLocationException { +// List result = new ArrayList<>(); +// +// List parameters = method.parameters(); +// for (Object object : parameters) { +// if (object instanceof VariableDeclaration) { +// VariableDeclaration variable = (VariableDeclaration) object; +// String name = variable.getName().toString(); +// +// IVariableBinding variableBinding = variable.resolveBinding(); +// String type = variableBinding.getType().getQualifiedName(); +// +// DocumentRegion region = ASTUtils.nodeRegion(doc, variable.getName()); +// Range range = doc.toRange(region); +// +// Location location = new Location(doc.getUri(), range); +// AnnotationMetadata[] annotations = ASTUtils.getAnnotationsMetadata(variableBinding.getAnnotations()); +// +// result.add(new InjectionPoint(name, type, location, annotations)); +// } +// } +// return result; +// } +// public static void findSupertypes(ITypeBinding binding, Set supertypesCollector) { // interfaces @@ -405,8 +415,8 @@ public static InjectionPoint[] findInjectionPoints(MethodDeclaration method, Tex List parameters = method.parameters(); for (Object object : parameters) { - if (object instanceof VariableDeclaration) { - VariableDeclaration variable = (VariableDeclaration) object; + if (object instanceof SingleVariableDeclaration) { + SingleVariableDeclaration variable = (SingleVariableDeclaration) object; String name = variable.getName().toString(); IVariableBinding variableBinding = variable.resolveBinding(); @@ -416,7 +426,8 @@ public static InjectionPoint[] findInjectionPoints(MethodDeclaration method, Tex Range range = doc.toRange(region); Location location = new Location(doc.getUri(), range); - AnnotationMetadata[] annotations = ASTUtils.getAnnotationsMetadata(variableBinding.getAnnotations()); + + AnnotationMetadata[] annotations = getAnnotationsMetadata(getAnnotations(variable), doc); result.add(new InjectionPoint(name, type, location, annotations)); } @@ -471,10 +482,7 @@ public static InjectionPoint[] findInjectionPoints(TypeDeclaration type, TextDoc String fieldType = field.getType().resolveBinding().getQualifiedName(); - AnnotationMetadata[] annotationsMetadata = fieldAnnotations.stream() - .map(an -> an.resolveAnnotationBinding()) - .map(t -> new AnnotationMetadata(t.getAnnotationType().getQualifiedName(), false, ASTUtils.getAttributes(t))) - .toArray(AnnotationMetadata[]::new); + AnnotationMetadata[] annotationsMetadata = getAnnotationsMetadata(fieldAnnotations, doc); result.add(new InjectionPoint(fieldName, fieldType, fieldLocation, annotationsMetadata)); } @@ -485,26 +493,129 @@ public static InjectionPoint[] findInjectionPoints(TypeDeclaration type, TextDoc return result.size() > 0 ? result.toArray(new InjectionPoint[result.size()]) : DefaultValues.EMPTY_INJECTION_POINTS; } - private static AnnotationMetadata[] getAnnotationsMetadata(IAnnotationBinding[] annotations) { - return Arrays.stream(annotations) - .map(t -> new AnnotationMetadata(t.getAnnotationType().getQualifiedName(), false, getAttributes(t))) - .toArray(AnnotationMetadata[]::new); + public static AnnotationMetadata[] getAnnotationsMetadata(Collection annotations, TextDocument doc) { + return annotations.stream() + .map(annotation -> createAnnotationMetadataFrom(annotation, doc)) + .toArray(AnnotationMetadata[]::new); } - public static Map getAttributes(IAnnotationBinding t) { - Map result = new LinkedHashMap<>(); + private static AnnotationMetadata createAnnotationMetadataFrom(Annotation annotation, TextDocument doc) { + try { + DocumentRegion region = ASTUtils.nodeRegion(doc, annotation); + Range range = doc.toRange(region); + Location location = new Location(doc.getUri(), range); + IAnnotationBinding binding = annotation.resolveAnnotationBinding(); + return new AnnotationMetadata(binding.getAnnotationType().getQualifiedName(), false, location, getAttributes(annotation, doc)); + } + catch (BadLocationException e) { + log.error("problem when identifying location of annotation", e); + } + + return null; + } + +// public static Map getAttributes(IAnnotationBinding t) { +// Map result = new LinkedHashMap<>(); +// +// IMemberValuePairBinding[] pairs = t.getDeclaredMemberValuePairs(); +// for (IMemberValuePairBinding pair : pairs) { +// MemberValuePairAndType values = ASTUtils.getValuesFromValuePair(pair); +// if (values != null) { +// result.put(pair.getName(), values.values); +// } +// } +// +// return result; +// } + + public static Map getAttributes(Annotation annotation, TextDocument doc) throws BadLocationException { + Map result = new LinkedHashMap<>(); +/* + IAnnotationBinding t = annotation.resolveAnnotationBinding(); IMemberValuePairBinding[] pairs = t.getDeclaredMemberValuePairs(); for (IMemberValuePairBinding pair : pairs) { MemberValuePairAndType values = ASTUtils.getValuesFromValuePair(pair); if (values != null) { - result.put(pair.getName(), values.values); + AnnotationAttributeValue[] attributeValue = Arrays.stream(values.values) + .map(value -> new AnnotationAttributeValue(value, null)) + .toArray(AnnotationAttributeValue[]::new); + + result.put(pair.getName(), attributeValue); } } +*/ + if (annotation.isSingleMemberAnnotation()) { + Expression value = ((SingleMemberAnnotation) annotation).getValue(); + AnnotationAttributeValue[] attributeValues = getAnnotationAttributeValues(value, doc); + result.put("value", attributeValues); + + } else if (annotation.isNormalAnnotation()) { + List attributes = ((NormalAnnotation) annotation).values(); + for (Object attribute : attributes) { + MemberValuePair pair = (MemberValuePair) attribute; + + SimpleName attributeName = pair.getName(); + Expression attributeValue = pair.getValue(); + + AnnotationAttributeValue[] attributeValues = getAnnotationAttributeValues(attributeValue, doc); + result.put(attributeName.toString(), attributeValues); + } + } + return result; } + private static AnnotationAttributeValue[] getAnnotationAttributeValues(Expression expression, TextDocument doc) throws BadLocationException { + if (expression instanceof ArrayInitializer) { + ArrayInitializer arrayInitializer = (ArrayInitializer) expression; + List expressions = arrayInitializer.expressions(); + + AnnotationAttributeValue[] result = new AnnotationAttributeValue[expressions.size()]; + for (int i = 0; i < result.length; i++) { + Expression ex = (Expression) expressions.get(i); + result[i] = convertExpressionInto(ex, doc); + } + + return result; + } + else { + return new AnnotationAttributeValue[] {convertExpressionInto(expression, doc)}; + } + +// Object constantExpressionValue = attributeValue.resolveConstantExpressionValue(); + } + + private static AnnotationAttributeValue convertExpressionInto(Expression expression, TextDocument doc) throws BadLocationException { + if (expression instanceof StringLiteral) { + StringLiteral stringLiteral = (StringLiteral) expression; + String literalValue = stringLiteral.getLiteralValue(); + + DocumentRegion region = ASTUtils.nodeRegion(doc, stringLiteral); + Range range = doc.toRange(region); + Location location = new Location(doc.getUri(), range); + + return new AnnotationAttributeValue(literalValue, location); + } + else if (expression instanceof TypeLiteral) { + TypeLiteral type = (TypeLiteral) expression; + + DocumentRegion region = ASTUtils.nodeRegion(doc, type); + Range range = doc.toRange(region); + Location location = new Location(doc.getUri(), range); + + return new AnnotationAttributeValue(type.getType().resolveBinding().getQualifiedName(), location); + } + else { + DocumentRegion region = ASTUtils.nodeRegion(doc, expression); + Range range = doc.toRange(region); + Location location = new Location(doc.getUri(), range); + + return new AnnotationAttributeValue(expression.toString(), location); + } + } + public static ASTNode getNearestAnnotationParent(ASTNode node) { while (node != null && !(node instanceof Annotation)) { node = node.getParent(); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJava.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJava.java index 22b0590076..a4a45d5c58 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJava.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJava.java @@ -90,7 +90,7 @@ public static enum SCAN_PASS { // whenever the implementation of the indexer changes in a way that the stored data in the cache is no longer valid, // we need to change the generation - this will result in a re-indexing due to no up-to-date cache data being found - private static final String GENERATION = "GEN-6"; + private static final String GENERATION = "GEN-7"; private static final String INDEX_FILES_TASK_ID = "index-java-source-files-task-"; private static final String SYMBOL_KEY = "symbols"; diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/test/SpringMetamodelIndexTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/test/SpringMetamodelIndexTest.java index 5d507d405e..7c7b03694d 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/test/SpringMetamodelIndexTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/test/SpringMetamodelIndexTest.java @@ -30,6 +30,7 @@ import org.junit.jupiter.api.Test; import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.boot.index.cache.IndexCacheOnDisc; +import org.springframework.ide.vscode.commons.protocol.spring.AnnotationAttributeValue; import org.springframework.ide.vscode.commons.protocol.spring.AnnotationMetadata; import org.springframework.ide.vscode.commons.protocol.spring.Bean; import org.springframework.ide.vscode.commons.protocol.spring.DefaultValues; @@ -43,7 +44,7 @@ public class SpringMetamodelIndexTest { private Set emptySupertypes = new HashSet<>(); private AnnotationMetadata[] emptyAnnotations = new AnnotationMetadata[0]; private AnnotationMetadata[] emptyInjectionAnnotations = new AnnotationMetadata[0]; - private Map emptyAnnotationAttributes = new LinkedHashMap<>(); + private Map emptyAnnotationAttributes = new LinkedHashMap<>(); private Location locationForDoc1 = new Location("docURI1", new Range(new Position(1, 1), new Position(1, 10))); private Location locationForDoc2 = new Location("docURI2", new Range(new Position(2, 1), new Position(2, 10))); @@ -225,8 +226,24 @@ void testRemoveAllBeansForSpecificDocument() { @Test void testOverallSerializeDeserializeBeans() { + Location locationForAnnotation1 = new Location("docURI1", new Range(new Position(100, 5), new Position(100, 20))); + Location locationForAnnotation2 = new Location("docURI1", new Range(new Position(200, 10), new Position(200, 40))); + + Location locationForAttribute1 = new Location("docURI1", new Range(new Position(1000, 100), new Position(1000, 400))); + Location locationForAttribute2 = new Location("docURI1", new Range(new Position(2000, 200), new Position(2000, 800))); + Location locationForAttribute3 = new Location("docURI1", new Range(new Position(3000, 400), new Position(3000, 1600))); + + AnnotationAttributeValue annotationAttributeValue1 = new AnnotationAttributeValue("attribute1", locationForAttribute1); + AnnotationAttributeValue annotationAttributeValue2 = new AnnotationAttributeValue("attribute2", locationForAttribute2); + AnnotationAttributeValue annotationAttributeValue3 = new AnnotationAttributeValue("attribute3", locationForAttribute3); + InjectionPoint point1 = new InjectionPoint("point1", "point1-type", locationForDoc2, new AnnotationMetadata[] - {new AnnotationMetadata("anno1", false, emptyAnnotationAttributes),new AnnotationMetadata("anno2", false, emptyAnnotationAttributes)}); + { + new AnnotationMetadata("anno1", false, locationForAnnotation1, Map.of( + "attribute1", new AnnotationAttributeValue[] {annotationAttributeValue1, annotationAttributeValue2}, + "attribute2", new AnnotationAttributeValue[] {annotationAttributeValue3})), + new AnnotationMetadata("anno2", false, locationForAnnotation2, emptyAnnotationAttributes) + }); InjectionPoint point2 = new InjectionPoint("point2", "point2-type", locationForDoc1, null); @@ -250,6 +267,7 @@ void testOverallSerializeDeserializeBeans() { assertEquals("point2", points[1].getName()); assertEquals("point2-type", points[1].getType()); assertEquals(locationForDoc1, points[1].getLocation()); + assertSame(DefaultValues.EMPTY_ANNOTATIONS, points[1].getAnnotations()); assertTrue(deserializedBean.isTypeCompatibleWith("supertype1")); assertTrue(deserializedBean.isTypeCompatibleWith("supertype2")); @@ -259,6 +277,21 @@ void testOverallSerializeDeserializeBeans() { assertEquals("anno1", points[0].getAnnotations()[0].getAnnotationType()); assertEquals("anno2", points[0].getAnnotations()[1].getAnnotationType()); + assertEquals(locationForAnnotation1, points[0].getAnnotations()[0].getLocation()); + assertEquals(locationForAnnotation2, points[0].getAnnotations()[1].getLocation()); + + Map attributes = points[0].getAnnotations()[0].getAttributes(); + assertEquals(2, attributes.get("attribute1").length); + assertEquals(1, attributes.get("attribute2").length); + + assertEquals(annotationAttributeValue1, attributes.get("attribute1")[0]); + assertEquals(annotationAttributeValue2, attributes.get("attribute1")[1]); + assertEquals(annotationAttributeValue3, attributes.get("attribute2")[0]); + + assertEquals(locationForAttribute1, attributes.get("attribute1")[0].getLocation()); + assertEquals(locationForAttribute2, attributes.get("attribute1")[1].getLocation()); + assertEquals(locationForAttribute3, attributes.get("attribute2")[0].getLocation()); + assertEquals(0, points[1].getAnnotations().length); } diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/test/SpringMetamodelIndexerBeansTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/test/SpringMetamodelIndexerBeansTest.java index b39e173324..bebafeafb6 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/test/SpringMetamodelIndexerBeansTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/index/test/SpringMetamodelIndexerBeansTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2023 VMware, Inc. + * Copyright (c) 2023, 2024 VMware, 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 @@ -36,6 +36,7 @@ import org.springframework.ide.vscode.boot.bootiful.SymbolProviderTestConf; import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.commons.protocol.spring.AnnotationAttributeValue; import org.springframework.ide.vscode.commons.protocol.spring.AnnotationMetadata; import org.springframework.ide.vscode.commons.protocol.spring.Bean; import org.springframework.ide.vscode.commons.protocol.spring.DefaultValues; @@ -277,22 +278,41 @@ void testAnnotationMetadataFromBeanMethodBean() { assertEquals("org.springframework.context.annotation.Bean", beanAnnotation.getAnnotationType()); assertFalse(annotations[0].isMetaAnnotation()); assertEquals(0, annotations[0].getAttributes().size()); + assertEquals(new Location(mainClassBean.getLocation().getUri(), new Range(new Position(25, 1), new Position(25, 6))), beanAnnotation.getLocation()); AnnotationMetadata qualifierAnnotation = annotations[1]; assertEquals("org.springframework.beans.factory.annotation.Qualifier", qualifierAnnotation.getAnnotationType()); - Map attributes = qualifierAnnotation.getAttributes(); + assertEquals(new Location(mainClassBean.getLocation().getUri(), new Range(new Position(26, 1), new Position(26, 25))), qualifierAnnotation.getLocation()); + + Map attributes = qualifierAnnotation.getAttributes(); assertEquals(1, attributes.size()); assertTrue(attributes.containsKey("value")); - assertArrayEquals(new String[] {"qualifier1"}, attributes.get("value")); + + AnnotationAttributeValue[] valueAttributes = attributes.get("value"); + assertEquals(1, valueAttributes.length); + assertEquals("qualifier1", valueAttributes[0].getName()); + Location expectedValueAttributeLocation = new Location(mainClassBean.getLocation().getUri(), new Range(new Position(26, 12), new Position(26, 24))); + assertEquals(expectedValueAttributeLocation, valueAttributes[0].getLocation()); AnnotationMetadata profileAnnotation = annotations[2]; assertEquals("org.springframework.context.annotation.Profile", profileAnnotation.getAnnotationType()); assertFalse(profileAnnotation.isMetaAnnotation()); + assertEquals(new Location(mainClassBean.getLocation().getUri(), new Range(new Position(27, 1), new Position(27, 41))), profileAnnotation.getLocation()); attributes = profileAnnotation.getAttributes(); assertEquals(1, attributes.size()); - assertTrue(attributes.containsKey("value")); - assertArrayEquals(new String[] {"testprofile","testprofile2"}, attributes.get("value")); + + AnnotationAttributeValue[] profileValueAttributes = attributes.get("value"); + assertEquals(2, profileValueAttributes.length); + + assertEquals("testprofile", profileValueAttributes[0].getName()); + assertEquals("testprofile2", profileValueAttributes[1].getName()); + + Location profileValueLocation1 = new Location(mainClassBean.getLocation().getUri(), new Range(new Position(27, 11), new Position(27, 24))); + Location profileValueLocation2 = new Location(mainClassBean.getLocation().getUri(), new Range(new Position(27, 25), new Position(27, 39))); + + assertEquals(profileValueLocation1, profileValueAttributes[0].getLocation()); + assertEquals(profileValueLocation2, profileValueAttributes[1].getLocation()); } @Test @@ -309,11 +329,18 @@ void testAnnotationMetadataFromBeanMethodWithInjectionPointAnnotations() { AnnotationMetadata dependsonAnnotation = annotations[1]; assertEquals("org.springframework.context.annotation.Bean", beanAnnotation.getAnnotationType()); + assertEquals(new Location(bean.getLocation().getUri(), new Range(new Position(16, 1), new Position(16, 6))), beanAnnotation.getLocation()); + assertEquals("org.springframework.context.annotation.DependsOn", dependsonAnnotation.getAnnotationType()); - Map dependsOnAttributes = dependsonAnnotation.getAttributes(); + Map dependsOnAttributes = dependsonAnnotation.getAttributes(); assertEquals(1, dependsOnAttributes.size()); - assertArrayEquals(new String[] {"bean1", "bean2"}, dependsOnAttributes.get("value")); + AnnotationAttributeValue[] dependsOnValueAttribute = dependsOnAttributes.get("value"); + assertEquals(2, dependsOnValueAttribute.length); + assertEquals("bean1", dependsOnValueAttribute[0].getName()); + assertEquals("bean2", dependsOnValueAttribute[1].getName()); + assertEquals(new Location(bean.getLocation().getUri(), new Range(new Position(17, 13), new Position(17, 20))), dependsOnValueAttribute[0].getLocation()); + assertEquals(new Location(bean.getLocation().getUri(), new Range(new Position(17, 22), new Position(17, 29))), dependsOnValueAttribute[1].getLocation()); InjectionPoint[] injectionPoints = bean.getInjectionPoints(); assertEquals(2, injectionPoints.length); @@ -325,14 +352,20 @@ void testAnnotationMetadataFromBeanMethodWithInjectionPointAnnotations() { assertEquals(1, annotationsFromPoint2.length); assertEquals("org.springframework.beans.factory.annotation.Qualifier", annotationsFromPoint1[0].getAnnotationType()); - Map attributesFromParam1 = annotationsFromPoint1[0].getAttributes(); + Map attributesFromParam1 = annotationsFromPoint1[0].getAttributes(); assertEquals(1, attributesFromParam1.size()); - assertArrayEquals(new String[] {"q1"}, attributesFromParam1.get("value")); + AnnotationAttributeValue[] qualifier1ValueAttributes = attributesFromParam1.get("value"); + assertEquals(1, qualifier1ValueAttributes.length); + assertEquals("q1", qualifier1ValueAttributes[0].getName()); + assertEquals(new Location(bean.getLocation().getUri(), new Range(new Position(18, 84), new Position(18, 88))), qualifier1ValueAttributes[0].getLocation()); assertEquals("org.springframework.beans.factory.annotation.Qualifier", annotationsFromPoint2[0].getAnnotationType()); - Map attributesFromParam2 = annotationsFromPoint2[0].getAttributes(); + Map attributesFromParam2 = annotationsFromPoint2[0].getAttributes(); assertEquals(1, attributesFromParam2.size()); - assertArrayEquals(new String[] {"q2"}, attributesFromParam2.get("value")); + AnnotationAttributeValue[] qualifier2ValueAttributes = attributesFromParam2.get("value"); + assertEquals(1, qualifier2ValueAttributes.length); + assertEquals("q2", qualifier2ValueAttributes[0].getName()); + assertEquals(new Location(bean.getLocation().getUri(), new Range(new Position(18, 119), new Position(18, 123))), qualifier2ValueAttributes[0].getLocation()); } @Test @@ -359,13 +392,26 @@ void testAnnotationMetadataFromComponentClass() { assertEquals("org.springframework.context.annotation.ImportRuntimeHints", runtimeHintsAnnotation.getAnnotationType()); assertEquals("org.springframework.stereotype.Component", componentMetaAnnotation.getAnnotationType()); - Map qualifierAttributes = qualifierAnnotation.getAttributes(); + Map qualifierAttributes = qualifierAnnotation.getAttributes(); assertEquals(1, qualifierAttributes.size()); - assertArrayEquals(new String[] {"qualifier"}, qualifierAttributes.get("value")); - Map runtimeHintsAttributes = runtimeHintsAnnotation.getAttributes(); + AnnotationAttributeValue[] valueAttributes = qualifierAttributes.get("value"); + assertNotNull(valueAttributes); + assertEquals(1, valueAttributes.length); + + Location qualifierValueLocation = new Location(bean.getLocation().getUri(), new Range(new Position(12, 11), new Position(12, 22))); + assertEquals("qualifier", valueAttributes[0].getName()); + assertEquals(qualifierValueLocation, valueAttributes[0].getLocation()); + + Map runtimeHintsAttributes = runtimeHintsAnnotation.getAttributes(); assertEquals(1, runtimeHintsAttributes.size()); - assertArrayEquals(new String[] {"org.test.injections.DummyRuntimeHintsRegistrar"}, runtimeHintsAttributes.get("value")); + AnnotationAttributeValue[] runtimeHintsValueAttribute = runtimeHintsAttributes.get("value"); + assertNotNull(runtimeHintsValueAttribute); + assertEquals(1, runtimeHintsValueAttribute.length); + + Location runtimeHintsValueLocation = new Location(bean.getLocation().getUri(), new Range(new Position(13, 20), new Position(13, 52))); + assertEquals("org.test.injections.DummyRuntimeHintsRegistrar", runtimeHintsValueAttribute[0].getName()); + assertEquals(runtimeHintsValueLocation, runtimeHintsValueAttribute[0].getLocation()); } @Test @@ -395,9 +441,11 @@ void testAnnotationMetadataFromInjectionPointsFromAutowiredFields() { assertFalse(qualifierFromPoint2.isMetaAnnotation()); assertEquals(1, qualifierFromPoint2.getAttributes().size()); - Map qualifierAttributes = qualifierFromPoint2.getAttributes(); - assertEquals(1, qualifierAttributes.size()); - assertArrayEquals(new String[] {"qual1"}, qualifierAttributes.get("value")); + Map qualifierAttributes = qualifierFromPoint2.getAttributes(); + AnnotationAttributeValue[] qualifierAttributeValues = qualifierAttributes.get("value"); + assertEquals(1, qualifierAttributeValues.length); + assertEquals("qual1", qualifierAttributeValues[0].getName()); + assertEquals(new Location(beans[0].getLocation().getUri(), new Range(new Position(15, 12), new Position(15, 19))), qualifierAttributeValues[0].getLocation()); } @Test @@ -415,16 +463,26 @@ void testAnnotationMetadataFromSpringDataRepository() { assertEquals("org.springframework.beans.factory.annotation.Qualifier", qualifierAnnotation.getAnnotationType()); assertFalse(qualifierAnnotation.isMetaAnnotation()); - Map qualifierAttributes = qualifierAnnotation.getAttributes(); + Map qualifierAttributes = qualifierAnnotation.getAttributes(); assertEquals(1, qualifierAttributes.size()); - assertArrayEquals(new String[] {"repoQualifier"}, qualifierAttributes.get("value")); + AnnotationAttributeValue[] qualifierAttributeValues = qualifierAttributes.get("value"); + assertEquals(1, qualifierAttributeValues.length); + assertEquals("repoQualifier", qualifierAttributeValues[0].getName()); + assertEquals(new Location(beans[0].getLocation().getUri(), new Range(new Position(8, 11), new Position(8, 26))), qualifierAttributeValues[0].getLocation()); assertEquals("org.springframework.context.annotation.Profile", profileAnnotation.getAnnotationType()); assertFalse(profileAnnotation.isMetaAnnotation()); - Map profileAttributes = profileAnnotation.getAttributes(); + Map profileAttributes = profileAnnotation.getAttributes(); assertEquals(1, profileAttributes.size()); - assertArrayEquals(new String[] {"prof1", "prof2"}, profileAttributes.get("value")); + AnnotationAttributeValue[] profileAttributeValues = profileAttributes.get("value"); + assertEquals(2, profileAttributeValues.length); + + assertEquals("prof1", profileAttributeValues[0].getName()); + assertEquals(new Location(beans[0].getLocation().getUri(), new Range(new Position(9, 10), new Position(9, 17))), profileAttributeValues[0].getLocation()); + + assertEquals("prof2", profileAttributeValues[1].getName()); + assertEquals(new Location(beans[0].getLocation().getUri(), new Range(new Position(9, 19), new Position(9, 26))), profileAttributeValues[1].getLocation()); } diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/NamedCompletionProviderTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/NamedCompletionProviderTest.java index 77c9ee2512..31afb3b132 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/NamedCompletionProviderTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/NamedCompletionProviderTest.java @@ -36,6 +36,7 @@ import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.commons.protocol.spring.AnnotationAttributeValue; import org.springframework.ide.vscode.commons.protocol.spring.AnnotationMetadata; import org.springframework.ide.vscode.commons.protocol.spring.Bean; import org.springframework.ide.vscode.commons.util.text.LanguageId; @@ -79,8 +80,8 @@ public void setup() throws Exception { indexedBeans = springIndex.getBeansOfProject(project.getElementName()); tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString(); - AnnotationMetadata annotationBean1 = new AnnotationMetadata("jakarta.inject.Named", false, Map.of("value", new String[] {"named1"})); - AnnotationMetadata annotationBean2 = new AnnotationMetadata("jakarta.inject.Named", false, Map.of("value", new String[] {"named2"})); + AnnotationMetadata annotationBean1 = new AnnotationMetadata("jakarta.inject.Named", false, null, Map.of("value", new AnnotationAttributeValue[] {new AnnotationAttributeValue("named1", null)})); + AnnotationMetadata annotationBean2 = new AnnotationMetadata("jakarta.inject.Named", false, null, Map.of("value", new AnnotationAttributeValue[] {new AnnotationAttributeValue("named2", null)})); bean1 = new Bean("bean1", "type1", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, new AnnotationMetadata[] {annotationBean1}); bean2 = new Bean("bean2", "type2", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, new AnnotationMetadata[] {annotationBean2}); diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/ProfileCompletionProviderTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/ProfileCompletionProviderTest.java index d5383bae20..aed47ab58f 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/ProfileCompletionProviderTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/ProfileCompletionProviderTest.java @@ -36,6 +36,7 @@ import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.commons.protocol.spring.AnnotationAttributeValue; import org.springframework.ide.vscode.commons.protocol.spring.AnnotationMetadata; import org.springframework.ide.vscode.commons.protocol.spring.Bean; import org.springframework.ide.vscode.commons.util.text.LanguageId; @@ -80,8 +81,8 @@ public void setup() throws Exception { indexedBeans = springIndex.getBeansOfProject(project.getElementName()); tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString(); - AnnotationMetadata annotationBean1 = new AnnotationMetadata("org.springframework.context.annotation.Profile", false, Map.of("value", new String[] {"prof1", "prof2"})); - AnnotationMetadata annotationBean2 = new AnnotationMetadata("org.springframework.context.annotation.Profile", false, Map.of("value", new String[] {"prof3"})); + AnnotationMetadata annotationBean1 = new AnnotationMetadata("org.springframework.context.annotation.Profile", false, null, Map.of("value", new AnnotationAttributeValue[] {new AnnotationAttributeValue("prof1", null), new AnnotationAttributeValue("prof2", null)})); + AnnotationMetadata annotationBean2 = new AnnotationMetadata("org.springframework.context.annotation.Profile", false, null, Map.of("value", new AnnotationAttributeValue[] {new AnnotationAttributeValue("prof3", null)})); bean1 = new Bean("bean1", "type1", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, new AnnotationMetadata[] {annotationBean1}); bean2 = new Bean("bean2", "type2", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, new AnnotationMetadata[] {annotationBean2}); diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/QualifierCompletionProviderTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/QualifierCompletionProviderTest.java index 19a673d02b..044f7b33f0 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/QualifierCompletionProviderTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/QualifierCompletionProviderTest.java @@ -37,6 +37,7 @@ import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.commons.protocol.spring.AnnotationAttributeValue; import org.springframework.ide.vscode.commons.protocol.spring.AnnotationMetadata; import org.springframework.ide.vscode.commons.protocol.spring.Bean; import org.springframework.ide.vscode.commons.util.text.LanguageId; @@ -80,8 +81,8 @@ public void setup() throws Exception { indexedBeans = springIndex.getBeansOfProject(project.getElementName()); tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString(); - AnnotationMetadata annotationBean1 = new AnnotationMetadata("org.springframework.beans.factory.annotation.Qualifier", false, Map.of("value", new String[] {"quali1"})); - AnnotationMetadata annotationBean2 = new AnnotationMetadata("org.springframework.beans.factory.annotation.Qualifier", false, Map.of("value", new String[] {"quali2"})); + AnnotationMetadata annotationBean1 = new AnnotationMetadata("org.springframework.beans.factory.annotation.Qualifier", false, null, Map.of("value", new AnnotationAttributeValue[] {new AnnotationAttributeValue("quali1", null)})); + AnnotationMetadata annotationBean2 = new AnnotationMetadata("org.springframework.beans.factory.annotation.Qualifier", false, null, Map.of("value", new AnnotationAttributeValue[] {new AnnotationAttributeValue("quali2", null)})); bean1 = new Bean("bean1", "type1", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, new AnnotationMetadata[] {annotationBean1}); bean2 = new Bean("bean2", "type2", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, new AnnotationMetadata[] {annotationBean2}); diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/ResourceCompletionProviderTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/ResourceCompletionProviderTest.java index 693ecfd2ae..76b868060c 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/ResourceCompletionProviderTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/ResourceCompletionProviderTest.java @@ -36,6 +36,7 @@ import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; +import org.springframework.ide.vscode.commons.protocol.spring.AnnotationAttributeValue; import org.springframework.ide.vscode.commons.protocol.spring.AnnotationMetadata; import org.springframework.ide.vscode.commons.protocol.spring.Bean; import org.springframework.ide.vscode.commons.util.text.LanguageId; @@ -79,8 +80,8 @@ public void setup() throws Exception { indexedBeans = springIndex.getBeansOfProject(project.getElementName()); tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString(); - AnnotationMetadata annotationBean1 = new AnnotationMetadata("org.springframework.beans.factory.annotation.Qualifier", false, Map.of("value", new String[] {"quali1"})); - AnnotationMetadata annotationBean2 = new AnnotationMetadata("org.springframework.beans.factory.annotation.Qualifier", false, Map.of("value", new String[] {"quali2"})); + AnnotationMetadata annotationBean1 = new AnnotationMetadata("org.springframework.beans.factory.annotation.Qualifier", false, null, Map.of("value", new AnnotationAttributeValue[] {new AnnotationAttributeValue("quali1", null)})); + AnnotationMetadata annotationBean2 = new AnnotationMetadata("org.springframework.beans.factory.annotation.Qualifier", false, null, Map.of("value", new AnnotationAttributeValue[] {new AnnotationAttributeValue("quali2", null)})); bean1 = new Bean("bean1", "type1", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, new AnnotationMetadata[] {annotationBean1}); bean2 = new Bean("bean2", "type2", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, new AnnotationMetadata[] {annotationBean2}); diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/SpringIndexerJakartaJavaxAnnotationsTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/SpringIndexerJakartaJavaxAnnotationsTest.java index 1b1179a53a..64a1e63ec5 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/SpringIndexerJakartaJavaxAnnotationsTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/SpringIndexerJakartaJavaxAnnotationsTest.java @@ -67,7 +67,8 @@ void testScanSimpleConfigurationClass() throws Exception { String docUri = directory.toPath().resolve("src/main/java/org/test/jakarta/SimpleMovieLister.java").toUri().toString(); SpringIndexerHarness.assertDocumentSymbols(indexer, docUri, - SpringIndexerHarness.symbol("@Resource", "@Resource"), + SpringIndexerHarness.symbol("@Component", "@+ 'simpleMovieLister' (@Component) SimpleMovieLister"), + SpringIndexerHarness.symbol("@Resource", "@Resource"), SpringIndexerHarness.symbol("@Resource", "@Resource"), SpringIndexerHarness.symbol("@Resource(name=\"myMovieFinder\")", "@Resource(name=\"myMovieFinder\")"), SpringIndexerHarness.symbol("@Inject", "@Inject"), diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-annotation-symbols-for-jakarta-javax/src/main/java/org/test/jakarta/SimpleMovieLister.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-annotation-symbols-for-jakarta-javax/src/main/java/org/test/jakarta/SimpleMovieLister.java index 358c38e6fa..8ceb18e668 100644 --- a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-annotation-symbols-for-jakarta-javax/src/main/java/org/test/jakarta/SimpleMovieLister.java +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-annotation-symbols-for-jakarta-javax/src/main/java/org/test/jakarta/SimpleMovieLister.java @@ -6,6 +6,9 @@ import jakarta.inject.Inject; import jakarta.inject.Named; +import org.springframework.stereotype.Component; + +@Component public class SimpleMovieLister { @Resource diff --git a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-annotation-symbols-for-jakarta-javax/src/main/java/org/test/javax/SimpleMovieLister.java b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-annotation-symbols-for-jakarta-javax/src/main/java/org/test/javax/SimpleMovieLister.java index 464d2957d3..1ce3d7e6ae 100644 --- a/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-annotation-symbols-for-jakarta-javax/src/main/java/org/test/javax/SimpleMovieLister.java +++ b/headless-services/spring-boot-language-server/src/test/resources/test-projects/test-annotation-symbols-for-jakarta-javax/src/main/java/org/test/javax/SimpleMovieLister.java @@ -4,8 +4,11 @@ import javax.inject.Inject; import javax.inject.Named; +import org.springframework.stereotype.Component; + import org.test.MovieFinder; +@Component public class SimpleMovieLister { @Resource