GH-1400: include more precise location information for annotations and annotation attribute values in spring index

This commit is contained in:
Martin Lippert
2024-11-12 12:29:57 +01:00
parent 8de5ea4229
commit e52ae1890a
20 changed files with 371 additions and 106 deletions

View File

@@ -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);
}
}

View File

@@ -12,6 +12,8 @@ package org.springframework.ide.vscode.commons.protocol.spring;
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<String, String[]> attributes;
private final Location location;
private final Map<String, AnnotationAttributeValue[]> attributes;
public AnnotationMetadata(String annotationType, boolean isMetaAnnotation, Map<String, String[]> attributes) {
public AnnotationMetadata(String annotationType, boolean isMetaAnnotation, Location location, Map<String, AnnotationAttributeValue[]> attributes) {
this.annotationType = annotationType;
this.isMetaAnnotation = isMetaAnnotation;
this.location = location;
this.attributes = attributes;
}
@@ -34,9 +38,13 @@ public class AnnotationMetadata {
public boolean isMetaAnnotation() {
return isMetaAnnotation;
}
public Map<String, String[]> getAttributes() {
return attributes;
public Location getLocation() {
return location;
}
public Map<String, AnnotationAttributeValue[]> getAttributes() {
return attributes;
}
}

View File

@@ -96,16 +96,8 @@ public class BeansSymbolProvider extends AbstractSymbolProvider {
ASTUtils.findSupertypes(beanType, supertypes);
Collection<Annotation> 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));

View File

@@ -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 @@ public class ComponentSymbolProvider extends AbstractSymbolProvider {
Collection<Annotation> 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);

View File

@@ -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 @@ public class FeignClientSymbolProvider extends AbstractSymbolProvider {
Collection<Annotation> 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);

View File

@@ -54,7 +54,7 @@ public class NamedCompletionProvider implements AnnotationAttributeCompletionPro
.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<String> qualifiersFromInjectionPoints = Arrays.stream(beans)
// annotations from beans themselves
@@ -64,7 +64,7 @@ public class NamedCompletionProvider implements AnnotationAttributeCompletionPro
.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);
}

View File

@@ -52,7 +52,8 @@ public class ProfileCompletionProvider implements AnnotationAttributeCompletionP
.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<String> profilesFromInjectionPoints = Arrays.stream(beans)
// annotations from beans themselves
@@ -62,7 +63,8 @@ public class ProfileCompletionProvider implements AnnotationAttributeCompletionP
.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);
}

View File

@@ -64,7 +64,7 @@ public class QualifierCompletionProvider implements AnnotationAttributeCompletio
.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<String> qualifiersFromInjectionPoints = Arrays.stream(beans)
// annotations from beans themselves
@@ -74,7 +74,7 @@ public class QualifierCompletionProvider implements AnnotationAttributeCompletio
.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);
}

View File

@@ -78,10 +78,7 @@ public class DataRepositorySymbolProvider extends AbstractSymbolProvider {
String concreteRepoType = concreteBeanTypeBindung.getQualifiedName();
Collection<Annotation> 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);

View File

