Skip to content

Commit

Permalink
Merge pull request #290 from AxonFramework/fix/take-hierarchy-into-ac…
Browse files Browse the repository at this point in the history
…count

Take class hierarchy into account when resolving
  • Loading branch information
CodeDrivenMitch authored Oct 1, 2024
2 parents bf15afa + 0425dbc commit 90ea068
Show file tree
Hide file tree
Showing 15 changed files with 39 additions and 654 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
- Plugin is now compatible with IDEA 2024.3 (IDEA 243.*) with minimum version of 2024.2
- Fix various deprecation warnings
- Fix various javadoc issues
- Fix class hierarchy not being taken into account for handler and creator resolving.
- Remove wrong implementation of interceptor support, to possibly be re-implemented in a future release in a better form.

## [0.8.7]
- Plugin is now compatible with IDEA 2024.2 (IDEA 242.*)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ enum class MessageHandlerType(
EVENT_SOURCING(AxonAnnotation.EVENT_SOURCING_HANDLER, MessageType.EVENT),
QUERY(AxonAnnotation.QUERY_HANDLER, MessageType.QUERY),
DEADLINE(AxonAnnotation.DEADLINE_HANDLER, MessageType.DEADLINE),
COMMAND_INTERCEPTOR(AxonAnnotation.COMMAND_HANDLER_INTERCEPTOR, MessageType.COMMAND),
SAGA(AxonAnnotation.SAGA_EVENT_HANDLER, MessageType.EVENT),
;

Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import org.axonframework.intellij.ide.plugin.util.creatorResolver
* Provides a gutter icon on all generic handler methods
*/
class CommonHandlerMethodLineMarkerProvider : AbstractHandlerLineMarkerProvider() {
private val blacklistedTypes = listOf(MessageHandlerType.DEADLINE, MessageHandlerType.COMMAND, MessageHandlerType.COMMAND_INTERCEPTOR)
private val blacklistedTypes = listOf(MessageHandlerType.DEADLINE)
override fun createLineMarker(
element: PsiElement,
handlerType: MessageHandlerType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ package org.axonframework.intellij.ide.plugin.markers.publishers

import com.intellij.codeInsight.daemon.LineMarkerInfo
import com.intellij.codeInsight.daemon.LineMarkerProvider
import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo
import com.intellij.codeInsight.daemon.RelatedItemLineMarkerProvider
import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.psi.PsiElement
Expand All @@ -29,7 +27,6 @@ import org.axonframework.intellij.ide.plugin.AxonIcons
import org.axonframework.intellij.ide.plugin.api.MessageHandlerType
import org.axonframework.intellij.ide.plugin.markers.AxonNavigationTargetRenderer
import org.axonframework.intellij.ide.plugin.resolving.MessageHandlerResolver
import org.axonframework.intellij.ide.plugin.resolving.handlers.types.CommandHandlerInterceptor
import org.axonframework.intellij.ide.plugin.resolving.handlers.types.DeadlineHandler
import org.axonframework.intellij.ide.plugin.util.containingClassFqn
import org.axonframework.intellij.ide.plugin.util.handlerResolver
Expand Down Expand Up @@ -66,11 +63,9 @@ class PublishMethodLineMarkerProvider : LineMarkerProvider {
else -> null
} ?: return null

val allHandlers = element.handlerResolver().findHandlersForType(payload)
val handlers = element.handlerResolver().findHandlersForType(payload)
// Hide DeadlineHandlers here. These are handled by a more specific LineMarkerProvider
.filter { it !is DeadlineHandler }
val isCommand = allHandlers.all { it.handlerType == MessageHandlerType.COMMAND }
val handlers = allHandlers.filter { it !is CommandHandlerInterceptor || isCommand } // Only show interceptors when is a command
if (handlers.isEmpty()) {
return null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ package org.axonframework.intellij.ide.plugin.resolving

import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.search.searches.ClassInheritorsSearch
import com.intellij.psi.search.searches.MethodReferencesSearch
import com.intellij.psi.util.CachedValue
import org.axonframework.intellij.ide.plugin.api.MessageCreator
import org.axonframework.intellij.ide.plugin.resolving.creators.DefaultMessageCreator
import org.axonframework.intellij.ide.plugin.util.areAssignable
import org.axonframework.intellij.ide.plugin.util.axonScope
import org.axonframework.intellij.ide.plugin.util.createCachedValue
import org.axonframework.intellij.ide.plugin.util.findParentHandlers
Expand All @@ -38,7 +38,6 @@ import java.util.concurrent.ConcurrentHashMap
* the PSI is modified (code is edited) or is collected by the garbage collector.
*/
class MessageCreationResolver(private val project: Project) {
private val handlerResolver = project.handlerResolver()
private val psiFacade = project.javaFacade()
private val constructorsByPayloadCache = ConcurrentHashMap<String, CachedValue<List<MessageCreator>>>()

Expand All @@ -59,25 +58,19 @@ class MessageCreationResolver(private val project: Project) {
}

private fun findByPayload(payload: String): List<MessageCreator> {
val matchingHandlers = handlerResolver.findAllHandlers()
.map { it.payload }
.filter { areAssignable(project, payload, it) }
val classesForQualifiedName = listOf(payload).plus(matchingHandlers)
.distinct()
return resolveCreatorsForFqns(classesForQualifiedName)
}
val classes = psiFacade.findClass(payload, project.axonScope())?.let { clazz ->
listOf(clazz) + ClassInheritorsSearch.search(clazz, project.axonScope(), true)
} ?: return emptyList()

private fun resolveCreatorsForFqns(fqns: List<String>): List<MessageCreator> {
return fqns.flatMap { typeFqn ->
psiFacade.findClasses(typeFqn, project.axonScope()).flatMap { clazz ->
return classes
.flatMap { clazz ->
// Account for constructors and builder methods (builder(), toBuilder(), etc)
val methods = clazz.constructors + clazz.methods.filter { it.name.contains("build", ignoreCase = true) }
methods
.flatMap { MethodReferencesSearch.search(it, project.axonScope(), true) }
.flatMap { ref -> createCreators(typeFqn, ref.element) }
.flatMap { ref -> createCreators(clazz.qualifiedName!!, ref.element) }
.distinct()
}
}
}

private fun createCreators(payload: String, element: PsiElement): List<MessageCreator> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,22 @@
package org.axonframework.intellij.ide.plugin.resolving

import com.intellij.openapi.project.Project
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.search.searches.ClassInheritorsSearch
import org.axonframework.intellij.ide.plugin.api.Handler
import org.axonframework.intellij.ide.plugin.api.MessageType
import org.axonframework.intellij.ide.plugin.resolving.handlers.searchers.AggregateConstructorSearcher
import org.axonframework.intellij.ide.plugin.resolving.handlers.searchers.CommandHandlerInterceptorSearcher
import org.axonframework.intellij.ide.plugin.resolving.handlers.searchers.CommandHandlerSearcher
import org.axonframework.intellij.ide.plugin.resolving.handlers.searchers.DeadlineHandlerSearcher
import org.axonframework.intellij.ide.plugin.resolving.handlers.searchers.EventHandlerSearcher
import org.axonframework.intellij.ide.plugin.resolving.handlers.searchers.EventSourcingHandlerSearcher
import org.axonframework.intellij.ide.plugin.resolving.handlers.searchers.QueryHandlerSearcher
import org.axonframework.intellij.ide.plugin.resolving.handlers.searchers.SagaEventHandlerSearcher
import org.axonframework.intellij.ide.plugin.util.areAssignable
import org.axonframework.intellij.ide.plugin.util.axonScope
import org.axonframework.intellij.ide.plugin.util.createCachedValue
import org.axonframework.intellij.ide.plugin.util.findCompleteSupers

/**
* Searches the codebase for Message handlers based on the annotations defined in MessageHandlerType.
Expand All @@ -41,7 +44,6 @@ import org.axonframework.intellij.ide.plugin.util.createCachedValue
*/
class MessageHandlerResolver(private val project: Project) {
private val searchers = listOf(
CommandHandlerInterceptorSearcher(),
CommandHandlerSearcher(),
EventHandlerSearcher(),
EventSourcingHandlerSearcher(),
Expand All @@ -61,20 +63,29 @@ class MessageHandlerResolver(private val project: Project) {
fun findHandlersForType(
qualifiedName: String,
messageType: MessageType? = null,
reverseAssign: Boolean = false
): List<Handler> {
val baseClass = JavaPsiFacade.getInstance(project).findClasses(qualifiedName, project.axonScope()).firstOrNull()
?: return emptyList()

val additionalSupersOrImplementors = searchRelatedClasses(baseClass)
val completeList = listOf(qualifiedName) + additionalSupersOrImplementors
return handlerCache.value
.filter { messageType == null || it.handlerType.messageType == messageType }
.filter {
if (reverseAssign) areAssignable(project, qualifiedName, it.payload) else areAssignable(
project,
it.payload,
qualifiedName
)
}
.filter { completeList.contains(it.payload) }
.filter { it.element.isValid }
}

private fun searchRelatedClasses(baseClass: PsiClass): List<String> {
val implementors = ClassInheritorsSearch.search(baseClass, project.axonScope(), true)
.mapNotNull { it.qualifiedName }
.distinct()

// The supers call only returns one level at a time. We need to do this recursively
return implementors + baseClass.findCompleteSupers()
.mapNotNull { it.qualifiedName }
.distinct()
}

fun findAllHandlers(): List<Handler> = handlerCache.value

fun findHandlerByElement(psiElement: PsiElement): Handler? {
Expand Down

This file was deleted.

Loading

0 comments on commit 90ea068

Please sign in to comment.