Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure that I comprehend why only the DEADLINE is left for black listing. Care to explain?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class marks any @MessageHander annotated method, unless that handler type is in the list.

Before this PR, a command handler had a specific one, but with the interceptors gone it's not needed. Aditionally, in the future, the interceptors will be generic for any type of message and implemented in this provider.
The reason deadline is still here is because this is a specific one (DeadlineHandlerMethodLineMarkerProvider) because it uses the DeadlineManagerReferenceResolver instead of the MessageHandlerResolver

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left it a list, because maybe we need different MarkerProviders later after all

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation; it makes sense to me!

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
Loading