diff --git a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java index f605744e82af5..b5a95a94b2d9e 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java @@ -1375,7 +1375,8 @@ private QuarkusDevModeLauncher newLauncher(String actualDebugPort, String bootst .setPreferPomsFromWorkspace(true) // it's important to set the base directory instead of the POM // which maybe manipulated by a plugin and stored outside the base directory - .setCurrentProject(project.getBasedir().toString()); + .setCurrentProject(project.getBasedir().toString()) + .setEffectiveModelBuilder(BootstrapMavenContextConfig.getEffectiveModelBuilderProperty(projectProperties)); // There are a couple of reasons we don't want to use the original Maven session: // 1) a reload could be triggered by a change in a pom.xml, in which case the Maven session might not be in sync any more with the effective POM; diff --git a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java index 8b3a2d7a4bb44..a2b09b2e7a06c 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java @@ -40,6 +40,7 @@ import io.quarkus.bootstrap.resolver.AppModelResolverException; import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext; +import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContextConfig; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; import io.quarkus.bootstrap.resolver.maven.EffectiveModelResolver; import io.quarkus.bootstrap.resolver.maven.IncubatingApplicationModelResolver; @@ -195,7 +196,9 @@ private MavenArtifactResolver artifactResolver(QuarkusBootstrapMojo mojo, Launch .setPreferPomsFromWorkspace(true) .setProjectModelProvider(getProjectMap(mojo.mavenSession())::get) // pass the repositories since Maven extensions could manipulate repository configs - .setRemoteRepositories(mojo.remoteRepositories())); + .setRemoteRepositories(mojo.remoteRepositories()) + .setEffectiveModelBuilder(BootstrapMavenContextConfig + .getEffectiveModelBuilderProperty(mojo.mavenProject().getProperties()))); } // PROD packaging mode with workspace discovery disabled return MavenArtifactResolver.builder() diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java index 3eb1af3732511..7dc987859495a 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContext.java @@ -97,7 +97,7 @@ public class BootstrapMavenContext { private static final String SETTINGS_XML = "settings.xml"; private static final String SETTINGS_SECURITY = "settings.security"; - private static final String EFFECTIVE_MODEL_BUILDER_PROP = "quarkus.bootstrap.effective-model-builder"; + static final String EFFECTIVE_MODEL_BUILDER_PROP = "quarkus.bootstrap.effective-model-builder"; private static final String WARN_ON_FAILING_WS_MODULES_PROP = "quarkus.bootstrap.warn-on-failing-workspace-modules"; private static final String MAVEN_RESOLVER_TRANSPORT_KEY = "maven.resolver.transport"; @@ -1080,8 +1080,7 @@ public boolean isPreferPomsFromWorkspace() { public boolean isEffectiveModelBuilder() { if (effectiveModelBuilder == null) { - final String s = PropertyUtils.getProperty(EFFECTIVE_MODEL_BUILDER_PROP); - effectiveModelBuilder = s == null ? false : Boolean.parseBoolean(s); + effectiveModelBuilder = Boolean.getBoolean(EFFECTIVE_MODEL_BUILDER_PROP); } return effectiveModelBuilder; } diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContextConfig.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContextConfig.java index 6dc0d5ebb242b..47a80712c78b3 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContextConfig.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BootstrapMavenContextConfig.java @@ -6,6 +6,7 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import java.util.Properties; import java.util.function.Function; import org.apache.maven.model.Model; @@ -20,6 +21,23 @@ public class BootstrapMavenContextConfig> { + /** + * Resolves the effective value of the {@code effective-model-builder} option by looking for the + * {@code quarkus.bootstrap.effective-model-builder} property among the system properties and, + * if not set, in the properties argument. + *

+ * If the property is found, the method will return the result of {@link java.lang.Boolean#parseBoolean}. + * If the property is not set, the method will return false. + * + * @param props primary source of properties + * @return whether effective model builder should be enabled + */ + public static boolean getEffectiveModelBuilderProperty(Properties props) { + final String value = System.getProperty(BootstrapMavenContext.EFFECTIVE_MODEL_BUILDER_PROP); + return value == null ? Boolean.parseBoolean(props.getProperty(BootstrapMavenContext.EFFECTIVE_MODEL_BUILDER_PROP)) + : Boolean.parseBoolean(value); + } + protected String localRepo; protected String[] localRepoTail; protected Boolean localRepoTailIgnoreAvailability; diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalProject.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalProject.java index f97744c845d07..ca502db7afa0a 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalProject.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalProject.java @@ -366,71 +366,19 @@ public WorkspaceModule toWorkspaceModule(BootstrapMavenContext ctx) { .setBuildDir(getOutputDir()); final Model model = modelBuildingResult == null ? getRawModel() : modelBuildingResult.getEffectiveModel(); - if (!ArtifactCoords.TYPE_POM.equals(model.getPackaging())) { - final Build build = model.getBuild(); - boolean addDefaultSourceSet = true; - if (build != null && !build.getPlugins().isEmpty()) { - for (Plugin plugin : build.getPlugins()) { - if (plugin.getArtifactId().equals("maven-jar-plugin")) { - if (plugin.getExecutions().isEmpty()) { - final DefaultArtifactSources src = processJarPluginExecutionConfig(plugin.getConfiguration(), - false); - if (src != null) { - addDefaultSourceSet = false; - moduleBuilder.addArtifactSources(src); - } - } else { - for (PluginExecution e : plugin.getExecutions()) { - DefaultArtifactSources src = null; - if (e.getGoals().contains(ArtifactCoords.TYPE_JAR)) { - src = processJarPluginExecutionConfig(e.getConfiguration(), false); - addDefaultSourceSet &= !(src != null && e.getId().equals("default-jar")); - } else if (e.getGoals().contains("test-jar")) { - src = processJarPluginExecutionConfig(e.getConfiguration(), true); - } - if (src != null) { - moduleBuilder.addArtifactSources(src); - } - } - } - } else if (plugin.getArtifactId().equals("maven-surefire-plugin") && plugin.getConfiguration() != null) { - Object config = plugin.getConfiguration(); - if (!(config instanceof Xpp3Dom)) { - continue; - } - Xpp3Dom dom = (Xpp3Dom) config; - final Xpp3Dom depExcludes = dom.getChild("classpathDependencyExcludes"); - if (depExcludes != null) { - final Xpp3Dom[] excludes = depExcludes.getChildren("classpathDependencyExclude"); - if (excludes != null) { - final List list = new ArrayList<>(excludes.length); - for (Xpp3Dom exclude : excludes) { - list.add(exclude.getValue()); - } - moduleBuilder.setTestClasspathDependencyExclusions(list); - } - } - final Xpp3Dom additionalElements = dom.getChild("additionalClasspathElements"); - if (additionalElements != null) { - final Xpp3Dom[] elements = additionalElements.getChildren("additionalClasspathElement"); - if (elements != null) { - final List list = new ArrayList<>(elements.length); - for (Xpp3Dom element : elements) { - for (String s : element.getValue().split(",")) { - list.add(stripProjectBasedirPrefix(s, PROJECT_BASEDIR)); - } - } - moduleBuilder.setAdditionalTestClasspathElements(list); - } - } - } - } - } - + if (!ArtifactCoords.TYPE_POM.equals(getPackaging())) { + final List plugins = model.getBuild() == null ? List.of() : model.getBuild().getPlugins(); + boolean addDefaultSourceSet = addSourceSetsFromPlugins(plugins, moduleBuilder); if (addDefaultSourceSet) { - moduleBuilder.addArtifactSources(new DefaultArtifactSources(ArtifactSources.MAIN, - List.of(new DefaultSourceDir(getSourcesSourcesDir(), getClassesDir(), getGeneratedSourcesDir())), - collectMainResources(null))); + var pluginManagement = model.getBuild() == null ? null : model.getBuild().getPluginManagement(); + if (pluginManagement != null) { + addDefaultSourceSet = addSourceSetsFromPlugins(pluginManagement.getPlugins(), moduleBuilder); + } + if (addDefaultSourceSet) { + moduleBuilder.addArtifactSources(new DefaultArtifactSources(ArtifactSources.MAIN, + List.of(new DefaultSourceDir(getSourcesSourcesDir(), getClassesDir(), getGeneratedSourcesDir())), + collectMainResources(null))); + } } if (!moduleBuilder.hasTestSources()) { // FIXME: do tests have generated sources? @@ -454,6 +402,70 @@ public WorkspaceModule toWorkspaceModule(BootstrapMavenContext ctx) { return this.module = moduleBuilder.build(); } + private boolean addSourceSetsFromPlugins(List plugins, WorkspaceModule.Mutable moduleBuilder) { + boolean addDefaultSourceSet = true; + int processedPlugins = 0; + for (int i = 0; i < plugins.size() && processedPlugins < 2; ++i) { + var plugin = plugins.get(i); + if (plugin.getArtifactId().equals("maven-jar-plugin")) { + ++processedPlugins; + if (plugin.getExecutions().isEmpty()) { + final DefaultArtifactSources src = processJarPluginExecutionConfig(plugin.getConfiguration(), + false); + if (src != null) { + addDefaultSourceSet = false; + moduleBuilder.addArtifactSources(src); + } + } else { + for (PluginExecution e : plugin.getExecutions()) { + DefaultArtifactSources src = null; + if (e.getGoals().contains(ArtifactCoords.TYPE_JAR)) { + src = processJarPluginExecutionConfig(e.getConfiguration(), false); + addDefaultSourceSet &= !(src != null && e.getId().equals("default-jar")); + } else if (e.getGoals().contains("test-jar")) { + src = processJarPluginExecutionConfig(e.getConfiguration(), true); + } + if (src != null) { + moduleBuilder.addArtifactSources(src); + } + } + } + } else if (plugin.getArtifactId().equals("maven-surefire-plugin") && plugin.getConfiguration() != null) { + ++processedPlugins; + Object config = plugin.getConfiguration(); + if (!(config instanceof Xpp3Dom)) { + continue; + } + Xpp3Dom dom = (Xpp3Dom) config; + final Xpp3Dom depExcludes = dom.getChild("classpathDependencyExcludes"); + if (depExcludes != null) { + final Xpp3Dom[] excludes = depExcludes.getChildren("classpathDependencyExclude"); + if (excludes != null) { + final List list = new ArrayList<>(excludes.length); + for (Xpp3Dom exclude : excludes) { + list.add(exclude.getValue()); + } + moduleBuilder.setTestClasspathDependencyExclusions(list); + } + } + final Xpp3Dom additionalElements = dom.getChild("additionalClasspathElements"); + if (additionalElements != null) { + final Xpp3Dom[] elements = additionalElements.getChildren("additionalClasspathElement"); + if (elements != null) { + final List list = new ArrayList<>(elements.length); + for (Xpp3Dom element : elements) { + for (String s : element.getValue().split(",")) { + list.add(stripProjectBasedirPrefix(s, PROJECT_BASEDIR)); + } + } + moduleBuilder.setAdditionalTestClasspathElements(list); + } + } + } + } + return addDefaultSourceSet; + } + private List toArtifactDependencies(List rawModelDeps, BootstrapMavenContext ctx) { if (rawModelDeps.isEmpty()) { @@ -509,7 +521,7 @@ private DefaultArtifactSources processJarPluginExecutionConfig(Object config, bo new DefaultSourceDir(new DirectoryPathTree(test ? getTestSourcesSourcesDir() : getSourcesSourcesDir()), new DirectoryPathTree(test ? getTestClassesDir() : getClassesDir(), filter), // FIXME: wrong for tests - new DirectoryPathTree(test ? getGeneratedSourcesDir() : getGeneratedSourcesDir(), filter), + new DirectoryPathTree(getGeneratedSourcesDir(), filter), Map.of())); final Collection resources = test ? collectTestResources(filter) : collectMainResources(filter); return new DefaultArtifactSources(classifier, sources, resources); diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalWorkspace.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalWorkspace.java index e68e4affef2e8..a570d9f80455f 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalWorkspace.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/workspace/LocalWorkspace.java @@ -124,16 +124,12 @@ public File findArtifact(Artifact artifact) { return path.toFile(); } - if (!artifact.getClassifier().isEmpty()) { - if ("tests".equals(artifact.getClassifier())) { - //special classifier used for test jars - path = lp.getTestClassesDir(); - if (Files.exists(path)) { - return path.toFile(); - } + if ("tests".equals(artifact.getClassifier())) { + //special classifier used for test jars + path = lp.getTestClassesDir(); + if (Files.exists(path)) { + return path.toFile(); } - // otherwise, this artifact hasn't been built yet - return null; } if (ArtifactCoords.TYPE_JAR.equals(artifact.getExtension())) { diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java b/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java index f9a1957dd172a..3f0873bc20084 100644 --- a/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java +++ b/integration-tests/maven/src/test/java/io/quarkus/maven/it/DevMojoIT.java @@ -1622,4 +1622,12 @@ public void testThatAptInAnnotationProcessorsWorks() throws MavenInvocationExcep assertThat(entityMetamodelClassFile).exists(); assertThat(entityQueryClassFile).doesNotExist(); } + + @Test + void testMultimoduleFilteredClassifier() + throws MavenInvocationException, IOException { + testDir = initProject("projects/multimodule-filtered-classifier"); + run(true); + assertThat(devModeClient.getHttpResponse("/")).isEqualTo("Big"); + } } diff --git a/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/app/pom.xml b/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/app/pom.xml new file mode 100644 index 0000000000000..4b0d7b99b3c82 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/app/pom.xml @@ -0,0 +1,36 @@ + + + + acme-parent + org.acme + 1.0.0-SNAPSHOT + + 4.0.0 + + acme-app + + + org.acme + \${project.version} + acme-lib + shared + + + + + + \${quarkus.platform.group-id} + quarkus-maven-plugin + + + + build + + + + + + + \ No newline at end of file diff --git a/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/app/src/main/java/org/acme/App.java b/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/app/src/main/java/org/acme/App.java new file mode 100644 index 0000000000000..6f9e51cb54958 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/app/src/main/java/org/acme/App.java @@ -0,0 +1,19 @@ +package org.acme; + +import org.acme.shared.BigBean; + +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; + +@Path("/") +public class App { + + @Inject + BigBean bean; + + @GET + public String get() { + return bean.getName(); + } +} diff --git a/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/library/pom.xml b/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/library/pom.xml new file mode 100644 index 0000000000000..dddbb8780fc0d --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/library/pom.xml @@ -0,0 +1,14 @@ + + + + acme-parent + org.acme + 1.0.0-SNAPSHOT + + 4.0.0 + + acme-lib + + \ No newline at end of file diff --git a/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/library/src/main/java/org/acme/BigBeanProducer.java b/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/library/src/main/java/org/acme/BigBeanProducer.java new file mode 100644 index 0000000000000..993e92be768f1 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/library/src/main/java/org/acme/BigBeanProducer.java @@ -0,0 +1,15 @@ +package org.acme; + +import jakarta.enterprise.inject.Produces; +import org.acme.shared.BigBean; + +/** + * The purpose of this class is to create a conflict with the shared BigBeanProducer + */ +public class BigBeanProducer { + + @Produces + public BigBean getName() { + return new BigBean(); + } +} diff --git a/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/library/src/main/java/org/acme/shared/BigBean.java b/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/library/src/main/java/org/acme/shared/BigBean.java new file mode 100644 index 0000000000000..e74b855a968a6 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/library/src/main/java/org/acme/shared/BigBean.java @@ -0,0 +1,7 @@ +package org.acme.shared; + +public class BigBean { + public String getName() { + return "Big"; + } +} diff --git a/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/library/src/main/java/org/acme/shared/BigBeanProducer.java b/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/library/src/main/java/org/acme/shared/BigBeanProducer.java new file mode 100644 index 0000000000000..eabf45b6f1524 --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/library/src/main/java/org/acme/shared/BigBeanProducer.java @@ -0,0 +1,11 @@ +package org.acme.shared; + +import jakarta.enterprise.inject.Produces; + +public class BigBeanProducer { + + @Produces + public BigBean getBigBean() { + return new BigBean(); + } +} diff --git a/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/library/src/main/resources/META-INF/beans.xml b/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/library/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/pom.xml b/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/pom.xml new file mode 100644 index 0000000000000..09ebd99118eda --- /dev/null +++ b/integration-tests/maven/src/test/resources-filtered/projects/multimodule-filtered-classifier/pom.xml @@ -0,0 +1,86 @@ + + + 4.0.0 + org.acme + acme-parent + pom + 1.0.0-SNAPSHOT + + library + app + + + + @project.version@ + ${compiler-plugin.version} + ${version.surefire.plugin} + ${maven.compiler.source} + ${maven.compiler.target} + UTF-8 + UTF-8 + quarkus-bom + io.quarkus + true + + + + + \${quarkus.platform.group-id} + \${quarkus.platform.artifact-id} + \${quarkus.platform.version} + pom + import + + + + + + io.quarkus + quarkus-rest + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.2.0 + + + package + + jar + + + shared + + **/shared/* + META-INF/* + + + + + + + \${quarkus.platform.group-id} + quarkus-maven-plugin + \${quarkus.platform.version} + true + + + maven-compiler-plugin + \${compiler-plugin.version} + + + + + + \${quarkus.platform.group-id} + quarkus-maven-plugin + + + +