diff --git a/plugins/kotlin/maven/src/org/jetbrains/kotlin/idea/maven/PomFile.kt b/plugins/kotlin/maven/src/org/jetbrains/kotlin/idea/maven/PomFile.kt
index edae14d9f6c7..c1544cd18e74 100644
--- a/plugins/kotlin/maven/src/org/jetbrains/kotlin/idea/maven/PomFile.kt
+++ b/plugins/kotlin/maven/src/org/jetbrains/kotlin/idea/maven/PomFile.kt
@@ -201,11 +201,13 @@ class PomFile private constructor(private val xmlFile: XmlFile, val domModel: Ma
?: domModel.build.pluginManagement.plugins.plugins.firstOrNull { it.matches(groupArtifact) }
fun isPluginAfter(plugin: MavenDomPlugin, referencePlugin: MavenDomPlugin): Boolean {
- require(plugin.parent === referencePlugin.parent) { "Plugins should be siblings" }
require(plugin !== referencePlugin)
val referenceElement = referencePlugin.xmlElement!!
var e: PsiElement = plugin.xmlElement!!
+ // `pluginManagement/plugins` and `build/plugins` can both contain the same Maven plugin.
+ // In that case there is no shared sibling order to compare inside one XML container.
+ if (e.parent !== referenceElement.parent) return false
while (e !== referenceElement) {
val prev = e.prevSibling ?: return false
@@ -216,13 +218,21 @@ class PomFile private constructor(private val xmlFile: XmlFile, val domModel: Ma
}
private fun ensurePluginAfter(plugin: MavenDomPlugin, referencePlugin: MavenDomPlugin): MavenDomPlugin {
+ // Only reorder plugins that already live in the same XML list. Moving a plugin across
+ // `pluginManagement` and `build/plugins` would change the POM structure instead of order.
+ if (plugin.xmlElement?.parent !== referencePlugin.xmlElement?.parent) {
+ return plugin
+ }
+
if (!isPluginAfter(plugin, referencePlugin)) {
// rearrange
val referenceElement = referencePlugin.xmlElement!!
val newElement = referenceElement.parent.addAfter(plugin.xmlElement!!, referenceElement)
plugin.xmlTag?.delete()
- return domModel.build.plugins.plugins.single { it.xmlElement == newElement }
+ return (domModel.build.plugins.plugins + domModel.build.pluginManagement.plugins.plugins)
+ .singleOrNull { it.xmlElement == newElement }
+ ?: error("Failed to find plugin after reordering in ${xmlFile.name}")
}
return plugin
diff --git a/plugins/kotlin/maven/tests/test/org/jetbrains/kotlin/idea/maven/configuration/KotlinSourceRootDirsMavenTest.kt b/plugins/kotlin/maven/tests/test/org/jetbrains/kotlin/idea/maven/configuration/KotlinSourceRootDirsMavenTest.kt
index 3cc070c0763b..14b5d19b8724 100644
--- a/plugins/kotlin/maven/tests/test/org/jetbrains/kotlin/idea/maven/configuration/KotlinSourceRootDirsMavenTest.kt
+++ b/plugins/kotlin/maven/tests/test/org/jetbrains/kotlin/idea/maven/configuration/KotlinSourceRootDirsMavenTest.kt
@@ -401,6 +401,200 @@ class KotlinSourceRootDirsMavenTest : AbstractKotlinMavenImporterTest() {
doTest(project, module, afterFile)
}
+ @Test
+ fun `test root module with plugin management and processor submodule`() = runBlocking {
+ val mainPom = createProjectPom(
+ """
+ org.example
+ project
+ 1.0-SNAPSHOT
+ pom
+
+ sub-mod
+
+
+
+ 17
+ 17
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.15.0
+
+
+ org.jetbrains.kotlin
+ kotlin-maven-plugin
+ $KOTLIN_VERSION
+
+
+ compile
+ compile
+
+ compile
+
+
+
+ test-compile
+ test-compile
+
+ test-compile
+
+
+
+
+
+
+
+ """.trimIndent()
+ )
+
+ val subModulePom = createModulePom(
+ "sub-mod",
+ """
+
+ org.example
+ project
+ 1.0-SNAPSHOT
+
+
+ sub-mod
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ org.mapstruct
+ mapstruct-processor
+ 1.6.3
+
+
+
+
+
+
+ """.trimIndent()
+ )
+
+ importProjectsAsync(mainPom, subModulePom)
+ assertModules("project", "sub-mod")
+
+ val module = project.modules.first { it.name == "project" }
+
+ val afterFile = """
+
+ 4.0.0
+ org.example
+ project
+ 1.0-SNAPSHOT
+ pom
+
+ sub-mod
+
+
+
+ 17
+ 17
+ 2.2.20
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib
+ ${'$'}{kotlin.version}
+
+
+ org.jetbrains.kotlin
+ kotlin-test
+ ${'$'}{kotlin.version}
+ test
+
+
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-maven-plugin
+ ${'$'}{kotlin.version}
+
+
+ compile
+ compile
+
+ compile
+
+
+
+ test-compile
+ test-compile
+
+ test-compile
+
+
+
+
+ ${'$'}{maven.compiler.target}
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.15.0
+
+
+ default-compile
+ none
+
+
+ default-testCompile
+ none
+
+
+ compile
+ compile
+
+ compile
+
+
+
+ testCompile
+ test-compile
+
+ testCompile
+
+
+
+
+
+
+
+"""
+
+ val childTextBefore = runReadAction { subModulePom.toPsiFile(project)!!.text }
+
+ doTest(project, module, afterFile)
+
+ val childTextAfter = runReadAction { subModulePom.toPsiFile(project)!!.text }
+ assertEquals(
+ "Submodule POM should stay untouched:\n$childTextAfter",
+ childTextBefore,
+ childTextAfter
+ )
+ }
+
private fun doTest(project: Project, module: Module, afterFile: String) {
return runInEdtAndGet {
val moduleRootManager = ModuleRootManager.getInstance(module)