@@ -40,9 +40,10 @@ import org.eclipse.jdt.core.dom.NormalAnnotation;
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.slf4j.LoggerFactory;
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 class ASTUtils {
return getAnnotationsFromModifiers(methodDeclaration.getStructuralProperty(MethodDeclaration.MODIFIERS2_PROPERTY));
}
public static Collection<Annotation> getAnnotations(FieldDeclaration fieldDeclaration) {
return getAnnotationsFromModifiers(fieldDeclaration.getStructuralProperty(FieldDeclaration.MODIFIERS2_PROPERTY));
}
public static Collection<Annotation> getAnnotations(SingleVariableDeclaration variableDeclaration) {
return getAnnotationsFromModifiers(variableDeclaration.getStructuralProperty(SingleVariableDeclaration.MODIFIERS2_PROPERTY));
}
private static Collection<Annotation> getAnnotationsFromModifiers(Object modifiersObj) {
if (modifiersObj instanceof List) {
ImmutableList.Builder<Annotation> annotations = ImmutableList.builder();
@@ -285,7 +295,7 @@ public class ASTUtils {
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 class ASTUtils {
return edit != null ? Optional.of(edit) : Optional.empty();
}
public static Collection<InjectionPoint> getInjectionPointsFromMethodParams(MethodDeclaration method, TextDocument doc) throws BadLocationException {
List<InjectionPoint> 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<InjectionPoint> getInjectionPointsFromMethodParams(MethodDeclaration method, TextDocument doc) throws BadLocationException {
// List<InjectionPoint> 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<String> supertypesCollector) {
// interfaces
@@ -405,8 +415,8 @@ public class ASTUtils {
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 class ASTUtils {
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 class ASTUtils {
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 class ASTUtils {
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<Annotation> annotations, TextDocument doc) {
return annotations.stream()
.map(annotation -> createAnnotationMetadataFrom(annotation, doc))
.toArray(AnnotationMetadata[]::new);
}
public static Map<String, String[]> getAttributes(IAnnotationBinding t) {
Map<String, String[]> 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<String, String[]> getAttributes(IAnnotationBinding t) {
// Map<String, String[]> 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<String, AnnotationAttributeValue[]> getAttributes(Annotation annotation, TextDocument doc) throws BadLocationException {
Map<String, AnnotationAttributeValue[]> 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();

View File

@@ -90,7 +90,7 @@ public class SpringIndexerJava implements SpringIndexer {
// 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";

View File

@@ -30,6 +30,7 @@ import org.eclipse.lsp4j.Range;
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<String> emptySupertypes = new HashSet<>();
private AnnotationMetadata[] emptyAnnotations = new AnnotationMetadata[0];
private AnnotationMetadata[] emptyInjectionAnnotations = new AnnotationMetadata[0];
private Map<String, String[]> emptyAnnotationAttributes = new LinkedHashMap<>();
private Map<String, AnnotationAttributeValue[]> 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 @@ public class SpringMetamodelIndexTest {
@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 @@ public class SpringMetamodelIndexTest {
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 @@ public class SpringMetamodelIndexTest {
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<String, AnnotationAttributeValue[]> 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);
}

View File

@@ -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.BootLanguageServerTest;
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 @@ public class SpringMetamodelIndexerBeansTest {
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<String, String[]> attributes = qualifierAnnotation.getAttributes();
assertEquals(new Location(mainClassBean.getLocation().getUri(), new Range(new Position(26, 1), new Position(26, 25))), qualifierAnnotation.getLocation());
Map<String, AnnotationAttributeValue[]> 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 @@ public class SpringMetamodelIndexerBeansTest {
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<String, String[]> dependsOnAttributes = dependsonAnnotation.getAttributes();
Map<String, AnnotationAttributeValue[]> 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 @@ public class SpringMetamodelIndexerBeansTest {
assertEquals(1, annotationsFromPoint2.length);
assertEquals("org.springframework.beans.factory.annotation.Qualifier", annotationsFromPoint1[0].getAnnotationType());
Map<String, String[]> attributesFromParam1 = annotationsFromPoint1[0].getAttributes();
Map<String, AnnotationAttributeValue[]> 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<String, String[]> attributesFromParam2 = annotationsFromPoint2[0].getAttributes();
Map<String, AnnotationAttributeValue[]> 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 @@ public class SpringMetamodelIndexerBeansTest {
assertEquals("org.springframework.context.annotation.ImportRuntimeHints", runtimeHintsAnnotation.getAnnotationType());
assertEquals("org.springframework.stereotype.Component", componentMetaAnnotation.getAnnotationType());
Map<String, String[]> qualifierAttributes = qualifierAnnotation.getAttributes();
Map<String, AnnotationAttributeValue[]> qualifierAttributes = qualifierAnnotation.getAttributes();
assertEquals(1, qualifierAttributes.size());
assertArrayEquals(new String[] {"qualifier"}, qualifierAttributes.get("value"));
Map<String, String[]> 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<String, AnnotationAttributeValue[]> 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 @@ public class SpringMetamodelIndexerBeansTest {
assertFalse(qualifierFromPoint2.isMetaAnnotation());
assertEquals(1, qualifierFromPoint2.getAttributes().size());
Map<String, String[]> qualifierAttributes = qualifierFromPoint2.getAttributes();
assertEquals(1, qualifierAttributes.size());
assertArrayEquals(new String[] {"qual1"}, qualifierAttributes.get("value"));
Map<String, AnnotationAttributeValue[]> 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 @@ public class SpringMetamodelIndexerBeansTest {
assertEquals("org.springframework.beans.factory.annotation.Qualifier", qualifierAnnotation.getAnnotationType());
assertFalse(qualifierAnnotation.isMetaAnnotation());
Map<String, String[]> qualifierAttributes = qualifierAnnotation.getAttributes();
Map<String, AnnotationAttributeValue[]> 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<String, String[]> profileAttributes = profileAnnotation.getAttributes();
Map<String, AnnotationAttributeValue[]> 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());
}

View File

@@ -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.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 class NamedCompletionProviderTest {
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});

View File

@@ -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.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 class ProfileCompletionProviderTest {
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});

View File

@@ -37,6 +37,7 @@ import org.springframework.ide.vscode.boot.bootiful.SymbolProviderTestConf;
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 class QualifierCompletionProviderTest {
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});

View File

@@ -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.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 class ResourceCompletionProviderTest {
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});

View File

@@ -67,7 +67,8 @@ public class SpringIndexerJakartaJavaxAnnotationsTest {
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"),

View File

@@ -6,6 +6,9 @@ import jakarta.annotation.Resource;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import org.springframework.stereotype.Component;
@Component
public class SimpleMovieLister {
@Resource

View File

@@ -4,8 +4,11 @@ import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import org.springframework.stereotype.Component;
import org.test.MovieFinder;
@Component
public class SimpleMovieLister {
@Resource