Skip to content

Commit

Permalink
GH-1465: take event listener types defined via annotation attribute i…
Browse files Browse the repository at this point in the history
…nto account when looking for references

Fixes GH-1465
  • Loading branch information
martinlippert committed Feb 5, 2025
1 parent 24c5d4e commit f8aabc2
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
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;
Expand Down Expand Up @@ -112,7 +111,7 @@ protected void createSymbol(Annotation node, ITypeBinding annotationType, Collec

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)
Expand All @@ -123,31 +122,6 @@ protected void createSymbol(Annotation node, ITypeBinding annotationType, Collec
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())) {
Expand Down Expand Up @@ -212,7 +186,6 @@ public boolean visit(MethodInvocation methodInvocation) {

@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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -25,6 +28,8 @@
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;

Expand Down Expand Up @@ -55,19 +60,26 @@ public List<? extends Location> provideReferences(CancelChecker cancelToken, IJa
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();

Expand All @@ -76,20 +88,30 @@ public List<? extends Location> provideReferences(CancelChecker cancelToken, IJa
}
}

// 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()))
.filter(eventPublisher -> isPositionInside(position, eventPublisher.getLocation()))
.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();

Expand All @@ -106,6 +128,29 @@ public List<? extends Location> provideReferences(CancelChecker cancelToken, IJa
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());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,9 @@ public void foo() {
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));


}

}

0 comments on commit f8aabc2

Please sign in to comment.