GH-1462: add event listener index elements for interface implementations without component annotation
This commit is contained in:
@@ -78,6 +78,23 @@ public class SpringMetamodelIndex {
|
||||
project.removeDocument(docURI);
|
||||
}
|
||||
}
|
||||
|
||||
public DocumentElement getDocument(String docURI) {
|
||||
ArrayDeque<SpringIndexElement> elementsToVisit = new ArrayDeque<>();
|
||||
elementsToVisit.addAll(this.projectRootElements.values());
|
||||
|
||||
while (!elementsToVisit.isEmpty()) {
|
||||
SpringIndexElement element = elementsToVisit.pop();
|
||||
|
||||
if (element instanceof DocumentElement doc && doc.getDocURI().equals(docURI)) {
|
||||
return doc;
|
||||
}
|
||||
|
||||
elementsToVisit.addAll(element.getChildren());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Bean[] getBeans() {
|
||||
List<Bean> result = new ArrayList<>();
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
|
||||
import org.springframework.ide.vscode.boot.java.events.EventListenerIndexElement;
|
||||
import org.springframework.ide.vscode.boot.java.events.EventPublisherIndexElement;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.AbstractSymbolProvider;
|
||||
@@ -131,7 +132,7 @@ public class ComponentSymbolProvider extends AbstractSymbolProvider {
|
||||
Collection<Annotation> annotationsOnHandleEventMethod = ASTUtils.getAnnotations(handleEventMethod);
|
||||
AnnotationMetadata[] handleEventMethodAnnotations = ASTUtils.getAnnotationsMetadata(annotationsOnHandleEventMethod, doc);
|
||||
|
||||
EventListenerIndexElement eventElement = new EventListenerIndexElement(eventTypeFq, handleMethodLocation, handleEventMethodAnnotations);
|
||||
EventListenerIndexElement eventElement = new EventListenerIndexElement(eventTypeFq, handleMethodLocation, beanType.getQualifiedName(), handleEventMethodAnnotations);
|
||||
beanDefinition.addChild(eventElement);
|
||||
}
|
||||
}
|
||||
@@ -198,6 +199,40 @@ public class ComponentSymbolProvider extends AbstractSymbolProvider {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addSymbolsPass1(TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
// event listener - create child element, if necessary
|
||||
try {
|
||||
ITypeBinding typeBinding = typeDeclaration.resolveBinding();
|
||||
if (typeBinding == null) return;
|
||||
|
||||
ITypeBinding inTypeHierarchy = ASTUtils.findInTypeHierarchy(typeDeclaration, doc, typeBinding, Set.of(Annotations.APPLICATION_LISTENER));
|
||||
if (inTypeHierarchy == null) return;
|
||||
|
||||
MethodDeclaration handleEventMethod = findHandleEventMethod(typeDeclaration);
|
||||
if (handleEventMethod == null) return;
|
||||
|
||||
IMethodBinding methodBinding = handleEventMethod.resolveBinding();
|
||||
ITypeBinding[] parameterTypes = methodBinding.getParameterTypes();
|
||||
if (parameterTypes != null && parameterTypes.length == 1) {
|
||||
|
||||
ITypeBinding eventType = parameterTypes[0];
|
||||
String eventTypeFq = eventType.getQualifiedName();
|
||||
|
||||
DocumentRegion nodeRegion = ASTUtils.nodeRegion(doc, handleEventMethod.getName());
|
||||
Location handleMethodLocation = new Location(doc.getUri(), nodeRegion.asRange());
|
||||
|
||||
Collection<Annotation> annotationsOnHandleEventMethod = ASTUtils.getAnnotations(handleEventMethod);
|
||||
AnnotationMetadata[] handleEventMethodAnnotations = ASTUtils.getAnnotationsMetadata(annotationsOnHandleEventMethod, doc);
|
||||
|
||||
EventListenerIndexElement eventElement = new EventListenerIndexElement(eventTypeFq, handleMethodLocation, typeBinding.getQualifiedName(), handleEventMethodAnnotations);
|
||||
context.getBeans().add(new CachedBean(doc.getUri(), eventElement));
|
||||
}
|
||||
} catch (BadLocationException e) {
|
||||
log.error("", e);
|
||||
}
|
||||
}
|
||||
|
||||
private MethodDeclaration findHandleEventMethod(TypeDeclaration type) {
|
||||
MethodDeclaration[] methods = type.getMethods();
|
||||
|
||||
@@ -21,11 +21,13 @@ public class EventListenerIndexElement extends AbstractSpringIndexElement {
|
||||
|
||||
private final String eventType;
|
||||
private final Location location;
|
||||
private final String containerBeanType;
|
||||
private final AnnotationMetadata[] annotations;
|
||||
|
||||
public EventListenerIndexElement(String eventType, Location location, AnnotationMetadata[] annotations) {
|
||||
public EventListenerIndexElement(String eventType, Location location, String containerBeanType, AnnotationMetadata[] annotations) {
|
||||
this.eventType = eventType;
|
||||
this.location = location;
|
||||
this.containerBeanType = containerBeanType;
|
||||
this.annotations = annotations;
|
||||
}
|
||||
|
||||
@@ -41,4 +43,8 @@ public class EventListenerIndexElement extends AbstractSpringIndexElement {
|
||||
return location;
|
||||
}
|
||||
|
||||
public String getContainerBeanType() {
|
||||
return containerBeanType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.IVariableBinding;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.eclipse.lsp4j.Location;
|
||||
import org.eclipse.lsp4j.SymbolKind;
|
||||
import org.eclipse.lsp4j.WorkspaceSymbol;
|
||||
@@ -75,8 +76,17 @@ public class EventListenerSymbolProvider extends AbstractSymbolProvider {
|
||||
ITypeBinding eventType = getEventType(node, method);
|
||||
DocumentRegion nodeRegion = ASTUtils.nodeRegion(doc, method.getName());
|
||||
Location location = new Location(doc.getUri(), nodeRegion.asRange());
|
||||
|
||||
String containerBeanType = null;
|
||||
TypeDeclaration type = ASTUtils.findDeclaringType(method);
|
||||
if (type != null) {
|
||||
ITypeBinding binding = type.resolveBinding();
|
||||
if (binding != null) {
|
||||
containerBeanType = binding.getQualifiedName();
|
||||
}
|
||||
}
|
||||
|
||||
cachedBean.getBean().addChild(new EventListenerIndexElement(eventType != null ? eventType.getQualifiedName() : "", location, annotations));
|
||||
cachedBean.getBean().addChild(new EventListenerIndexElement(eventType != null ? eventType.getQualifiedName() : "", location, containerBeanType, annotations));
|
||||
}
|
||||
}
|
||||
} catch (BadLocationException e) {
|
||||
@@ -84,6 +94,11 @@ public class EventListenerSymbolProvider extends AbstractSymbolProvider {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addSymbolsPass1(TypeDeclaration typeDeclaration, SpringIndexerJavaContext context, TextDocument doc) {
|
||||
super.addSymbolsPass1(typeDeclaration, context, doc);
|
||||
}
|
||||
|
||||
private String createEventListenerSymbolLabel(Annotation node, MethodDeclaration method) {
|
||||
// event listener annotation type
|
||||
String annotationTypeName = getAnnotationTypeName(node);
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.springframework.ide.vscode.boot.java.events.EventListenerIndexElement
|
||||
import org.springframework.ide.vscode.boot.java.events.EventPublisherIndexElement;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
|
||||
import org.springframework.ide.vscode.commons.protocol.spring.DocumentElement;
|
||||
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
|
||||
import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness;
|
||||
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
|
||||
@@ -117,6 +118,7 @@ public class SpringIndexerEventsTest {
|
||||
|
||||
EventListenerIndexElement listenerElement = (EventListenerIndexElement) children.get(0);
|
||||
assertEquals("org.springframework.context.ApplicationEvent", listenerElement.getEventType());
|
||||
assertEquals("com.example.events.demo.EventListenerPerAnnotation", listenerElement.getContainerBeanType());
|
||||
|
||||
Location location = listenerElement.getLocation();
|
||||
assertNotNull(location);
|
||||
@@ -140,6 +142,7 @@ public class SpringIndexerEventsTest {
|
||||
|
||||
EventListenerIndexElement listenerElement = (EventListenerIndexElement) children.get(0);
|
||||
assertEquals("org.springframework.context.ApplicationEvent", listenerElement.getEventType());
|
||||
assertEquals("com.example.events.demo.EventListenerPerInterface", listenerElement.getContainerBeanType());
|
||||
|
||||
Location location = listenerElement.getLocation();
|
||||
assertNotNull(location);
|
||||
@@ -147,6 +150,26 @@ public class SpringIndexerEventsTest {
|
||||
assertEquals(new Range(new Position(10, 13), new Position(10, 31)), location.getRange());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEventListenerIndexElementForListenerInterfaceImplementationWithoutComponentAnnotation() throws Exception {
|
||||
String docUri = directory.toPath().resolve("src/main/java/com/example/events/demo/EventListenerPerInterfaceAndBeanMethod.java").toUri().toString();
|
||||
|
||||
Bean[] beans = springIndex.getBeansOfDocument(docUri);
|
||||
assertEquals(0, beans.length);
|
||||
|
||||
DocumentElement document = springIndex.getDocument(docUri);
|
||||
List<SpringIndexElement> children = document.getChildren();
|
||||
|
||||
EventListenerIndexElement listenerElement = children.stream().filter(element -> element instanceof EventListenerIndexElement).map(element -> (EventListenerIndexElement) element).findFirst().get();
|
||||
assertEquals("org.springframework.context.ApplicationEvent", listenerElement.getEventType());
|
||||
assertEquals("com.example.events.demo.EventListenerPerInterfaceAndBeanMethod", listenerElement.getContainerBeanType());
|
||||
|
||||
Location location = listenerElement.getLocation();
|
||||
assertNotNull(location);
|
||||
assertEquals(docUri, location.getUri());
|
||||
assertEquals(new Range(new Position(8, 13), new Position(8, 31)), location.getRange());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEventPublisherIndexElements() throws Exception {
|
||||
String docUri = directory.toPath().resolve("src/main/java/com/example/events/demo/CustomEventPublisher.java").toUri().toString();
|
||||
|
||||
@@ -40,6 +40,10 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
Reference in New Issue
Block a user