diff --git a/.idea/modules.xml b/.idea/modules.xml index 235ac9f3cd46..39ff6d6cfe52 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -664,6 +664,7 @@ + diff --git a/build/bazel-generated-file-list.txt b/build/bazel-generated-file-list.txt index e1c1915c37c1..e50e94da7034 100644 --- a/build/bazel-generated-file-list.txt +++ b/build/bazel-generated-file-list.txt @@ -1176,6 +1176,7 @@ plugins/marketplace-ml plugins/maven plugins/maven-model plugins/maven-server-api +plugins/maven-server-api/test plugins/maven/artifact-resolver-m31 plugins/maven/artifact-resolver/common plugins/maven/error-prone-compiler diff --git a/platform/testFramework/testResources/tests/testGroups.properties b/platform/testFramework/testResources/tests/testGroups.properties index ce2fa76b8fb0..370006a010bf 100644 --- a/platform/testFramework/testResources/tests/testGroups.properties +++ b/platform/testFramework/testResources/tests/testGroups.properties @@ -268,6 +268,7 @@ org.jetbrains.idea.maven.indices.* org.jetbrains.idea.maven.inspections.* org.jetbrains.idea.maven.inspections.dom.* org.jetbrains.idea.maven.intentions.* +org.jetbrains.idea.maven.model.* org.jetbrains.idea.maven.navigator.* org.jetbrains.idea.maven.plugins.* org.jetbrains.idea.maven.plugins.compatibility.* diff --git a/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/model/MavenBuild.java b/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/model/MavenBuild.java index 9f439a41c60d..12cd1b1c5efd 100644 --- a/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/model/MavenBuild.java +++ b/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/model/MavenBuild.java @@ -20,13 +20,12 @@ import org.jetbrains.annotations.NotNull; import java.io.Serializable; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import java.util.concurrent.CopyOnWriteArrayList; public class MavenBuild extends MavenBuildBase implements Serializable { private String myOutputDirectory; private String myTestOutputDirectory; - private @NotNull List<@NotNull String> mySources = new CopyOnWriteArrayList<>(); - private @NotNull List<@NotNull String> myTestSources = new CopyOnWriteArrayList<>(); public String getOutputDirectory() { return myOutputDirectory; @@ -45,18 +44,37 @@ public class MavenBuild extends MavenBuildBase implements Serializable { } public @NotNull List<@NotNull String> getSources() { - return Collections.unmodifiableList(mySources); + return getMavenSources().stream().filter(it -> MavenSource.isSource(it)) + .map(it -> it.getDirectory()) + .collect(Collectors.toList()); } public void setSources(@NotNull List<@NotNull String> sources) { - mySources = new CopyOnWriteArrayList<>(sources); + getMavenSources().removeIf(it -> MavenSource.isSource(it)); + sources.forEach(it -> { + getMavenSources().add(MavenSource.fromSrc(it, false)); + }); + } + + public void addSource(@NotNull String source) { + getMavenSources().add(MavenSource.fromSrc(source, false)); } public @NotNull List<@NotNull String> getTestSources() { - return Collections.unmodifiableList(myTestSources); + return getMavenSources().stream().filter(it -> MavenSource.isTestSource(it)) + .map(it -> it.getDirectory()) + .collect(Collectors.toList()); } public void setTestSources(@NotNull List<@NotNull String> testSources) { - myTestSources = new CopyOnWriteArrayList<>(testSources); + getMavenSources().removeIf(it -> MavenSource.isTestSource(it)); + testSources.forEach(it -> { + getMavenSources().add(MavenSource.fromSrc(it, true)); + }); } + + public void addTestSource(@NotNull String source) { + getMavenSources().add(MavenSource.fromSrc(source, true)); + } + } \ No newline at end of file diff --git a/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/model/MavenBuildBase.java b/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/model/MavenBuildBase.java index 87f13a289072..f91c22829eba 100644 --- a/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/model/MavenBuildBase.java +++ b/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/model/MavenBuildBase.java @@ -21,14 +21,15 @@ import java.io.Serializable; import java.util.Collections; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.stream.Collectors; public class MavenBuildBase implements Serializable { private String myFinalName; private String myDefaultGoal; private String myDirectory; - private @NotNull List<@NotNull MavenResource> myResources = new CopyOnWriteArrayList<>(); - private @NotNull List<@NotNull MavenResource> myTestResources = new CopyOnWriteArrayList<>(); - private @NotNull List<@NotNull String> myFilters = new CopyOnWriteArrayList<>(); + private final @NotNull List<@NotNull String> myFilters =new CopyOnWriteArrayList<>(); + + private final @NotNull List<@NotNull MavenSource> myMavenSources = new CopyOnWriteArrayList<>(); public String getFinalName() { return myFinalName; @@ -55,19 +56,29 @@ public class MavenBuildBase implements Serializable { } public @NotNull List<@NotNull MavenResource> getResources() { - return Collections.unmodifiableList(myResources); + return myMavenSources.stream().filter(it -> MavenSource.isResource(it)) + .map(it -> new MavenResource(it)).collect(Collectors.toList()); } public void setResources(@NotNull List<@NotNull MavenResource> resources) { - myResources = new CopyOnWriteArrayList<>(resources); + myMavenSources.removeIf(it -> MavenSource.isResource(it)); + resources.forEach(it -> { + myMavenSources.add(MavenSource.fromResource(it, false)); + }); } + + public @NotNull List<@NotNull MavenResource> getTestResources() { - return Collections.unmodifiableList(myTestResources); + return myMavenSources.stream().filter(it -> MavenSource.isTestResource(it)) + .map(it -> new MavenResource(it)).collect(Collectors.toList()); } public void setTestResources(@NotNull List<@NotNull MavenResource> testResources) { - myTestResources = new CopyOnWriteArrayList<>(testResources); + myMavenSources.removeIf(it -> MavenSource.isTestResource(it)); + testResources.forEach(it -> { + myMavenSources.add(MavenSource.fromResource(it, true)); + }); } public @NotNull List<@NotNull String> getFilters() { @@ -75,6 +86,17 @@ public class MavenBuildBase implements Serializable { } public void setFilters(@NotNull List<@NotNull String> filters) { - myFilters = new CopyOnWriteArrayList<>(filters); + myFilters.clear(); + myFilters.addAll(filters); } + + public @NotNull List<@NotNull MavenSource> getMavenSources() { + return myMavenSources; + } + + public void setMavenSources(@NotNull List<@NotNull MavenSource> mavenSources) { + myMavenSources.clear(); + myMavenSources.addAll(mavenSources); + } + } diff --git a/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/model/MavenResource.java b/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/model/MavenResource.java index 7cd7704f5a62..1cad9d5575a1 100644 --- a/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/model/MavenResource.java +++ b/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/model/MavenResource.java @@ -24,6 +24,10 @@ public class MavenResource implements Serializable { myExcludes = excludes == null ? Collections.emptyList() : new ArrayList(excludes); } + public MavenResource(@NotNull MavenSource source) { + this(source.getDirectory(), source.isFiltered(), source.getTargetPath(), source.getIncludes(), source.getExcludes()); + } + public @NotNull String getDirectory() { return myDirectory; } diff --git a/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/model/MavenSource.java b/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/model/MavenSource.java new file mode 100644 index 000000000000..2f3d56d7e5fc --- /dev/null +++ b/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/model/MavenSource.java @@ -0,0 +1,184 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.idea.maven.model; + +import org.jetbrains.annotations.NotNull; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +public class MavenSource implements Serializable { + public static final String MAIN_SCOPE = "main"; + public static final String TEST_SCOPE = "test"; + public static final String JAVA_LANG = "java"; + public static final String RESOURCES_LANG = "resources"; + + private final @NotNull String myDirectory; + private final ArrayList myIncludes; + private final ArrayList myExcludes; + private final String myScope; + private final String myLang; + private final String myTargetPath; + private final String myTargetVersion; + private final boolean myFiltered; + private final boolean myEnabled; + private final boolean myIsSourceTag; + + + private MavenSource(boolean isSourceTag, + @NotNull String directory, + List includes, + List excludes, + String scope, + String lang, + String targetPath, + String targetVersion, + boolean filtered, + boolean enabled) { + + myIsSourceTag = isSourceTag; + myDirectory = directory; + myIncludes = new ArrayList<>(includes); + myExcludes = new ArrayList<>(excludes); + myScope = scope; + myLang = lang; + myTargetPath = targetPath; + myTargetVersion = targetVersion; + myFiltered = filtered; + myEnabled = enabled; + } + + + public @NotNull String getDirectory() { + return myDirectory; + } + + public List getIncludes() { + return myIncludes; + } + + public List getExcludes() { + return myExcludes; + } + + public String getScope() { + return myScope; + } + + public String getLang() { + return myLang; + } + + public String getTargetPath() { + return myTargetPath; + } + + public String getTargetVersion() { + return myTargetVersion; + } + + public boolean isFiltered() { + return myFiltered; + } + + public boolean isEnabled() { + return myEnabled; + } + + /** + * @return true if this object was generated from maven 4-rc3+ source tag, false otherwise + */ + public boolean isFromSourceTag() { + return myIsSourceTag; + } + + public MavenSource withNewDirectory(String newDir) { + return new MavenSource( + myIsSourceTag, + myDirectory, + myIncludes, + myExcludes, + myScope, + myLang, + myTargetPath, + myTargetVersion, + myFiltered, + myEnabled + ); + } + + public static boolean isSource(MavenSource src) { + return src.isEnabled() && (src.getScope() == null || src.getScope().equals(MAIN_SCOPE)) && JAVA_LANG.equals(src.getLang()); + } + + public static boolean isTestSource(MavenSource src) { + return src.isEnabled() && src.getScope().equals(TEST_SCOPE) && JAVA_LANG.equals(src.getLang()); + } + + public static boolean isResource(MavenSource src) { + return src.isEnabled() && (src.getScope() == null || src.getScope().equals(MAIN_SCOPE)) && RESOURCES_LANG.equals(src.getLang()); + } + + public static boolean isTestResource(MavenSource src) { + return src.isEnabled() && src.getScope().equals(TEST_SCOPE) && RESOURCES_LANG.equals(src.getLang()); + } + + public static @NotNull MavenSource fromSrc(@NotNull String dir, boolean forTests) { + return new MavenSource(false, dir, Collections.emptyList(), Collections.emptyList(), forTests ? TEST_SCOPE : MAIN_SCOPE, JAVA_LANG, + null, null, + false, true); + } + + public static @NotNull MavenSource fromResource(MavenResource resource, boolean forTests) { + return new MavenSource(false, resource.getDirectory(), resource.getIncludes(), resource.getExcludes(), + forTests ? TEST_SCOPE : MAIN_SCOPE, + RESOURCES_LANG, resource.getTargetPath(), null, resource.isFiltered(), true); + } + + public static MavenSource fromSourceTag(@NotNull String directory, + List includes, + List excludes, + String scope, + String lang, + String targetPath, + String targetVersion, + boolean filtered, + boolean enabled) { + return new MavenSource(true, directory, includes, excludes, scope, lang, targetPath, targetVersion, filtered, enabled); + } + + + @Override + public final boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof MavenSource)) return false; + + MavenSource source = (MavenSource)o; + return myFiltered == source.myFiltered && + myEnabled == source.myEnabled && + Objects.equals(myDirectory, source.myDirectory) && + Objects.equals(myIncludes, source.myIncludes) && + Objects.equals(myExcludes, source.myExcludes) && + Objects.equals(myScope, source.myScope) && + Objects.equals(myLang, source.myLang) && + Objects.equals(myTargetPath, source.myTargetPath) && + Objects.equals(myTargetVersion, source.myTargetVersion); + } + + @Override + public int hashCode() { + int result = Objects.hashCode(myDirectory); + result = 31 * result + Objects.hashCode(myIncludes); + result = 31 * result + Objects.hashCode(myExcludes); + result = 31 * result + Objects.hashCode(myScope); + result = 31 * result + Objects.hashCode(myLang); + result = 31 * result + Objects.hashCode(myTargetPath); + result = 31 * result + Objects.hashCode(myTargetVersion); + result = 31 * result + Boolean.hashCode(myFiltered); + result = 31 * result + Boolean.hashCode(myEnabled); + return result; + } +} + diff --git a/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/server/MavenGoalExecutionResult.java b/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/server/MavenGoalExecutionResult.java index 5993066d529e..945bf2d4c0ec 100644 --- a/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/server/MavenGoalExecutionResult.java +++ b/plugins/maven-server-api/src/main/java/org/jetbrains/idea/maven/server/MavenGoalExecutionResult.java @@ -4,6 +4,7 @@ package org.jetbrains.idea.maven.server; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.maven.model.MavenProjectProblem; import org.jetbrains.idea.maven.model.MavenResource; +import org.jetbrains.idea.maven.model.MavenSource; import java.io.File; import java.io.Serializable; @@ -11,6 +12,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; public class MavenGoalExecutionResult implements Serializable { public final boolean success; @@ -33,42 +35,43 @@ public class MavenGoalExecutionResult implements Serializable { '}'; } + public static class Folders implements Serializable { - private List mySources = Collections.emptyList(); - private List myTestSources = Collections.emptyList(); - private List myResources = Collections.emptyList(); - private List myTestResources = Collections.emptyList(); + private List myMavenSources = Collections.emptyList(); + + public void setMavenSources(List mavenSources) { + myMavenSources = mavenSources; + } + + public List getMavenSources() { + return myMavenSources; + } public List getSources() { - return mySources == null ? Collections.emptyList() : mySources; + return myMavenSources.stream().filter(it -> MavenSource.isSource(it)).map(it -> it.getDirectory()).collect(Collectors.toList()); } - public void setSources(List sources) { - mySources = new ArrayList<>(sources); - } public List getTestSources() { - return myTestSources == null ? Collections.emptyList() : myTestSources; + return myMavenSources.stream().filter(it -> MavenSource.isTestSource(it)).map(it -> it.getDirectory()).collect(Collectors.toList()); } - public void setTestSources(List testSources) { - myTestSources = new ArrayList<>(testSources); - } - - public List getResources() { - return myResources; - } - - public void setResources(List resources) { - myResources = new ArrayList<>(resources); + public void set(List sources, List testSources, List resources, List testResources) { + myMavenSources = new ArrayList<>(); + sources.forEach(it -> myMavenSources.add(MavenSource.fromSrc(it, false))); + testSources.forEach(it -> myMavenSources.add(MavenSource.fromSrc(it, true))); + resources.forEach(it -> myMavenSources.add(MavenSource.fromResource(it, false))); + testResources.forEach(it -> myMavenSources.add(MavenSource.fromResource(it, true))); } public List getTestResources() { - return myTestResources; + return myMavenSources.stream().filter(it -> MavenSource.isTestResource(it)).map(it -> new MavenResource(it)) + .collect(Collectors.toList()); } - public void setTestResources(List testResources) { - myTestResources = new ArrayList<>(testResources); + public List getResources() { + return myMavenSources.stream().filter(it -> MavenSource.isResource(it)).map(it -> new MavenResource(it)) + .collect(Collectors.toList()); } } } diff --git a/plugins/maven-server-api/test/BUILD.bazel b/plugins/maven-server-api/test/BUILD.bazel new file mode 100644 index 000000000000..64c4fcd7503c --- /dev/null +++ b/plugins/maven-server-api/test/BUILD.bazel @@ -0,0 +1,25 @@ +### auto-generated section `build intellij.maven.server.tests` start +load("@rules_jvm//:jvm.bzl", "jvm_library") + +jvm_library( + name = "maven-server-tests_test_lib", + module_name = "intellij.maven.server.tests", + visibility = ["//visibility:public"], + srcs = glob(["java/**/*.kt", "java/**/*.java"], allow_empty = True), + deps = [ + "//plugins/maven-server-api:maven-server", + "//platform/testFramework", + "//platform/testFramework:testFramework_test_lib", + "@lib//:assert_j", + ] +) +### auto-generated section `build intellij.maven.server.tests` end + +### auto-generated section `test intellij.maven.server.tests` start +load("@community//build:tests-options.bzl", "jps_test") + +jps_test( + name = "maven-server-tests_test", + runtime_deps = [":maven-server-tests_test_lib"] +) +### auto-generated section `test intellij.maven.server.tests` end \ No newline at end of file diff --git a/plugins/maven-server-api/test/intellij.maven.server.tests.iml b/plugins/maven-server-api/test/intellij.maven.server.tests.iml new file mode 100644 index 000000000000..2eaeceae411c --- /dev/null +++ b/plugins/maven-server-api/test/intellij.maven.server.tests.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/maven-server-api/test/java/org/jetbrains/idea/maven/model/MavenBuildTest.kt b/plugins/maven-server-api/test/java/org/jetbrains/idea/maven/model/MavenBuildTest.kt new file mode 100644 index 000000000000..345eaf7e9003 --- /dev/null +++ b/plugins/maven-server-api/test/java/org/jetbrains/idea/maven/model/MavenBuildTest.kt @@ -0,0 +1,105 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.idea.maven.model + +import org.assertj.core.api.AssertionsForInterfaceTypes.assertThat +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +class MavenBuildTest { + + @Test + fun `maven sources should present if resources added`() { + val build = MavenBuild() + build.resources = listOf(MavenResource("dir", false, "target", emptyList(), emptyList())) + + assertThat(build.mavenSources).hasSize(1) + assertEquals("resources", build.mavenSources[0].lang) + assertEquals("main", build.mavenSources[0].scope) + assertEquals("dir", build.mavenSources[0].directory) + assertEquals("target", build.mavenSources[0].targetPath) + } + + @Test + fun `maven sources should present if test resources added`() { + val build = MavenBuild() + build.mavenSources = listOf( + MavenSource.fromSourceTag("resDir", + emptyList(), + emptyList(), + "main", + "resources", + "target", + "", false, true), + MavenSource.fromSourceTag("testResDir", + emptyList(), + emptyList(), + "test", + "resources", + "target", + "", false, true)) + assertThat(build.sources).isEmpty() + assertThat(build.testSources).isEmpty() + assertThat(build.resources).containsExactly(MavenResource( + "resDir", false, "target", emptyList(), emptyList() + )) + + assertThat(build.testResources).containsExactly(MavenResource( + "testResDir", false, "target", emptyList(), emptyList() + )) + } + + + @Test + fun `maven resources should present if mavensources added`() { + val build = MavenBuild() + build.testResources = listOf(MavenResource("dir", false, "target", emptyList(), emptyList())) + + assertThat(build.mavenSources).hasSize(1) + assertEquals("resources", build.mavenSources[0].lang) + assertEquals("test", build.mavenSources[0].scope) + assertEquals("dir", build.mavenSources[0].directory) + assertEquals("target", build.mavenSources[0].targetPath) + } + + @Test + fun `maven sources should present if sources added`() { + val build = MavenBuild() + build.sources = listOf("src") + assertThat(build.mavenSources).hasSize(1) + assertEquals("java", build.mavenSources[0].lang) + assertEquals("src", build.mavenSources[0].directory) + assertEquals("main", build.mavenSources[0].scope) + } + + @Test + fun `maven sources should present if test sources added`() { + val build = MavenBuild() + build.testSources = listOf("testSrc") + assertThat(build.mavenSources).hasSize(1) + assertEquals("java", build.mavenSources[0].lang) + assertEquals("testSrc", build.mavenSources[0].directory) + assertEquals("test", build.mavenSources[0].scope) + } + + @Test + fun `sources present if maven sources added`() { + val build = MavenBuild() + build.mavenSources = listOf( + MavenSource.fromSourceTag("srcDir", + emptyList(), + emptyList(), + "main", + "java", + "target", + "", false, true), + MavenSource.fromSourceTag("testDir", + emptyList(), + emptyList(), + "test", + "java", + "target", + "", false, true)) + assertThat(build.sources).containsExactly("srcDir") + assertThat(build.testSources).containsExactly("testDir") + } +} \ No newline at end of file diff --git a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3XServerEmbedder.java b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3XServerEmbedder.java index 57bf48df2f6d..174fe552f08d 100644 --- a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3XServerEmbedder.java +++ b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3XServerEmbedder.java @@ -23,19 +23,11 @@ import org.apache.maven.artifact.resolver.ArtifactResolutionException; import org.apache.maven.artifact.resolver.ArtifactResolver; import org.apache.maven.cli.MavenCli; import org.apache.maven.cli.internal.extension.model.CoreExtension; -import org.apache.maven.execution.DefaultMavenExecutionRequest; -import org.apache.maven.execution.MavenExecutionRequest; -import org.apache.maven.execution.MavenExecutionRequestPopulationException; -import org.apache.maven.execution.MavenExecutionRequestPopulator; -import org.apache.maven.execution.MavenExecutionResult; +import org.apache.maven.execution.*; import org.apache.maven.model.Dependency; import org.apache.maven.model.Model; import org.apache.maven.model.Plugin; -import org.apache.maven.model.building.DefaultModelBuilder; -import org.apache.maven.model.building.FileModelSource; -import org.apache.maven.model.building.ModelBuilder; -import org.apache.maven.model.building.ModelProblem; -import org.apache.maven.model.building.ModelProcessor; +import org.apache.maven.model.building.*; import org.apache.maven.model.interpolation.ModelInterpolator; import org.apache.maven.model.interpolation.StringSearchModelInterpolator; import org.apache.maven.model.io.ModelReader; @@ -74,20 +66,8 @@ import org.eclipse.aether.transfer.ArtifactTransferException; import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.maven.model.MavenArtifact; -import org.jetbrains.idea.maven.model.MavenArtifactInfo; -import org.jetbrains.idea.maven.model.MavenExplicitProfiles; -import org.jetbrains.idea.maven.model.MavenId; -import org.jetbrains.idea.maven.model.MavenModel; -import org.jetbrains.idea.maven.model.MavenProjectProblem; -import org.jetbrains.idea.maven.model.MavenRemoteRepository; -import org.jetbrains.idea.maven.model.MavenWorkspaceMap; -import org.jetbrains.idea.maven.server.embedder.CustomMaven3ArtifactFactory; -import org.jetbrains.idea.maven.server.embedder.CustomMaven3ArtifactResolver; -import org.jetbrains.idea.maven.server.embedder.CustomMaven3ModelInterpolator2; -import org.jetbrains.idea.maven.server.embedder.CustomMaven3RepositoryMetadataManager; -import org.jetbrains.idea.maven.server.embedder.CustomModelValidator385; -import org.jetbrains.idea.maven.server.embedder.Maven3ExecutionResult; +import org.jetbrains.idea.maven.model.*; +import org.jetbrains.idea.maven.server.embedder.*; import org.jetbrains.idea.maven.server.security.MavenToken; import org.jetbrains.idea.maven.server.utils.Maven3SettingsBuilder; import org.jetbrains.idea.maven.server.utils.Maven3XProjectResolver; @@ -98,18 +78,7 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.rmi.RemoteException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Properties; -import java.util.Set; +import java.util.*; /** * Overridden maven components: @@ -707,11 +676,11 @@ public abstract class Maven3XServerEmbedder extends Maven3ServerEmbedder { MavenProject mavenProject = result.getMavenProject(); if (mavenProject == null) return new MavenGoalExecutionResult(false, file, folders, problems); - folders.setSources(mavenProject.getCompileSourceRoots()); - folders.setTestSources(mavenProject.getTestCompileSourceRoots()); - folders.setResources(Maven3ModelConverter.convertResources(mavenProject.getModel().getBuild().getResources())); - folders.setTestResources(Maven3ModelConverter.convertResources(mavenProject.getModel().getBuild().getTestResources())); - + folders.set(mavenProject.getCompileSourceRoots(), + mavenProject.getTestCompileSourceRoots(), + Maven3ModelConverter.convertResources(mavenProject.getModel().getBuild().getResources()), + Maven3ModelConverter.convertResources(mavenProject.getModel().getBuild().getTestResources()) + ); return new MavenGoalExecutionResult(true, file, folders, problems); } diff --git a/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/Maven40ServerEmbedderImpl.java b/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/Maven40ServerEmbedderImpl.java index 8ebf46c4e2c7..e4d58a585241 100644 --- a/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/Maven40ServerEmbedderImpl.java +++ b/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/Maven40ServerEmbedderImpl.java @@ -23,17 +23,14 @@ import org.apache.maven.DefaultMaven; import org.apache.maven.Maven; import org.apache.maven.MavenExecutionException; import org.apache.maven.RepositoryUtils; -import org.apache.maven.api.ArtifactCoordinates; -import org.apache.maven.api.DependencyCoordinates; -import org.apache.maven.api.DownloadedArtifact; -import org.apache.maven.api.Node; -import org.apache.maven.api.PathScope; -import org.apache.maven.api.Session; +import org.apache.maven.api.*; import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.cli.InvokerException; import org.apache.maven.api.cli.InvokerRequest; import org.apache.maven.api.cli.Logger; import org.apache.maven.api.cli.ParserRequest; +import org.apache.maven.api.cli.mvn.MavenOptions; +import org.apache.maven.api.model.Source; import org.apache.maven.api.services.ArtifactResolver; import org.apache.maven.api.services.ArtifactResolverResult; import org.apache.maven.api.services.Lookup; @@ -82,15 +79,7 @@ import org.eclipse.aether.transfer.ArtifactTransferException; import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.maven.model.MavenArchetype; -import org.jetbrains.idea.maven.model.MavenArtifact; -import org.jetbrains.idea.maven.model.MavenArtifactInfo; -import org.jetbrains.idea.maven.model.MavenExplicitProfiles; -import org.jetbrains.idea.maven.model.MavenId; -import org.jetbrains.idea.maven.model.MavenModel; -import org.jetbrains.idea.maven.model.MavenProjectProblem; -import org.jetbrains.idea.maven.model.MavenRemoteRepository; -import org.jetbrains.idea.maven.model.MavenWorkspaceMap; +import org.jetbrains.idea.maven.model.*; import org.jetbrains.idea.maven.server.LongRunningTask; import org.jetbrains.idea.maven.server.LongRunningTaskInput; import org.jetbrains.idea.maven.server.MavenArtifactResolutionRequest; @@ -865,14 +854,29 @@ public class Maven40ServerEmbedderImpl extends MavenServerEmbeddedBase { MavenProject mavenProject = result.getMavenProject(); if (mavenProject == null) return new MavenGoalExecutionResult(false, file, folders, problems); - folders.setSources(mavenProject.getCompileSourceRoots()); - folders.setTestSources(mavenProject.getTestCompileSourceRoots()); - folders.setResources(Maven40ModelConverter.convertResources(mavenProject.getModel().getBuild().getResources())); - folders.setTestResources(Maven40ModelConverter.convertResources(mavenProject.getModel().getBuild().getTestResources())); + folders.setMavenSources(convertSourceRoots(mavenProject.getSourceRoots())); return new MavenGoalExecutionResult(true, file, folders, problems); } + private static List convertSourceRoots(List roots) { + List list = new ArrayList<>(); + for (Source it : roots) { + MavenSource convert = Maven40ModelConverter.convert(it); + list.add(convert); + } + return list; + } + + private static List convertSourceRoots(Collection roots) { + List list = new ArrayList<>(); + for (SourceRoot it : roots) { + MavenSource convert = Maven40ModelConverter.convert(it); + list.add(convert); + } + return list; + } + private static List filterExceptions(List list) { for (Throwable throwable : list) { if (!(throwable instanceof Exception)) { diff --git a/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/utils/Maven40AetherModelConverter.java b/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/utils/Maven40AetherModelConverter.java index 33e99ba98155..e178ad7012e6 100644 --- a/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/utils/Maven40AetherModelConverter.java +++ b/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/utils/Maven40AetherModelConverter.java @@ -52,10 +52,7 @@ public final class Maven40AetherModelConverter extends Maven40ModelConverter { result.setProfiles(convertProfiles(model.getProfiles())); result.setModules(mavenProject.getModules()); - convertBuild(result.getBuild(), model.getBuild(), - //mavenProject.getCompileSourceRoots(), mavenProject.getTestCompileSourceRoots() - Collections.singletonList(model.getBuild().getSourceDirectory()), Collections.singletonList(model.getBuild().getTestSourceDirectory()) - ); + convertBuild(result.getBuild(), model.getBuild()); return result; } diff --git a/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/utils/Maven40ApiModelConverter.java b/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/utils/Maven40ApiModelConverter.java index dca865b55430..d2e82a42b62e 100644 --- a/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/utils/Maven40ApiModelConverter.java +++ b/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/utils/Maven40ApiModelConverter.java @@ -1,279 +1,17 @@ // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.maven.server.m40.utils; -import com.intellij.util.ReflectionUtilRt; import org.apache.maven.api.Artifact; -import org.apache.maven.api.model.*; -import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy; -import org.codehaus.plexus.util.xml.Xpp3Dom; -import org.jdom.Element; -import org.jdom.IllegalNameException; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.idea.maven.model.*; -import org.jetbrains.idea.maven.server.MavenServerGlobals; +import org.jetbrains.idea.maven.model.MavenArtifact; import java.io.File; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.nio.file.Path; -import java.util.*; public final class Maven40ApiModelConverter { - public static @NotNull MavenModel convertModel(Model model) { - Build build = model.getBuild(); - return convertModel( - model, - asSourcesList(build.getSourceDirectory()), - asSourcesList(build.getTestSourceDirectory())); - } - - private static @NotNull MavenModel convertModel(Model model, - List sources, - List testSources) { - MavenModel result = new MavenModel(); - result.setMavenId(new MavenId(model.getGroupId(), model.getArtifactId(), model.getVersion())); - - Parent parent = model.getParent(); - if (parent != null) { - result.setParent(new MavenParent( - new MavenId(parent.getGroupId(), parent.getArtifactId(), parent.getVersion()), parent.getRelativePath())); - } - result.setPackaging(model.getPackaging()); - result.setName(model.getName()); - result.setProperties(model.getProperties()); - result.setPlugins(convertPlugins(model)); - - result.setRemoteRepositories(convertRepositories(model.getRepositories())); - result.setRemotePluginRepositories(convertRepositories(model.getPluginRepositories())); - result.setProfiles(convertProfiles(model.getProfiles())); - result.setModules(model.getModules()); - - convertBuild(result.getBuild(), model.getBuild(), sources, testSources); - return result; - } - - private static List convertPlugins(Model mavenModel) { - List result = new ArrayList<>(); - Build build = mavenModel.getBuild(); - - if (build != null) { - List plugins = build.getPlugins(); - if (plugins != null) { - for (Plugin each : plugins) { - result.add(convertPlugin(false, each)); - } - } - } - - return result; - } - - private static MavenPlugin convertPlugin(boolean isDefault, Plugin plugin) { - List executions = new ArrayList<>(plugin.getExecutions().size()); - for (PluginExecution each : plugin.getExecutions()) { - executions.add(convertExecution(each)); - } - - List deps = new ArrayList<>(plugin.getDependencies().size()); - for (Dependency each : plugin.getDependencies()) { - deps.add(new MavenId(each.getGroupId(), each.getArtifactId(), each.getVersion())); - } - - return new MavenPlugin(plugin.getGroupId(), - plugin.getArtifactId(), - plugin.getVersion(), - isDefault, - "true".equals(plugin.getExtensions()), - convertConfiguration(plugin.getConfiguration()), - executions, deps); - } - - private static MavenPlugin.Execution convertExecution(PluginExecution execution) { - return new MavenPlugin.Execution(execution.getId(), execution.getPhase(), execution.getGoals(), convertConfiguration(execution.getConfiguration())); - } - - private static Element convertConfiguration(Object config) { - return config == null ? null : xppToElement((Xpp3Dom)config); - } - - private static Element xppToElement(Xpp3Dom xpp) { - Element result; - try { - result = new Element(xpp.getName()); - } - catch (IllegalNameException e) { - MavenServerGlobals.getLogger().info(e); - return null; - } - - Xpp3Dom[] children = xpp.getChildren(); - if (children == null || children.length == 0) { - result.setText(xpp.getValue()); - } - else { - for (Xpp3Dom each : children) { - Element child = xppToElement(each); - if (child != null) result.addContent(child); - } - } - return result; - } - - private static List asSourcesList(String directory) { - return directory == null ? Collections.emptyList() : Collections.singletonList(directory); - } - - private static void convertBuild(MavenBuild result, Build build, List sources, List testSources) { - convertBuildBase(result, build); - result.setOutputDirectory(build.getOutputDirectory()); - result.setTestOutputDirectory(build.getTestOutputDirectory()); - result.setSources(sources); - result.setTestSources(testSources); - } - - private static void convertBuildBase(MavenBuildBase result, BuildBase build) { - result.setFinalName(build.getFinalName()); - result.setDefaultGoal(build.getDefaultGoal()); - result.setDirectory(build.getDirectory()); - result.setResources(convertResources(build.getResources())); - result.setTestResources(convertResources(build.getTestResources())); - result.setFilters(build.getFilters() == null ? Collections.emptyList() : build.getFilters()); - } - - private static List convertResources(List resources) { - if (resources == null) return new ArrayList(); - - List result = new ArrayList(resources.size()); - for (Resource each : resources) { - String directory = each.getDirectory(); - - if (null == directory) continue; - - result.add(new MavenResource(directory, - each.isFiltering(), - each.getTargetPath(), - ensurePatterns(each.getIncludes()), - ensurePatterns(each.getExcludes()))); - } - return result; - } - - private static List ensurePatterns(List patterns) { - return patterns == null ? Collections.emptyList() : patterns; - } - - private static List convertRepositories(List repositories) { - if (repositories == null) return new ArrayList(); - - List result = new ArrayList(repositories.size()); - for (Repository each : repositories) { - result.add(new MavenRemoteRepository(each.getId(), - each.getName(), - each.getUrl(), - each.getLayout(), - convertPolicy(each.getReleases()), - convertPolicy(each.getSnapshots()))); - } - return result; - } - - private static MavenRemoteRepository.Policy convertPolicy(RepositoryPolicy policy) { - return policy != null - ? new MavenRemoteRepository.Policy(policy.isEnabled(), policy.getUpdatePolicy(), policy.getChecksumPolicy()) - : null; - } - - private static MavenRemoteRepository.Policy convertPolicy(ArtifactRepositoryPolicy policy) { - return policy != null - ? new MavenRemoteRepository.Policy(policy.isEnabled(), policy.getUpdatePolicy(), policy.getChecksumPolicy()) - : null; - } - private static String convertExtension(Artifact artifact) { return artifact.getExtension(); } - private static List convertProfiles(Collection profiles) { - if (profiles == null) return Collections.emptyList(); - List result = new ArrayList(); - for (Profile each : profiles) { - String id = each.getId(); - if (id == null) continue; - MavenProfile profile = new MavenProfile(id, each.getSource()); - List modules = each.getModules(); - profile.setModules(modules == null ? Collections.emptyList() : modules); - profile.setActivation(convertActivation(each.getActivation())); - if (each.getBuild() != null) convertBuildBase(profile.getBuild(), each.getBuild()); - result.add(profile); - } - return result; - } - - private static MavenProfileActivation convertActivation(Activation activation) { - if (activation == null) return null; - - MavenProfileActivation result = new MavenProfileActivation(); - result.setActiveByDefault(activation.isActiveByDefault()); - result.setOs(convertOsActivation(activation.getOs())); - result.setJdk(activation.getJdk()); - result.setFile(convertFileActivation(activation.getFile())); - result.setProperty(convertPropertyActivation(activation.getProperty())); - return result; - } - - private static MavenProfileActivationOS convertOsActivation(ActivationOS os) { - return os == null ? null : new MavenProfileActivationOS(os.getName(), os.getFamily(), os.getArch(), os.getVersion()); - } - - private static MavenProfileActivationFile convertFileActivation(ActivationFile file) { - return file == null ? null : new MavenProfileActivationFile(file.getExists(), file.getMissing()); - } - - private static MavenProfileActivationProperty convertPropertyActivation(ActivationProperty property) { - return property == null ? null : new MavenProfileActivationProperty(property.getName(), property.getValue()); - } - - private static boolean isNativeToString(String toStringResult, Object o) { - String className = o.getClass().getName(); - return (toStringResult.startsWith(className) && toStringResult.startsWith("@", className.length())); - } - - private static void doConvert(Object object, String prefix, Map result) - throws IllegalAccessException, InvocationTargetException { - for (Method each : ReflectionUtilRt.collectGetters(object.getClass())) { - Class type = each.getReturnType(); - if (shouldSkip(type)) continue; - - each.setAccessible(true); - Object value = each.invoke(object); - - if (value != null) { - String key = each.getName().substring(3); - String name = prefix + key.substring(0, 1).toLowerCase() + key.substring(1); - - if (value instanceof String || value.getClass().isPrimitive()) { - String sValue = String.valueOf(value); - if (!isNativeToString(sValue, value)) { - result.put(name, sValue); - } - } - else { - Package pack = type.getPackage(); - if (pack != null && pack.getName().startsWith("org.apache.maven")) { - doConvert(value, name + ".", result); - } - } - } - } - } - - private static boolean shouldSkip(Class clazz) { - return clazz.isArray() - || Collection.class.isAssignableFrom(clazz) - || Map.class.isAssignableFrom(clazz) - || Xpp3Dom.class.isAssignableFrom(clazz); - } - public static MavenArtifact convertArtifactAndPath(Artifact artifact, Path artifactPath, File localRepository) { return new MavenArtifact(artifact.getGroupId(), artifact.getArtifactId(), diff --git a/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/utils/Maven40ModelConverter.java b/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/utils/Maven40ModelConverter.java index 11cfe252dc3f..b0277f63d386 100644 --- a/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/utils/Maven40ModelConverter.java +++ b/plugins/maven/maven40-server-impl/src/com/intellij/maven/server/m40/utils/Maven40ModelConverter.java @@ -2,6 +2,7 @@ package com.intellij.maven.server.m40.utils; import com.intellij.util.ReflectionUtilRt; +import org.apache.maven.api.SourceRoot; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.handler.ArtifactHandler; import org.apache.maven.artifact.repository.ArtifactRepository; @@ -24,15 +25,6 @@ public class Maven40ModelConverter { if (model.getBuild() == null) { model.setBuild(new Build()); } - Build build = model.getBuild(); - return convertModel(model, - asSourcesList(build.getSourceDirectory()), - asSourcesList(build.getTestSourceDirectory())); - } - - public static @NotNull MavenModel convertModel(Model model, - List sources, - List testSources) { MavenModel result = new MavenModel(); result.setMavenId(new MavenId(model.getGroupId(), model.getArtifactId(), model.getVersion())); @@ -51,7 +43,7 @@ public class Maven40ModelConverter { result.setProfiles(convertProfiles(model.getProfiles())); result.setModules(model.getModules()); - convertBuild(result.getBuild(), model.getBuild(), sources, testSources); + convertBuild(result.getBuild(), model.getBuild()); return result; } @@ -140,20 +132,76 @@ public class Maven40ModelConverter { return directory == null ? Collections.emptyList() : Collections.singletonList(directory); } - public static void convertBuild(MavenBuild result, Build build, List sources, List testSources) { + public static void convertBuild(MavenBuild result, Build build) { convertBuildBase(result, build); result.setOutputDirectory(build.getOutputDirectory()); result.setTestOutputDirectory(build.getTestOutputDirectory()); - result.setSources(sources); - result.setTestSources(testSources); + setupSourceDirectories(result, build); + } + + + private static void setupSourceDirectories(MavenBuild result, Build build) { + + /* + * `sourceDirectory`, `testSourceDirectory` and `scriptSourceDirectory` + * are ignored if the POM file contains at least one element + * for the corresponding scope and language. This rule exists because + * Maven provides default values for those elements which may conflict + * with user's configuration. + */ + List sourceList = build.getDelegate().getSources(); + if (sourceList.isEmpty()) { + List sources = asSourcesList(build.getSourceDirectory()); + List testSources = asSourcesList(build.getTestSourceDirectory()); + result.setSources(sources); + result.setTestSources(testSources); + result.setResources(convertResources(build.getResources())); + result.setTestResources(convertResources(build.getTestResources())); + } + else { + List list = new ArrayList<>(); + for (org.apache.maven.api.model.Source it : sourceList) { + MavenSource source = convert(it); + list.add(source); + } + result.setMavenSources(list); + } + } + + public static @NotNull MavenSource convert(org.apache.maven.api.model.Source it) { + return MavenSource.fromSourceTag( + it.getDirectory(), + it.getIncludes(), + it.getExcludes(), + it.getScope(), + it.getLang(), + it.getTargetPath(), + it.getTargetVersion(), + it.isStringFiltering(), + it.isEnabled() + ); + } + + public static @NotNull MavenSource convert(SourceRoot it) { + var scope = it.scope() == null ? null : it.scope().id(); + var lang = it.language() == null ? null : it.language().id(); + return MavenSource.fromSourceTag( + it.directory().toString(), + Collections.emptyList(), + Collections.emptyList(), + scope, + lang, + it.targetPath().map(tp -> tp.toString()).orElse(null), + it.targetVersion().map(tv -> tv.toString()).orElse(null), + it.stringFiltering(), + it.enabled() + ); } private static void convertBuildBase(MavenBuildBase result, BuildBase build) { result.setFinalName(build.getFinalName()); result.setDefaultGoal(build.getDefaultGoal()); result.setDirectory(build.getDirectory()); - result.setResources(convertResources(build.getResources())); - result.setTestResources(convertResources(build.getTestResources())); result.setFilters(build.getFilters() == null ? Collections.emptyList() : build.getFilters()); } @@ -171,10 +219,10 @@ public class Maven40ModelConverter { if (null == directory) continue; result.add(new MavenResource(directory, - each.isFiltering(), - each.getTargetPath(), - ensurePatterns(each.getIncludes()), - ensurePatterns(each.getExcludes()))); + each.isFiltering(), + each.getTargetPath(), + ensurePatterns(each.getIncludes()), + ensurePatterns(each.getExcludes()))); } return result; } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/converters/MavenSourceLangConverter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/converters/MavenSourceLangConverter.java new file mode 100644 index 000000000000..a35bba1a2d8b --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/converters/MavenSourceLangConverter.java @@ -0,0 +1,18 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.idea.maven.dom.converters; + +import com.intellij.openapi.util.NlsSafe; +import com.intellij.util.xml.ConvertContext; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.maven.model.MavenSource; + +import java.util.Collection; +import java.util.List; + +public class MavenSourceLangConverter extends MavenConstantListConverter { + + @Override + protected Collection<@NlsSafe String> getValues(@NotNull ConvertContext context) { + return List.of(MavenSource.JAVA_LANG, MavenSource.RESOURCES_LANG); + } +} diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/converters/MavenSourceScopeConverter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/converters/MavenSourceScopeConverter.java new file mode 100644 index 000000000000..04020ff83166 --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/converters/MavenSourceScopeConverter.java @@ -0,0 +1,40 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.idea.maven.dom.converters; + +import com.intellij.openapi.util.NlsSafe; +import com.intellij.util.xml.ConvertContext; +import com.intellij.util.xml.DomElement; +import com.intellij.util.xml.ResolvingConverter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Unmodifiable; +import org.jetbrains.idea.maven.model.MavenSource; + +import java.util.Collection; +import java.util.List; + +public class MavenSourceScopeConverter extends ResolvingConverter implements MavenDomSoftAwareConverter { + + @Override + public @Unmodifiable @NotNull Collection getVariants(@NotNull ConvertContext context) { + return List.of(MavenSource.MAIN_SCOPE, MavenSource.TEST_SCOPE); + } + + @Override + public @Nullable String fromString(@Nullable String s, @NotNull ConvertContext context) { + if (s == null) { + return MavenSource.MAIN_SCOPE; + } + return s; + } + + @Override + public @Nullable String toString(@Nullable String s, @NotNull ConvertContext context) { + return s; + } + + @Override + public boolean isSoft(@NotNull DomElement element) { + return true; + } +} diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/model/MavenDomBuild.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/model/MavenDomBuild.java index 964ae827236e..cf568baceaae 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/model/MavenDomBuild.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/model/MavenDomBuild.java @@ -117,4 +117,10 @@ public interface MavenDomBuild extends MavenDomBuildBase { */ @NotNull MavenDomExtensions getExtensions(); + + + + @NotNull + MavenDomSources getSources(); + } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/model/MavenDomSource.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/model/MavenDomSource.java new file mode 100644 index 000000000000..063a0b27a5ee --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/model/MavenDomSource.java @@ -0,0 +1,55 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.idea.maven.dom.model; + +import com.intellij.openapi.paths.PathReference; +import com.intellij.psi.PsiFile; +import com.intellij.util.xml.Convert; +import com.intellij.util.xml.GenericDomValue; +import com.intellij.util.xml.Required; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.maven.dom.converters.MavenDependencyTypeConverter; +import org.jetbrains.idea.maven.dom.converters.MavenParentRelativePathConverter; +import org.jetbrains.idea.maven.dom.converters.MavenSourceLangConverter; +import org.jetbrains.idea.maven.dom.converters.MavenSourceScopeConverter; +import org.jetbrains.idea.maven.dom.references.MavenDirectoryPathReferenceConverter; + +import java.util.List; + +public interface MavenDomSource { + + @NotNull + @Required(value = true, nonEmpty = true) + @Convert(value = MavenDirectoryPathReferenceConverter.class, soft = true) + GenericDomValue getDirectory(); + + @NotNull + MavenDomIncludes getIncludes(); + + @NotNull + MavenDomExcludes getExcludes(); + + @NotNull + @Convert(MavenSourceScopeConverter.class) + GenericDomValue getScope(); + + @NotNull + @Required(value = false, nonEmpty = true) + @Convert(MavenSourceLangConverter.class) + GenericDomValue getLang(); + + @NotNull + GenericDomValue getModule(); + + @NotNull + GenericDomValue getTargetVersion(); + + @NotNull + @Convert(value = MavenDirectoryPathReferenceConverter.class, soft = true) + GenericDomValue getTargetPath(); + + @NotNull + GenericDomValue isFiltering(); + + @NotNull + GenericDomValue isEnabled(); +} diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/model/MavenDomSources.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/model/MavenDomSources.java new file mode 100644 index 000000000000..70d08dc9f0c7 --- /dev/null +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/model/MavenDomSources.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2009 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Generated on Mon Mar 17 18:02:09 MSK 2008 +// DTD/Schema : http://maven.apache.org/POM/4.0.0 + +package org.jetbrains.idea.maven.dom.model; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.maven.dom.MavenDomElement; + +import java.util.List; + +/** + * http://maven.apache.org/POM/4.1.0:sources interface. + */ +public interface MavenDomSources extends MavenDomElement { + + /** + * Returns the list of sources + * + * @return the list of sources children. + */ + @NotNull + List getSources(); + + /** + * Adds new child to the list of sources children. + * + * @return created child + */ + MavenDomSource addSource(); +} diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImportUtil.kt b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImportUtil.kt index 4c70bdca62c8..a44981f72ef8 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImportUtil.kt +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenImportUtil.kt @@ -37,6 +37,7 @@ import org.jetbrains.annotations.ApiStatus import org.jetbrains.idea.maven.config.MavenConfigSettings import org.jetbrains.idea.maven.model.MavenArtifact import org.jetbrains.idea.maven.model.MavenPlugin +import org.jetbrains.idea.maven.model.MavenSource import org.jetbrains.idea.maven.project.* import org.jetbrains.idea.maven.project.MavenProject.ProcMode import org.jetbrains.idea.maven.server.MavenDistribution @@ -204,11 +205,27 @@ object MavenImportUtil { val executionId: String? = null, ) { fun getMavenLanguageLevel(): LanguageLevel? { + val scope = if (isTest) MavenSource.TEST_SCOPE else MavenSource.MAIN_SCOPE + val resultMaven4Source = mavenProject + .mavenSources + .filter { it.isFromSourceTag && it.isEnabled } + .filter { it.scope == scope } + .filter { it.lang == null || it.lang == MavenSource.JAVA_LANG } + .firstNotNullOfOrNull { it.targetVersion } + + if (resultMaven4Source != null) { + return LanguageLevel.parse(resultMaven4Source) + } + val useReleaseCompilerProp = isReleaseCompilerProp(mavenProject) val releaseLevel = if (useReleaseCompilerProp) getCompilerLevel("release") else null return releaseLevel ?: getCompilerLevel(if (isSource) "source" else "target") } + private fun useMaven4Sources(mavenProject: MavenProject): Boolean { + return mavenProject.mavenSources.any { it.isFromSourceTag } + } + private fun getConfigs(): List { if (null != executionId) return compilerExecutions(mavenProject) .filter { it.executionId == executionId } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.kt b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.kt index 096e5c7d9374..23738bb6cdb8 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.kt +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.kt @@ -188,10 +188,7 @@ class MavenProject(val file: VirtualFile) { @Internal fun setFolders(folders: MavenGoalExecutionResult.Folders): MavenProjectChanges { val newState = myState.copy( - sources = folders.sources, - testSources = folders.testSources, - resources = folders.resources, - testResources = folders.testResources, + mavenSources = folders.mavenSources ) return setState(newState) } @@ -264,17 +261,32 @@ class MavenProject(val file: VirtualFile) { val testOutputDirectory: @NlsSafe String get() = myState.testOutputDirectory!! + val mavenSources: List + get() = myState.mavenSources + + /** + * use mavenSources instead + */ val sources: List - get() = myState.sources + @ApiStatus.Obsolete get() = myState.mavenSources.filter { MavenSource.isSource(it) }.map { it.directory } + /** + * use mavenSources instead + */ val testSources: List - get() = myState.testSources + @ApiStatus.Obsolete get() = myState.mavenSources.filter { MavenSource.isTestSource(it) }.map { it.directory } + /** + * use mavenSources instead + */ val resources: List - get() = myState.resources + @ApiStatus.Obsolete get() = myState.mavenSources.filter { MavenSource.isResource(it) }.map { MavenResource(it) } + /** + * use mavenSources instead + */ val testResources: List - get() = myState.testResources + @ApiStatus.Obsolete get() = myState.mavenSources.filter { MavenSource.isTestResource(it) }.map { MavenResource(it) } val filters: List get() = myState.filters @@ -930,10 +942,7 @@ class MavenProject(val file: VirtualFile) { modulesPathsAndNames = collectModulePathsAndNames(model, directory, fileExtension), profilesIds = collectProfilesIds(model.profiles) + if (keepPreviousProfiles) state.profilesIds else emptySet(), modelMap = nativeModelMap, - sources = build.sources, - testSources = build.testSources, - resources = build.resources, - testResources = build.testResources, + mavenSources = build.mavenSources, unresolvedArtifactIds = newUnresolvedArtifacts, remoteRepositories = remoteRepositories, remotePluginRepositories = remotePluginRepositories, diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectReader.kt b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectReader.kt index 54e8f07b9e13..ca2fdcb7949d 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectReader.kt +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectReader.kt @@ -167,7 +167,8 @@ class MavenProjectReader( } private fun readModelBody(mavenModelBase: MavenModelBase, mavenBuildBase: MavenBuildBase, xmlModel: Element, projectFile: VirtualFile) { - val modules = findSubprojects(xmlModel, projectFile) + val modelVersion = xmlModel.getModelVersion() + val modules = if (isMaven4Model(modelVersion)) findSubprojects(xmlModel, projectFile) else findModules(xmlModel) mavenModelBase.modules = myReadHelper.filterModules(modules, projectFile) collectProperties(findChildByPath(xmlModel, "properties"), mavenModelBase) @@ -176,23 +177,62 @@ class MavenProjectReader( mavenBuildBase.finalName = findChildValueByPath(xmlBuild, "finalName") mavenBuildBase.defaultGoal = findChildValueByPath(xmlBuild, "defaultGoal") mavenBuildBase.directory = findChildValueByPath(xmlBuild, "directory") - mavenBuildBase.resources = collectResources( - findChildrenByPath(xmlBuild, "resources", "resource")) - mavenBuildBase.testResources = collectResources( - findChildrenByPath(xmlBuild, "testResources", "testResource")) + + if (isMaven4Model(modelVersion)) { + mavenBuildBase.mavenSources = collectMavenSources(xmlBuild) + } + else { + mavenBuildBase.resources = collectResources( + findChildrenByPath(xmlBuild, "resources", "resource")) + mavenBuildBase.testResources = collectResources( + findChildrenByPath(xmlBuild, "testResources", "testResource")) + if (mavenBuildBase is MavenBuild) { + val source = findChildValueByPath(xmlBuild, "sourceDirectory") + if (!source.isNullOrBlank()) mavenBuildBase.sources = listOf(source) + val testSource = findChildValueByPath(xmlBuild, "testSourceDirectory") + if (!testSource.isNullOrBlank()) mavenBuildBase.testSources = listOf(testSource) + } + } + + mavenBuildBase.filters = findChildrenValuesByPath(xmlBuild, "filters", "filter") if (mavenBuildBase is MavenBuild) { - val source = findChildValueByPath(xmlBuild, "sourceDirectory") - if (!source.isNullOrBlank()) mavenBuildBase.sources = listOf(source) - val testSource = findChildValueByPath(xmlBuild, "testSourceDirectory") - if (!testSource.isNullOrBlank()) mavenBuildBase.testSources = listOf(testSource) - mavenBuildBase.outputDirectory = findChildValueByPath(xmlBuild, "outputDirectory") mavenBuildBase.testOutputDirectory = findChildValueByPath(xmlBuild, "testOutputDirectory") } } + private fun collectMavenSources(xmlBuild: Element?): List { + if (xmlBuild == null) return emptyList() + val xmlSources = findChildrenByPath(xmlBuild, "sources", "source") + val result: MutableList = ArrayList() + for (each in xmlSources) { + + val targetPath = findChildValueByPath(each, "targetPath") + val targetVersion = findChildValueByPath(each, "targetVersion") + val scope = findChildValueByPath(each, "scope") ?: MavenSource.MAIN_SCOPE + val lang = findChildValueByPath(each, "lang") ?: MavenSource.JAVA_LANG + val includes = findChildrenValuesByPath(each, "includes", "include") + val excludes = findChildrenValuesByPath(each, "excludes", "exclude") + val filtered = "true" == findChildValueByPath(each, "filtering") + val enabled = "true" == findChildValueByPath(each, "enabled") + val directory = findChildValueByPath(each, "directory") ?: "src/${scope}/${lang}" + result.add(MavenSource.fromSourceTag( + directory, + includes, + excludes, + scope, + lang, + targetPath, + targetVersion, + filtered, + enabled + )) + } + return result + } + private fun Element.getModelVersion() = this.getChild("modelVersion")?.value private fun collectResources(xmlResources: List): List { @@ -226,32 +266,28 @@ class MavenProjectReader( } private fun findSubprojects(xmlModel: Element, projectFile: VirtualFile): List { - val modelVersion = xmlModel.getModelVersion() + val subprojects = findChildrenValuesByPath(xmlModel, "subprojects", "subproject") + if (!subprojects.isEmpty()) return subprojects - if (modelVersion != null && StringUtil.compareVersionNumbers(modelVersion, MODEL_VERSION_4_0_0) > 0) { - val subprojects = findChildrenValuesByPath(xmlModel, "subprojects", "subproject") - if (!subprojects.isEmpty()) return subprojects + val modules = findModules(xmlModel) + if (!modules.isEmpty()) return modules - val modules = findModules(xmlModel) - if (!modules.isEmpty()) return modules + if (MavenConstants.TYPE_POM != xmlModel.getChild("packaging")?.value) return emptyList() - if (MavenConstants.TYPE_POM != xmlModel.getChild("packaging")?.value) return emptyList() - - // subprojects discovery - // see org.apache.maven.internal.impl.model.DefaultModelBuilder.DefaultModelBuilderSession#doReadFileModel - return projectFile.parent.children.filter { it.hasPomFile() }.map { it.name } - } - - return findModules(xmlModel) + // subprojects discovery + // see org.apache.maven.internal.impl.model.DefaultModelBuilder.DefaultModelBuilderSession#doReadFileModel + return projectFile.parent.children.filter { it.hasPomFile() }.map { it.name } } + private fun isMaven4Model(modelVersion: String?): Boolean = modelVersion != null && StringUtil.compareVersionNumbers(modelVersion, MODEL_VERSION_4_0_0) > 0 + private fun findModules(xmlModel: Element): List = findChildrenValuesByPath(xmlModel, "modules", "module") private suspend fun resolveInheritance( model: MavenModel, file: VirtualFile, problems: MutableCollection, - recursionGuard: MutableSet + recursionGuard: MutableSet, ): MavenModel { if (recursionGuard.contains(file)) { problems.add(MavenProjectProblem.createProblem( @@ -329,7 +365,7 @@ class MavenProjectReader( private suspend fun readRawResult( projectFile: VirtualFile, parentDesc: MavenParentDesc?, - recursionGuard: MutableSet + recursionGuard: MutableSet, ): Pair? { if (parentDesc == null) { return null diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectState.kt b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectState.kt index 03f8112ed15c..a27f321a21ca 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectState.kt +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectState.kt @@ -26,10 +26,7 @@ data class MavenProjectState( val buildDirectory: String? = null, val outputDirectory: String? = null, val testOutputDirectory: String? = null, - val sources: List = emptyList(), - val testSources: List = emptyList(), - val resources: List = emptyList(), - val testResources: List = emptyList(), + val mavenSources: List = emptyList(), val filters: List = emptyList(), val properties: Properties? = null, val extensions: List = emptyList(), @@ -69,10 +66,7 @@ data class MavenProjectState( || outputDirectory != newState.outputDirectory || testOutputDirectory != newState.testOutputDirectory) - result.setHasSourceChanges(!Comparing.equal(sources, newState.sources) - || !Comparing.equal(testSources, newState.testSources) - || !Comparing.equal(resources, newState.resources) - || !Comparing.equal(testResources, newState.testResources)) + result.setHasSourceChanges(!Comparing.equal(mavenSources, newState.mavenSources)) val repositoryChanged = !Comparing.equal(localRepository, newState.localRepository) diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.kt b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.kt index 20e7139f2dcb..7e9a8cdd0c6f 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.kt +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.kt @@ -1094,7 +1094,7 @@ class MavenProjectsTree(val project: Project) { companion object { private val LOG = Logger.getInstance(MavenProjectsTree::class.java) - private const val STORAGE_VERSION_NUMBER = 14 + private const val STORAGE_VERSION_NUMBER = 15 val STORAGE_VERSION: String = MavenProjectsTree::class.java.simpleName + "." + STORAGE_VERSION_NUMBER private fun String.getStorageVersionNumber(): Int { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenBuildPathsChange.kt b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenBuildPathsChange.kt index ac03c47c812c..c2d8d4b897d6 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenBuildPathsChange.kt +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenBuildPathsChange.kt @@ -1,7 +1,6 @@ // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.idea.maven.server -import com.intellij.util.containers.ContainerUtil import org.jdom.Element import org.jetbrains.idea.maven.model.* import java.io.File @@ -27,21 +26,14 @@ class MavenBuildPathsChange( } private fun MavenBuild.transformPaths() { - sources = ContainerUtil.map(sources) { transformer(it) } - testSources = ContainerUtil.map(testSources) { transformer(it) } directory = transformer(directory) outputDirectory = transformer(outputDirectory) testOutputDirectory = transformer(testOutputDirectory) - resources = resources.map { it.transformPaths() } - testResources = testResources.map { it.transformPaths() } + mavenSources = mavenSources.map { it.transformPaths() } } - private fun MavenResource.transformPaths() = MavenResource( - transformer(directory), - isFiltered, - targetPath /*todo*/, - includes, - excludes + private fun MavenSource.transformPaths() = this.withNewDirectory( + transformer(directory) ) private fun MavenArtifact.transformPaths(): MavenArtifact { diff --git a/plugins/maven/src/main/resources/schemas/maven-4.1.0.xsd b/plugins/maven/src/main/resources/schemas/maven-4.1.0.xsd index 921bdb607237..a17d0c145632 100644 --- a/plugins/maven/src/main/resources/schemas/maven-4.1.0.xsd +++ b/plugins/maven/src/main/resources/schemas/maven-4.1.0.xsd @@ -2355,6 +2355,23 @@ + + + 4.1.0+ + + All the sources to compile and resources files to copy for a project or it's unit tests. + The sources can be Java source files, generated source files, scripts or resources for examples. + Each source is specified by a mandatory {@code directory} element, which is relative to the POM. + The kind of sources (codes to compile or resources to copy) and their usage (for the main code or for the tests) is specified by the + {@code <scope>} element together with each source directory. + + + + + + + + 3.0.0+ @@ -2510,6 +2527,84 @@ + + + 4.1.0+ + Description of the sources associated with a project main code or unit tests. The sources can be Java source files, generated source files, scripts or resources for examples. A source is specified by a mandatory {@code directory} element, which is relative to the POM. The directory content can optionally by reduced to a subset with the {@code includes} and {@code excludes} elements. The kind of sources (codes, resources, etc.) and their usage (main code, tests, etc.) is specified by the {@code scope} element.

Default source directories

If no source directories are specified, the defaults are {@code src/${scope}/${lang}} where {@code ${scope}} is the value of the {@link #scope} element (typically {@code main} or {@code test}) and {@code ${lang}} is the value of the {@link #lang} element (typically {@code java} or {@code resources}).
+
+ + + + 4.1.0+ + Specifies in which context the source files will be used - typically {@code main} or {@code test}.

The main scope is used for specifying a directory containing the source of the project. The generated build system will compile the sources from this directory when the project is built. The path given in the {@code directory} field is relative to the project descriptor. The default directory for the default language (Java) is {@code "src/main/java"}.

The test scope is used for specifying a directory containing the unit test source of the project. The generated build system will compile these directories when the project is being tested. The path given in the {@code directory} field is relative to the project descriptor. The default directory for the default language (Java) is {@code "src/test/java"}.

If no scope is specified, the default is {@code main}.

+
+
+ + + 4.1.0+ + Specifies the language of the source files - typically {@code java} or {@code resources}. Resources is used as a generic term for scripting languages (e.g., JavaScript or Python) or markup languages (e.g. properties file, JSON or XML).

The java language is used for specifying a directory containing the Java sources of the project. The generated build system will compile the sources from this directory using the Java compiler when the project is built. The path given in the {@code directory} field is relative to the project descriptor. The default directory for the main Java sources is {@code "src/main/java"}.

The resources language is used for specifying a directory containing the class-path or module-path resources such as properties files or scripts associated with a project. This directory is meant to be different from the main source directory, in that its contents will be copied to the output directory in most cases (since scripts are interpreted rather than compiled). The default directory for the main resources is {@code "src/main/resources"}.

If no language is specified, the default is {@code java}.

+
+
+ + + 4.1.0+ + Name of the Java module (or other language-specific module) which is built by the sources. This element can be specified in a Maven project containing multiple Java modules. It is generally not needed for non-modular projects, or for modular projects having only one module.

If a module name is specified for resources or script files, then this value modifies the directory where the files will be copied. For example, if a Java module name is "foo.biz", then the {@code foo/bar.properties} resource file will be copied as {@code foo.biz/foo/bar.properties}.

This element can be combined with the {@code targetVersion} element for specifying sources, scripts or resources that are specific to both a particular module and a target version.

+
+
+ + + 4.1.0+ + The version of the platform where the code will be executed. In a Java environment, this is the value of the {@code --release} compiler option. If a Java project contains multiple main sources with different target versions, then a multi-version JAR file will be created with the lowest version taken as the base version. If this element is omitted, then the default target version is the compiler default value, which is usually the version of the Java environment running Maven.

If a target version, different from the base version, is specified for resources or script files, then this value modifies the directory where the files will be copied. For example, if {@code targetVersion} is 17, then the {@code foo/bar.properties} resource file will be copied as {@code META-INF/versions/17/foo/bar.properties}.

This element can be combined with the {@code module} element for specifying sources, scripts or resources that are specific to both a particular module and a target version.

+
+
+ + + 4.1.0+ + Specifies an explicit target path, overriding the default value. The path is relative to the {@code ${project.build.outputDirectory}} directory, which is typically {@code target/classes} in a Java project.

When a target path is explicitly specified, the values of the {@code module} and {@code targetVersion} elements are not used for inferring the path (they are still used as compiler options however). It means that for scripts and resources, the files below the path specified by {@code directory} are copied to the path specified by {@code targetPath} with the exact same directory structure. It is user's responsibility to put module and version components in the {@code targetPath} if needed.

Note that for Java source files, a directory with the module name may still be generated despite above statement about {@code module} being ignored, because that directory is generated by the Java compiler rather than Maven.

+
+
+ + + 4.1.0+ + Whether resources are filtered to replace tokens with parameterized values. The values are taken from the {@code properties} element and from the properties in the files listed in the {@code filters} element.

The default value is {@code false}.

+
+
+ + + 4.1.0+ + Whether the directory described by this source element should be included in the build. This flag provides an easy way to include or exclude some sources depending, for example, o property values defined in profiles. A use case is including optional resources only when the user confirmed a license agreement.

The default value is {@code true}.

+
+
+ + + 3.0.0+ + Describe the directory where the resources are stored. The path is relative to the POM. + + + + + 3.0.0+ + A list of patterns to include, e.g. {@code **/*.xml}. + + + + + + + + + + 3.0.0+ + A list of patterns to exclude, e.g. {@code **/*.xml} + + + + + + + +
+
4.0.0+ diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/FoldersImportingTest.kt b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/FoldersImportingTest.kt index 16b6800ed788..aed3f76e396b 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/FoldersImportingTest.kt +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/FoldersImportingTest.kt @@ -22,6 +22,7 @@ import com.intellij.openapi.application.edtWriteAction import com.intellij.openapi.externalSystem.service.project.ProjectDataManager import com.intellij.openapi.module.ModuleManager.Companion.getInstance import com.intellij.openapi.project.Project +import com.intellij.openapi.util.registry.Registry import com.intellij.util.ArrayUtil import kotlinx.coroutines.runBlocking import org.jetbrains.idea.maven.MavenCustomRepositoryHelper @@ -1869,6 +1870,48 @@ class FoldersImportingTest : MavenMultiVersionImportingTestCase() { assertExcludes("project", "target") } + + @Test + fun testImportingSourcesTag() = runBlocking { + assumeMaven4() + useModel410() + createProjectSubDirs("my/src", "my/res", "my/testsrc", "my/testres") + importProjectAsync(""" + test + project + 1 + + + + my/src + java + main + + + my/res + resources + main + + + my/testsrc + java + test + + + my/testres + resources + test + + + + """); + assertModules("project") + assertSources("project", "my/src") + assertTestSources("project", "my/testsrc") + assertResources("project", "my/res") + assertTestResources("project", "my/testres") + } + private suspend fun resolveFoldersAndImport() { MavenFolderResolver(projectsManager.project).resolveFoldersAndImport(projectsManager.projects) } diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/MavenCompilerImportingTest.kt b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/MavenCompilerImportingTest.kt index 8dd49d8e6429..677f1ebf81c3 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/MavenCompilerImportingTest.kt +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/MavenCompilerImportingTest.kt @@ -362,30 +362,30 @@ class MavenCompilerImportingTest : MavenMultiVersionImportingTestCase() { @Test fun testInheritingLanguageLevelFromPluginManagementSection() = runBlocking { importProjectAsync(("test" + - "project" + - "1" + - "" + - " " + - " " + - " " + - " org.apache.maven.plugins" + - " maven-compiler-plugin" + - " " + - " 1.4" + - " " + - " " + - " " + - " " + - " " + - " " + - " org.apache.maven.plugins" + - " maven-compiler-plugin" + - " " + - " 1.5" + - " " + - " " + - " " + - "")) + "project" + + "1" + + "" + + " " + + " " + + " " + + " org.apache.maven.plugins" + + " maven-compiler-plugin" + + " " + + " 1.4" + + " " + + " " + + " " + + " " + + " " + + " " + + " org.apache.maven.plugins" + + " maven-compiler-plugin" + + " " + + " 1.5" + + " " + + " " + + " " + + "")) assertModules("project") TestCase.assertEquals(LanguageLevel.JDK_1_4, getLanguageLevelForModule()) } @@ -1092,28 +1092,28 @@ class MavenCompilerImportingTest : MavenMultiVersionImportingTestCase() { @Test fun testCompilerPluginConfigurationUnresolvedCompilerArguments() = runBlocking { importProjectAsync(("test" + - "project" + - "1" + - "" + - " " + - " " + - " org.apache.maven.plugins" + - " maven-compiler-plugin" + - " " + - " \${maven.compiler.compilerId}" + - " \${unresolvedArgument}" + - " " + - " path/with/braces_\${" + - " \${_\${foo}" + - " " + - " " + - " \${anotherUnresolvedArgument}" + - " -myArg" + - " " + - " " + - " " + - " " + - "")) + "project" + + "1" + + "" + + " " + + " " + + " org.apache.maven.plugins" + + " maven-compiler-plugin" + + " " + + " \${maven.compiler.compilerId}" + + " \${unresolvedArgument}" + + " " + + " path/with/braces_\${" + + " \${_\${foo}" + + " " + + " " + + " \${anotherUnresolvedArgument}" + + " -myArg" + + " " + + " " + + " " + + " " + + "")) assertEquals("Javac", ideCompilerConfiguration.defaultCompiler.id) assertUnorderedElementsAreEqual(ideCompilerConfiguration.getAdditionalOptions(getModule("project")), "-myArg", "-d", "path/with/braces_\${") @@ -1335,4 +1335,53 @@ class MavenCompilerImportingTest : MavenMultiVersionImportingTestCase() { assertModules("project") } + @Test + fun testLanguageLevelMavenSourcesTag() = runBlocking { + assumeMaven4() + useModel410() + importProjectAsync(""" + test + project + 1 + + + + src + 17 + + + """) + assertModules("project") + assertEquals(LanguageLevel.parse("17"), getLanguageLevelForModule()) + } + + @Test + fun testLanguageLevelSplittedForMavenSourcesTag() = runBlocking { + assumeMaven4() + useModel410() + importProjectAsync(""" + test + project + 1 + + + + test + 17 + test + + + src + 11 + + + """) + assertModules("project", "project.main", "project.test") + assertModules("project", "project.main", "project.test") + TestCase.assertEquals(LanguageLevel.JDK_11, LanguageLevel.parse( + ideCompilerConfiguration.getBytecodeTargetLevel(getModule("project.main")))) + TestCase.assertEquals(LanguageLevel.JDK_17, LanguageLevel.parse( + ideCompilerConfiguration.getBytecodeTargetLevel(getModule("project.test")))) + } + } diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectReaderTest.kt b/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectReaderTest.kt index 60381e49346e..7e3eb6d67c75 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectReaderTest.kt +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectReaderTest.kt @@ -2,6 +2,7 @@ package org.jetbrains.idea.maven.project import com.intellij.openapi.util.SystemInfo +import com.intellij.openapi.util.registry.Registry import com.intellij.testFramework.PlatformTestUtil import com.intellij.util.Function import com.intellij.util.containers.ContainerUtil @@ -1911,4 +1912,67 @@ ${System.getProperty("os.name")} assertOrderedElementsAreEqual(resource.includes, includes) assertOrderedElementsAreEqual(resource.excludes, excludes) } + + fun `test custom source directories 410 model`() = runBlocking { + assumeMaven4() + useModel410() + val submodulePom = createModulePom("submodule", + """ + test + submodule + 1 + + test + project + 1 + + """.trimIndent()) + importProjectAsync(""" + test + project + 1 + + submodule + + + + + my/src + java + main + + + my/res + resources + main + + + my/testsrc + java + test + + + my/testres + resources + test + + + + """); + assertModules("project") + + + val submoduleModelBuild = readProject(submodulePom).build + + val submodulePath = submodulePom.parent.path + val srcPaths = listOf(Path.of(submodulePath, "my/src").pathString) + val testPaths = listOf(Path.of(submodulePath, "my/testsrc").pathString) + val resourcePaths = listOf(Path.of(submodulePath, "my/res").pathString) + val testResourcePaths = listOf(Path.of(submodulePath, "my/testsrc").pathString) + + assertEquals(srcPaths, submoduleModelBuild.sources) + assertEquals(testPaths, submoduleModelBuild.testSources) + assertEquals(resourcePaths, submoduleModelBuild.resources.map { it.directory }) + assertEquals(testResourcePaths, submoduleModelBuild.testResources.map { it.directory }) + } } diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/importing/MavenProjectTreeVersionNumberTest.kt b/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/importing/MavenProjectTreeVersionNumberTest.kt index 0fa22f62e660..ec40c06841b7 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/importing/MavenProjectTreeVersionNumberTest.kt +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/importing/MavenProjectTreeVersionNumberTest.kt @@ -22,7 +22,7 @@ class MavenProjectTreeVersionNumberTest : UsefulTestCase() { hashKType(MavenProjectState::class.createType(), recursionKeeper, hash) hash.putString(MavenProjectsTree.STORAGE_VERSION) - assertEquals("UPDATE STORAGE VERSION ALONG WITH THIS HASH!!!", 5736572056086370157, hash.asLong) + assertEquals("UPDATE STORAGE VERSION ALONG WITH THIS HASH!!!", -8406772361914507557, hash.asLong) } private fun hashKType(type: KType, recursionKeeper: MutableSet, hash: HashSink) { diff --git a/plugins/maven/testFramework/src/com/intellij/maven/testFramework/MavenTestCase.kt b/plugins/maven/testFramework/src/com/intellij/maven/testFramework/MavenTestCase.kt index 385a5e3d7cf6..d74ead14cbc0 100644 --- a/plugins/maven/testFramework/src/com/intellij/maven/testFramework/MavenTestCase.kt +++ b/plugins/maven/testFramework/src/com/intellij/maven/testFramework/MavenTestCase.kt @@ -118,6 +118,9 @@ abstract class MavenTestCase : UsefulTestCase() { myAllPoms.add(pom) } + protected fun useModel410() { + myModelVersion = "4.1.0" + } override fun setUp() { super.setUp() @@ -825,5 +828,4 @@ abstract class MavenTestCase : UsefulTestCase() { """.trimIndent() + xml + "" } } - }