added support for spring data repositories to spring model indexing
This commit is contained in:
@@ -30,11 +30,12 @@ public class SpringSymbolIndexerConfig {
|
||||
@Bean
|
||||
AnnotationHierarchyAwareLookup<SymbolProvider> symbolProviders(SymbolCache cache, SpringMetamodelIndex springIndex) {
|
||||
AnnotationHierarchyAwareLookup<SymbolProvider> providers = new AnnotationHierarchyAwareLookup<>();
|
||||
|
||||
RequestMappingSymbolProvider requestMappingSymbolProvider = new RequestMappingSymbolProvider();
|
||||
BeansSymbolProvider beansSymbolProvider = new BeansSymbolProvider(springIndex);
|
||||
ComponentSymbolProvider componentSymbolProvider = new ComponentSymbolProvider(springIndex);
|
||||
RestrictedDefaultSymbolProvider restrictedDefaultSymbolProvider = new RestrictedDefaultSymbolProvider();
|
||||
DataRepositorySymbolProvider dataRepositorySymbolProvider = new DataRepositorySymbolProvider();
|
||||
DataRepositorySymbolProvider dataRepositorySymbolProvider = new DataRepositorySymbolProvider(springIndex);
|
||||
WebfluxRouterSymbolProvider webfluxRouterSymbolProvider = new WebfluxRouterSymbolProvider();
|
||||
|
||||
providers.put(Annotations.SPRING_REQUEST_MAPPING, requestMappingSymbolProvider);
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.beans;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -26,9 +25,7 @@ import org.eclipse.jdt.core.dom.ParameterizedType;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.jdt.core.dom.Type;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.jdt.core.dom.VariableDeclaration;
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.SymbolKind;
|
||||
import org.eclipse.lsp4j.WorkspaceSymbol;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
@@ -73,11 +70,19 @@ public class BeansSymbolProvider extends AbstractSymbolProvider {
|
||||
|
||||
@Override
|
||||
protected void addSymbolsPass1(Annotation node, ITypeBinding annotationType, Collection<ITypeBinding> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
if (isMethodAbstract(node)) return;
|
||||
if (node == null) return;
|
||||
|
||||
ASTNode parent = node.getParent();
|
||||
if (parent == null || !(parent instanceof MethodDeclaration)) return;
|
||||
|
||||
MethodDeclaration method = (MethodDeclaration) parent;
|
||||
|
||||
if (isMethodAbstract(method)) return;
|
||||
|
||||
boolean isFunction = isFunctionBean(method);
|
||||
ITypeBinding beanType = getBeanType(method);
|
||||
String markerString = getAnnotations(method);
|
||||
|
||||
boolean isFunction = isFunctionBean(node);
|
||||
ITypeBinding beanType = getBeanType(node);
|
||||
String markerString = getAnnotations(node);
|
||||
for (Tuple2<String, DocumentRegion> nameAndRegion : getBeanNames(node, doc)) {
|
||||
try {
|
||||
Location location = new Location(doc.getUri(), doc.toRange(nameAndRegion.getT2()));
|
||||
@@ -92,7 +97,7 @@ public class BeansSymbolProvider extends AbstractSymbolProvider {
|
||||
|
||||
context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol));
|
||||
|
||||
InjectionPoint[] injectionPoints = findInjectionPoints(node, doc);
|
||||
InjectionPoint[] injectionPoints = ASTUtils.findInjectionPoints(method, doc);
|
||||
|
||||
Set<String> supertypes = new HashSet<>();
|
||||
ASTUtils.findSupertypes(beanType, supertypes);
|
||||
@@ -105,18 +110,6 @@ public class BeansSymbolProvider extends AbstractSymbolProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private InjectionPoint[] findInjectionPoints(Annotation node, TextDocument doc) throws BadLocationException {
|
||||
List<InjectionPoint> result = new ArrayList<>();
|
||||
|
||||
ASTNode parent = node.getParent();
|
||||
if (parent instanceof MethodDeclaration) {
|
||||
MethodDeclaration method = (MethodDeclaration) parent;
|
||||
result.addAll(ASTUtils.getInjectionPointsFromMethodParams(method, doc));
|
||||
}
|
||||
|
||||
return (InjectionPoint[]) result.toArray(new InjectionPoint[result.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addSymbolsPass1(TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
// this checks function beans that are defined as implementations of Function interfaces
|
||||
@@ -187,70 +180,51 @@ public class BeansSymbolProvider extends AbstractSymbolProvider {
|
||||
return literals.build();
|
||||
}
|
||||
|
||||
protected ITypeBinding getBeanType(Annotation node) {
|
||||
ASTNode parent = node.getParent();
|
||||
if (parent instanceof MethodDeclaration) {
|
||||
MethodDeclaration method = (MethodDeclaration) parent;
|
||||
return method.getReturnType2().resolveBinding();
|
||||
}
|
||||
return null;
|
||||
protected ITypeBinding getBeanType(MethodDeclaration method) {
|
||||
return method.getReturnType2().resolveBinding();
|
||||
}
|
||||
|
||||
private boolean isFunctionBean(Annotation node) {
|
||||
ASTNode parent = node.getParent();
|
||||
if (parent instanceof MethodDeclaration) {
|
||||
MethodDeclaration method = (MethodDeclaration) parent;
|
||||
String returnType = null;
|
||||
private boolean isFunctionBean(MethodDeclaration method) {
|
||||
String returnType = null;
|
||||
|
||||
if (method.getReturnType2().isParameterizedType()) {
|
||||
ParameterizedType paramType = (ParameterizedType) method.getReturnType2();
|
||||
Type type = paramType.getType();
|
||||
ITypeBinding typeBinding = type.resolveBinding();
|
||||
returnType = typeBinding.getBinaryName();
|
||||
}
|
||||
else {
|
||||
returnType = method.getReturnType2().resolveBinding().getQualifiedName();
|
||||
}
|
||||
|
||||
return FunctionUtils.FUNCTION_FUNCTION_TYPE.equals(returnType) || FunctionUtils.FUNCTION_CONSUMER_TYPE.equals(returnType)
|
||||
|| FunctionUtils.FUNCTION_SUPPLIER_TYPE.equals(returnType);
|
||||
if (method.getReturnType2().isParameterizedType()) {
|
||||
ParameterizedType paramType = (ParameterizedType) method.getReturnType2();
|
||||
Type type = paramType.getType();
|
||||
ITypeBinding typeBinding = type.resolveBinding();
|
||||
returnType = typeBinding.getBinaryName();
|
||||
}
|
||||
return false;
|
||||
else {
|
||||
returnType = method.getReturnType2().resolveBinding().getQualifiedName();
|
||||
}
|
||||
|
||||
return FunctionUtils.FUNCTION_FUNCTION_TYPE.equals(returnType) || FunctionUtils.FUNCTION_CONSUMER_TYPE.equals(returnType)
|
||||
|| FunctionUtils.FUNCTION_SUPPLIER_TYPE.equals(returnType);
|
||||
}
|
||||
|
||||
private String getAnnotations(Annotation node) {
|
||||
private String getAnnotations(MethodDeclaration method) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
ASTNode parent = node.getParent();
|
||||
if (parent instanceof MethodDeclaration) {
|
||||
MethodDeclaration method = (MethodDeclaration) parent;
|
||||
List<?> modifiers = method.modifiers();
|
||||
for (Object modifier : modifiers) {
|
||||
if (modifier instanceof Annotation) {
|
||||
Annotation annotation = (Annotation) modifier;
|
||||
IAnnotationBinding annotationBinding = annotation.resolveAnnotationBinding();
|
||||
String type = annotationBinding.getAnnotationType().getBinaryName();
|
||||
|
||||
List<?> modifiers = method.modifiers();
|
||||
for (Object modifier : modifiers) {
|
||||
if (modifier instanceof Annotation) {
|
||||
Annotation annotation = (Annotation) modifier;
|
||||
IAnnotationBinding annotationBinding = annotation.resolveAnnotationBinding();
|
||||
String type = annotationBinding.getAnnotationType().getBinaryName();
|
||||
|
||||
if (type != null && !Annotations.BEAN.equals(type)) {
|
||||
result.append(' ');
|
||||
result.append(annotation.toString());
|
||||
}
|
||||
if (type != null && !Annotations.BEAN.equals(type)) {
|
||||
result.append(' ');
|
||||
result.append(annotation.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private boolean isMethodAbstract(Annotation node) {
|
||||
if (node != null && node.getParent() != null && node.getParent() instanceof MethodDeclaration) {
|
||||
MethodDeclaration method = (MethodDeclaration) node.getParent();
|
||||
List<?> modifiers = method.modifiers();
|
||||
for (Object modifier : modifiers) {
|
||||
if (modifier instanceof Modifier && ((Modifier) modifier).isAbstract()) {
|
||||
return true;
|
||||
}
|
||||
private boolean isMethodAbstract(MethodDeclaration method) {
|
||||
List<?> modifiers = method.modifiers();
|
||||
for (Object modifier : modifiers) {
|
||||
if (modifier instanceof Modifier && ((Modifier) modifier).isAbstract()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -10,23 +10,15 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.beans;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration;
|
||||
import org.eclipse.jdt.core.dom.FieldDeclaration;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.SymbolKind;
|
||||
import org.eclipse.lsp4j.WorkspaceSymbol;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
@@ -42,7 +34,6 @@ import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
|
||||
import org.springframework.ide.vscode.boot.java.utils.CachedSymbol;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJavaContext;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.text.DocumentRegion;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
/**
|
||||
@@ -62,7 +53,7 @@ public class ComponentSymbolProvider extends AbstractSymbolProvider {
|
||||
@Override
|
||||
protected void addSymbolsPass1(Annotation node, ITypeBinding annotationType, Collection<ITypeBinding> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
try {
|
||||
if (!isOnAnnotationDeclaration(node)) {
|
||||
if (node != null && node.getParent() != null && node.getParent() instanceof TypeDeclaration) {
|
||||
EnhancedSymbolInformation enhancedSymbol = createSymbol(node, annotationType, metaAnnotations, doc);
|
||||
context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol));
|
||||
}
|
||||
@@ -77,8 +68,11 @@ public class ComponentSymbolProvider extends AbstractSymbolProvider {
|
||||
Collection<String> metaAnnotationNames = metaAnnotations.stream()
|
||||
.map(ITypeBinding::getName)
|
||||
.collect(Collectors.toList());
|
||||
String beanName = getBeanName(node);
|
||||
ITypeBinding beanType = getBeanType(node);
|
||||
|
||||
TypeDeclaration type = (TypeDeclaration) node.getParent();
|
||||
|
||||
String beanName = getBeanName(type);
|
||||
ITypeBinding beanType = getBeanType(type);
|
||||
|
||||
Location location = new Location(doc.getUri(), doc.toRange(node.getStartPosition(), node.getLength()));
|
||||
|
||||
@@ -94,7 +88,7 @@ public class ComponentSymbolProvider extends AbstractSymbolProvider {
|
||||
addon = new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(beanName, beanType.getQualifiedName())};
|
||||
}
|
||||
|
||||
InjectionPoint[] injectionPoints = findInjectionPoints(node, doc);
|
||||
InjectionPoint[] injectionPoints = ASTUtils.findInjectionPoints(type, doc);
|
||||
|
||||
Set<String> supertypes = new HashSet<>();
|
||||
ASTUtils.findSupertypes(beanType, supertypes);
|
||||
@@ -104,61 +98,6 @@ public class ComponentSymbolProvider extends AbstractSymbolProvider {
|
||||
return new EnhancedSymbolInformation(symbol, addon);
|
||||
}
|
||||
|
||||
private InjectionPoint[] findInjectionPoints(Annotation node, TextDocument doc) throws BadLocationException {
|
||||
List<InjectionPoint> result = new ArrayList<>();
|
||||
|
||||
ASTNode parent = node.getParent();
|
||||
if (parent instanceof TypeDeclaration) {
|
||||
TypeDeclaration type = (TypeDeclaration) parent;
|
||||
|
||||
MethodDeclaration[] methods = type.getMethods();
|
||||
for (MethodDeclaration method : methods) {
|
||||
if (method.isConstructor()) {
|
||||
result.addAll(ASTUtils.getInjectionPointsFromMethodParams(method, doc));
|
||||
}
|
||||
}
|
||||
|
||||
FieldDeclaration[] fields = type.getFields();
|
||||
for (FieldDeclaration field : fields) {
|
||||
|
||||
boolean autowiredField = false;
|
||||
|
||||
List<?> modifiers = field.modifiers();
|
||||
for (Object modifier : modifiers) {
|
||||
if (modifier instanceof Annotation) {
|
||||
Annotation annotation = (Annotation) modifier;
|
||||
|
||||
String qualifiedName = annotation.resolveTypeBinding().getQualifiedName();
|
||||
if (Annotations.AUTOWIRED.equals(qualifiedName)) {
|
||||
autowiredField = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (autowiredField) {
|
||||
List<?> fragments = field.fragments();
|
||||
for (Object fragment : fragments) {
|
||||
if (fragment instanceof VariableDeclarationFragment) {
|
||||
VariableDeclarationFragment varFragment = (VariableDeclarationFragment) fragment;
|
||||
String fieldName = varFragment.getName().toString();
|
||||
|
||||
DocumentRegion region = ASTUtils.nodeRegion(doc, varFragment.getName());
|
||||
Range range = doc.toRange(region);
|
||||
Location fieldLocation = new Location(doc.getUri(), range);
|
||||
|
||||
String fieldType = field.getType().resolveBinding().getQualifiedName();
|
||||
|
||||
result.add(new InjectionPoint(fieldName, fieldType, fieldLocation));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (InjectionPoint[]) result.toArray(new InjectionPoint[result.size()]);
|
||||
}
|
||||
|
||||
protected String beanLabel(String searchPrefix, String annotationTypeName, Collection<String> metaAnnotationNames, String beanName, String beanType) {
|
||||
StringBuilder symbolLabel = new StringBuilder();
|
||||
symbolLabel.append("@");
|
||||
@@ -186,34 +125,13 @@ public class ComponentSymbolProvider extends AbstractSymbolProvider {
|
||||
return symbolLabel.toString();
|
||||
}
|
||||
|
||||
private String getBeanName(Annotation node) {
|
||||
ASTNode parent = node.getParent();
|
||||
if (parent instanceof TypeDeclaration) {
|
||||
TypeDeclaration type = (TypeDeclaration) parent;
|
||||
|
||||
String beanName = type.getName().toString();
|
||||
return BeanUtils.getBeanNameFromType(beanName);
|
||||
}
|
||||
return null;
|
||||
private String getBeanName(TypeDeclaration type) {
|
||||
String beanName = type.getName().toString();
|
||||
return BeanUtils.getBeanNameFromType(beanName);
|
||||
}
|
||||
|
||||
private ITypeBinding getBeanType(Annotation node) {
|
||||
ASTNode parent = node.getParent();
|
||||
if (parent instanceof TypeDeclaration) {
|
||||
TypeDeclaration type = (TypeDeclaration) parent;
|
||||
return type.resolveBinding();
|
||||
}
|
||||
return null;
|
||||
private ITypeBinding getBeanType(TypeDeclaration type) {
|
||||
return type.resolveBinding();
|
||||
}
|
||||
|
||||
private boolean isOnAnnotationDeclaration(Annotation node) {
|
||||
ASTNode parent = node.getParent();
|
||||
if (parent != null && parent instanceof AnnotationTypeDeclaration) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.data;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.Location;
|
||||
@@ -18,6 +21,8 @@ import org.eclipse.lsp4j.WorkspaceSymbol;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.index.InjectionPoint;
|
||||
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
|
||||
import org.springframework.ide.vscode.boot.java.beans.BeanUtils;
|
||||
import org.springframework.ide.vscode.boot.java.beans.BeansSymbolAddOnInformation;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.AbstractSymbolProvider;
|
||||
@@ -39,22 +44,41 @@ import reactor.util.function.Tuples;
|
||||
public class DataRepositorySymbolProvider extends AbstractSymbolProvider {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DataRepositorySymbolProvider.class);
|
||||
private final SpringMetamodelIndex springIndex;
|
||||
|
||||
public DataRepositorySymbolProvider(SpringMetamodelIndex springIndex) {
|
||||
this.springIndex = springIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addSymbolsPass1(TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
// this checks spring data repository beans that are defined as extensions of the repository interface
|
||||
Tuple4<String, ITypeBinding, String, DocumentRegion> repositoryBean = getRepositoryBean(typeDeclaration, doc);
|
||||
|
||||
if (repositoryBean != null) {
|
||||
try {
|
||||
String beanName = repositoryBean.getT1();
|
||||
ITypeBinding beanType = repositoryBean.getT2();
|
||||
Location location = new Location(doc.getUri(), doc.toRange(repositoryBean.getT4()));
|
||||
|
||||
WorkspaceSymbol symbol = new WorkspaceSymbol(
|
||||
beanLabel(true, repositoryBean.getT1(), repositoryBean.getT2().getName(), repositoryBean.getT3()),
|
||||
beanLabel(true, beanName, beanType.getName(), repositoryBean.getT3()),
|
||||
SymbolKind.Interface,
|
||||
Either.forLeft(new Location(doc.getUri(), doc.toRange(repositoryBean.getT4()))));
|
||||
Either.forLeft(location));
|
||||
|
||||
SymbolAddOnInformation[] addon = new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(repositoryBean.getT1(), repositoryBean.getT2().getQualifiedName())};
|
||||
EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(symbol, addon);
|
||||
|
||||
context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol));
|
||||
|
||||
InjectionPoint[] injectionPoints = ASTUtils.findInjectionPoints(typeDeclaration, doc);
|
||||
|
||||
Set<String> supertypes = new HashSet<>();
|
||||
ASTUtils.findSupertypes(beanType, supertypes);
|
||||
|
||||
String concreteRepoType = typeDeclaration.resolveBinding().getQualifiedName();
|
||||
springIndex.registerBean(beanName, concreteRepoType, location, injectionPoints, (String[]) supertypes.toArray(new String[supertypes.size()]));
|
||||
|
||||
} catch (BadLocationException e) {
|
||||
log.error("error creating data repository symbol for a specific range", e);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
package org.springframework.ide.vscode.boot.java.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -24,6 +25,7 @@ import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.ArrayInitializer;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.Expression;
|
||||
import org.eclipse.jdt.core.dom.FieldDeclaration;
|
||||
import org.eclipse.jdt.core.dom.IBinding;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.IVariableBinding;
|
||||
@@ -37,6 +39,7 @@ import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
|
||||
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.VariableDeclarationFragment;
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.slf4j.Logger;
|
||||
@@ -381,5 +384,77 @@ public class ASTUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static InjectionPoint[] findInjectionPoints(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();
|
||||
String type = variable.resolveBinding().getType().getQualifiedName();
|
||||
|
||||
DocumentRegion region = ASTUtils.nodeRegion(doc, variable.getName());
|
||||
Range range = doc.toRange(region);
|
||||
|
||||
Location location = new Location(doc.getUri(), range);
|
||||
result.add(new InjectionPoint(name, type, location));
|
||||
}
|
||||
}
|
||||
return (InjectionPoint[]) result.toArray(new InjectionPoint[result.size()]);
|
||||
}
|
||||
|
||||
public static InjectionPoint[] findInjectionPoints(TypeDeclaration type, TextDocument doc) throws BadLocationException {
|
||||
List<InjectionPoint> result = new ArrayList<>();
|
||||
|
||||
MethodDeclaration[] methods = type.getMethods();
|
||||
for (MethodDeclaration method : methods) {
|
||||
if (method.isConstructor()) {
|
||||
result.addAll(Arrays.asList(ASTUtils.findInjectionPoints(method, doc)));
|
||||
}
|
||||
}
|
||||
|
||||
FieldDeclaration[] fields = type.getFields();
|
||||
for (FieldDeclaration field : fields) {
|
||||
|
||||
boolean autowiredField = false;
|
||||
|
||||
List<?> modifiers = field.modifiers();
|
||||
for (Object modifier : modifiers) {
|
||||
if (modifier instanceof Annotation) {
|
||||
Annotation annotation = (Annotation) modifier;
|
||||
|
||||
String qualifiedName = annotation.resolveTypeBinding().getQualifiedName();
|
||||
if (Annotations.AUTOWIRED.equals(qualifiedName)) {
|
||||
autowiredField = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (autowiredField) {
|
||||
List<?> fragments = field.fragments();
|
||||
for (Object fragment : fragments) {
|
||||
if (fragment instanceof VariableDeclarationFragment) {
|
||||
VariableDeclarationFragment varFragment = (VariableDeclarationFragment) fragment;
|
||||
String fieldName = varFragment.getName().toString();
|
||||
|
||||
DocumentRegion region = ASTUtils.nodeRegion(doc, varFragment.getName());
|
||||
Range range = doc.toRange(region);
|
||||
Location fieldLocation = new Location(doc.getUri(), range);
|
||||
|
||||
String fieldType = field.getType().resolveBinding().getQualifiedName();
|
||||
|
||||
result.add(new InjectionPoint(fieldName, fieldType, fieldLocation));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (InjectionPoint[]) result.toArray(new InjectionPoint[result.size()]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -87,24 +87,6 @@ public class SpringMetamodelIndexerBeansTest {
|
||||
assertEquals("org.test.BeanClass1", beans[0].getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBeansNameAndTypeFromComponentAnnotatedClassExists() {
|
||||
Bean[] beans = springIndex.getBeans("constructorInjectionService");
|
||||
|
||||
assertEquals(1, beans.length);
|
||||
assertEquals("constructorInjectionService", beans[0].getName());
|
||||
assertEquals("org.test.injections.ConstructorInjectionService", beans[0].getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBeansNameAndTypeFromConfigurationAnnotatedClassExists() {
|
||||
Bean[] beans = springIndex.getBeans("configurationWithoutInjection");
|
||||
|
||||
assertEquals(1, beans.length);
|
||||
assertEquals("configurationWithoutInjection", beans[0].getName());
|
||||
assertEquals("org.test.injections.ConfigurationWithoutInjection", beans[0].getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBeansDefintionLocationFromBeanAnnotatedMethod() {
|
||||
Bean[] beans = springIndex.getBeans("bean1");
|
||||
@@ -114,6 +96,15 @@ public class SpringMetamodelIndexerBeansTest {
|
||||
assertEquals(location, beans[0].getLocation());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBeansNameAndTypeFromComponentAnnotatedClassExists() {
|
||||
Bean[] beans = springIndex.getBeans("constructorInjectionService");
|
||||
|
||||
assertEquals(1, beans.length);
|
||||
assertEquals("constructorInjectionService", beans[0].getName());
|
||||
assertEquals("org.test.injections.ConstructorInjectionService", beans[0].getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBeansDefintionLocationFromComponentAnnotatedClass() {
|
||||
Bean[] beans = springIndex.getBeans("constructorInjectionService");
|
||||
@@ -123,6 +114,15 @@ public class SpringMetamodelIndexerBeansTest {
|
||||
assertEquals(location, beans[0].getLocation());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBeansNameAndTypeFromConfigurationAnnotatedClassExists() {
|
||||
Bean[] beans = springIndex.getBeans("configurationWithoutInjection");
|
||||
|
||||
assertEquals(1, beans.length);
|
||||
assertEquals("configurationWithoutInjection", beans[0].getName());
|
||||
assertEquals("org.test.injections.ConfigurationWithoutInjection", beans[0].getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBeansDefinitionLocationFromConfigurationAnnotatedClass() {
|
||||
Bean[] beans = springIndex.getBeans("configurationWithoutInjection");
|
||||
@@ -203,6 +203,18 @@ public class SpringMetamodelIndexerBeansTest {
|
||||
Location ip2Location = new Location(docUri, new Range(new Position(11, 31), new Position(11, 36)));
|
||||
assertEquals(ip2Location, injectionPoints[1].getLocation());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBeanFromSpringDataRepository() {
|
||||
Bean[] beans = springIndex.getBeans("customerRepository");
|
||||
|
||||
assertEquals(1, beans.length);
|
||||
assertEquals("customerRepository", beans[0].getName());
|
||||
assertEquals("org.test.springdata.CustomerRepository", beans[0].getType());
|
||||
|
||||
InjectionPoint[] injectionPoints = beans[0].getInjectionPoints();
|
||||
assertEquals(0, injectionPoints.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBeansWithSupertypes() {
|
||||
@@ -218,7 +230,8 @@ public class SpringMetamodelIndexerBeansTest {
|
||||
|
||||
assertFalse(beans[0].isTypeCompatibleWith("java.lang.String"));
|
||||
assertFalse(beans[0].isTypeCompatibleWith("java.util.Comparator"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -11,17 +11,22 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.7.8</version>
|
||||
<version>3.0.5</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<jakarta-servlet.version>5.0.0</jakarta-servlet.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>jakarta.persistence</groupId>
|
||||
<artifactId>jakarta.persistence-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
@@ -34,6 +39,15 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<!--
|
||||
<build>
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// tag::sample[]
|
||||
package org.test.springdata;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
|
||||
@Entity
|
||||
public class Customer extends Person {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
private boolean thisCustomerIsSpecial;//contains keyword in name
|
||||
|
||||
@ManyToOne
|
||||
private Employee responsibleEmployee;
|
||||
|
||||
protected Customer() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Customer(String firstName, String lastName, Employee responsibleEmployee) {
|
||||
super(firstName, lastName);
|
||||
this.responsibleEmployee = responsibleEmployee;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Customer [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", responsibleEmployee="
|
||||
+ responsibleEmployee + "]";
|
||||
}
|
||||
|
||||
// end::sample[]
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean isThisCustomerIsSpecial() {
|
||||
return thisCustomerIsSpecial;
|
||||
}
|
||||
|
||||
public Employee getResponsibleEmployee() {
|
||||
return responsibleEmployee;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.test.springdata;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
public interface CustomerRepository extends CrudRepository<Customer, Long> {
|
||||
|
||||
List<Customer> findByLastName(String lastName);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// tag::sample[]
|
||||
package org.test.springdata;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Employee extends Person {
|
||||
|
||||
@Id
|
||||
private Long socialSecurityNumber;
|
||||
|
||||
protected Employee() {
|
||||
}
|
||||
|
||||
public Employee(long socialSecurityNumber, String firstName, String lastName) {
|
||||
super(firstName, lastName);
|
||||
this.socialSecurityNumber = socialSecurityNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Employee[socialSecurityNumber=%d, firstName='%s', lastName='%s']".formatted(
|
||||
socialSecurityNumber, firstName, lastName);
|
||||
}
|
||||
|
||||
// end::sample[]
|
||||
|
||||
public Long getSocialSecurityNumber() {
|
||||
return socialSecurityNumber;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.test.springdata;
|
||||
|
||||
public class Person {
|
||||
|
||||
protected String firstName;
|
||||
protected String lastName;
|
||||
|
||||
protected Person() {
|
||||
|
||||
}
|
||||
|
||||
public Person(String firstName, String lastName) {
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user