GH-1465: take event listener types defined via annotation attribute into account when looking for references
Fixes GH-1465
This commit is contained in:
@@ -34,7 +34,6 @@ 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;
|
||||
@@ -112,7 +111,7 @@ public class ComponentSymbolProvider extends AbstractSymbolProvider {
|
||||
|
||||
Bean beanDefinition = new Bean(beanName, beanType.getQualifiedName(), location, injectionPoints, supertypes, annotations, isConfiguration);
|
||||
|
||||
// event listener - create child element, if necessary
|
||||
// type implements event listener - move those already created event index elements under the bean node
|
||||
List<CachedBean> alreadyCreatedEventListenerChilds = context.getBeans().stream()
|
||||
.filter(cachedBean -> cachedBean.getDocURI().equals(doc.getUri()))
|
||||
.filter(cachedBean -> cachedBean.getBean() instanceof EventListenerIndexElement)
|
||||
@@ -123,31 +122,6 @@ public class ComponentSymbolProvider extends AbstractSymbolProvider {
|
||||
beanDefinition.addChild(eventListener.getBean());
|
||||
}
|
||||
|
||||
// ITypeBinding inTypeHierarchy = ASTUtils.findInTypeHierarchy(type, doc, beanType, Set.of(Annotations.APPLICATION_LISTENER));
|
||||
// if (inTypeHierarchy != null) {
|
||||
//
|
||||
// MethodDeclaration handleEventMethod = findHandleEventMethod(type);
|
||||
// if (handleEventMethod != null) {
|
||||
//
|
||||
// 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, beanType.getQualifiedName(), handleEventMethodAnnotations);
|
||||
// beanDefinition.addChild(eventElement);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// event publisher checks
|
||||
for (InjectionPoint injectionPoint : injectionPoints) {
|
||||
if (Annotations.EVENT_PUBLISHER.equals(injectionPoint.getType())) {
|
||||
@@ -212,7 +186,6 @@ 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;
|
||||
|
||||
@@ -10,9 +10,12 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.events;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
@@ -25,6 +28,8 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.ReferenceProvider;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.protocol.spring.AnnotationAttributeValue;
|
||||
import org.springframework.ide.vscode.commons.protocol.spring.AnnotationMetadata;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
@@ -55,19 +60,26 @@ public class EventReferenceProvider implements ReferenceProvider {
|
||||
List<EventListenerIndexElement> listeners = index.getNodesOfType(EventListenerIndexElement.class);
|
||||
List<EventPublisherIndexElement> publishers = index.getNodesOfType(EventPublisherIndexElement.class);
|
||||
|
||||
// when offset is inside an event listener, find the respective event type
|
||||
Optional<String> listenerEventType = listeners.stream()
|
||||
// when offset is inside an event listener, look for references from publishers
|
||||
Optional<EventListenerIndexElement> listenerElement = listeners.stream()
|
||||
.filter(listener -> listener.getLocation().getUri().equals(doc.getUri()))
|
||||
.filter(eventListener -> isPositionInside(position, eventListener.getLocation()))
|
||||
.map(eventListener -> eventListener.getEventType())
|
||||
.findAny();
|
||||
|
||||
if (listenerEventType.isPresent()) {
|
||||
// use the listener event type to look for publishers for that type
|
||||
String eventType = listenerEventType.get();
|
||||
if (listenerElement.isPresent()) {
|
||||
Set<String> eventTypes = getListenerEventTypes(listenerElement.get());
|
||||
|
||||
List<Location> foundLocations = publishers.stream()
|
||||
.filter(publisher -> publisher.getEventType().equals(eventType) || publisher.getEventTypesFromHierarchy().contains(eventType))
|
||||
.filter(publisher -> {
|
||||
if (eventTypes.contains(publisher.getEventType())) return true;
|
||||
|
||||
for (String listenerEventType : eventTypes) {
|
||||
if (publisher.getEventTypesFromHierarchy().contains(listenerEventType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.map(publisher -> publisher.getLocation())
|
||||
.toList();
|
||||
|
||||
@@ -76,7 +88,7 @@ public class EventReferenceProvider implements ReferenceProvider {
|
||||
}
|
||||
}
|
||||
|
||||
// when offset is inside an event publisher, find the respective event type
|
||||
// when offset is inside an event publisher, look for references from listeners
|
||||
else {
|
||||
Optional<EventPublisherIndexElement> publisherElement = publishers.stream()
|
||||
.filter(publisher -> publisher.getLocation().getUri().equals(doc.getUri()))
|
||||
@@ -84,12 +96,22 @@ public class EventReferenceProvider implements ReferenceProvider {
|
||||
.findAny();
|
||||
|
||||
if (publisherElement.isPresent()) {
|
||||
// use the publisher event type to look for listeners for that type
|
||||
String eventType = publisherElement.get().getEventType();
|
||||
Set<String> eventTypesFromHierarchy = publisherElement.get().getEventTypesFromHierarchy();
|
||||
|
||||
List<Location> foundLocations = listeners.stream()
|
||||
.filter(listener -> listener.getEventType().equals(eventType) || eventTypesFromHierarchy.contains(listener.getEventType()))
|
||||
.filter(listener -> {
|
||||
Set<String> listenerEventTypes = getListenerEventTypes(listener);
|
||||
for (String listenerEventType : listenerEventTypes) {
|
||||
if (listenerEventType.equals(eventType)) {
|
||||
return true;
|
||||
}
|
||||
if (eventTypesFromHierarchy.contains(listenerEventType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.map(listener -> listener.getLocation())
|
||||
.toList();
|
||||
|
||||
@@ -106,6 +128,29 @@ public class EventReferenceProvider implements ReferenceProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Set<String> getListenerEventTypes(EventListenerIndexElement eventListenerIndexElement) {
|
||||
AnnotationMetadata[] annotations = eventListenerIndexElement.getAnnotations();
|
||||
if (annotations != null && annotations.length > 0) {
|
||||
for (AnnotationMetadata annotationMetadata : annotations) {
|
||||
Map<String, AnnotationAttributeValue[]> attributes = annotationMetadata.getAttributes();
|
||||
if (attributes.containsKey("classes")) {
|
||||
AnnotationAttributeValue[] annotationAttributeValues = attributes.get("classes");
|
||||
return Arrays.stream(annotationAttributeValues)
|
||||
.map(attributeValue -> attributeValue.getName())
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
else if (attributes.containsKey("value")) {
|
||||
AnnotationAttributeValue[] annotationAttributeValues = attributes.get("value");
|
||||
return Arrays.stream(annotationAttributeValues)
|
||||
.map(attributeValue -> attributeValue.getName())
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Set.of(eventListenerIndexElement.getEventType());
|
||||
}
|
||||
|
||||
private boolean isPositionInside(Position position, Location location) {
|
||||
boolean afterStart = position.getLine() > location.getRange().getStart().getLine()
|
||||
|| (position.getLine() == location.getRange().getStart().getLine() && position.getCharacter() >= location.getRange().getStart().getCharacter());
|
||||
|
||||
@@ -169,11 +169,9 @@ public class EventsReferencesProviderTest {
|
||||
assertTrue(references.contains(expectedLocation2));
|
||||
|
||||
String expectedDefinitionUri3 = directory.toPath().resolve("src/main/java/com/example/events/demo/EventListenerPerInterfaceAndBeanMethod.java").toUri().toString();
|
||||
Location expectedLocation3 = new Location(expectedDefinitionUri3, new Range(new Position(9, 13), new Position(9, 24)));
|
||||
Location expectedLocation3 = new Location(expectedDefinitionUri3, new Range(new Position(7, 13), new Position(7, 31)));
|
||||
|
||||
assertTrue(references.contains(expectedLocation3));
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user