Skip to content

Commit 8f63dcc

Browse files
authored
Add validation for mixins in consumer POM without flattening (fixes #11456) (#11463)
Maven now fails with a clear error message when a POM contains mixins but consumer POM flattening is disabled. Mixins require model version 4.2.0 and cannot be part of the consumer POM, so they must be removed during transformation through flattening. Changes: - Added validation in DefaultConsumerPomBuilder to check for mixins when flattening is disabled and throw MavenException with helpful message - Added integration test MavenITgh11456MixinsConsumerPomTest with three scenarios The error message guides users to either enable flattening by setting maven.consumer.pom.flatten=true, using preserve.model.version=true, or remove mixins from their POM. Fixes #11456
1 parent dff7903 commit 8f63dcc

File tree

17 files changed

+396
-2
lines changed

17 files changed

+396
-2
lines changed

impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.apache.maven.api.model.Profile;
4141
import org.apache.maven.api.model.Repository;
4242
import org.apache.maven.api.model.Scm;
43+
import org.apache.maven.api.services.MavenException;
4344
import org.apache.maven.api.services.ModelBuilder;
4445
import org.apache.maven.api.services.ModelBuilderException;
4546
import org.apache.maven.api.services.ModelBuilderRequest;
@@ -53,6 +54,45 @@
5354
import org.slf4j.Logger;
5455
import org.slf4j.LoggerFactory;
5556

57+
/**
58+
* Builds consumer POMs from project models, transforming them into a format suitable for downstream consumers.
59+
* <p>
60+
* A consumer POM is a simplified version of a project's POM that is published for consumption by other projects.
61+
* It removes build-specific information and internal details while preserving essential information like
62+
* dependencies, repositories, and distribution management.
63+
* <p>
64+
* This builder applies two orthogonal transformations:
65+
* <ul>
66+
* <li><b>Dependency Flattening</b>: When enabled via {@code maven.consumer.pom.flatten=true}, dependency management
67+
* is flattened into direct dependencies for non-POM projects, and mixins are removed.</li>
68+
* <li><b>Model Version Handling</b>: When {@code preserve.model.version=true} is set, the consumer POM
69+
* maintains the original model version (4.2.0) instead of downgrading to 4.0.0 for Maven 3 compatibility.
70+
* This allows modern features like mixins to be preserved in the consumer POM.</li>
71+
* </ul>
72+
* <p>
73+
* <b>Mixin Handling</b>: Mixins are only supported in model version 4.2.0 or later. If a POM contains mixins:
74+
* <ul>
75+
* <li>Setting {@code preserve.model.version=true} preserves them in the consumer POM with model version 4.2.0</li>
76+
* <li>Setting {@code maven.consumer.pom.flatten=true} removes them during transformation</li>
77+
* <li>Otherwise, an exception is thrown requiring one of the above options or manual mixin removal</li>
78+
* </ul>
79+
* <p>
80+
* <b>Dependency Filtering</b>: For non-POM projects with dependency management, the builder:
81+
* <ul>
82+
* <li>Filters dependencies to include only those with transitive scopes (compile/runtime)</li>
83+
* <li>Applies managed dependency metadata (version, scope, optional flag, exclusions) to direct dependencies</li>
84+
* <li>Removes managed dependencies that are not used by direct dependencies</li>
85+
* <li>Retains only managed dependencies that appear in the resolved dependency tree</li>
86+
* </ul>
87+
* <p>
88+
* <b>Repository and Profile Pruning</b>: The consumer POM removal strategy:
89+
* <ul>
90+
* <li>Removes the central repository (only non-central repositories are kept)</li>
91+
* <li>Removes build, mailing lists, issue management, and other build-specific information</li>
92+
* <li>Removes profiles that have no activation, build, dependencies, or properties</li>
93+
* <li>Preserves relocation information in distribution management</li>
94+
* </ul>
95+
*/
5696
@Named
5797
class DefaultConsumerPomBuilder implements PomBuilder {
5898
private static final String BOM_PACKAGING = "bom";
@@ -80,6 +120,20 @@ public Model build(RepositorySystemSession session, MavenProject project, ModelS
80120
// Check if this is a BOM (original packaging is "bom")
81121
boolean isBom = BOM_PACKAGING.equals(originalPackaging);
82122

123+
// Check if mixins are present without flattening enabled
124+
if (!model.getMixins().isEmpty() && !flattenEnabled && !model.isPreserveModelVersion()) {
125+
throw new MavenException("The consumer POM for "
126+
+ project.getId()
127+
+ " cannot be created because the POM contains mixins. "
128+
+ "Mixins are not supported in the default consumer POM format. "
129+
+ "You have the following options to resolve this:" + System.lineSeparator()
130+
+ " 1. Preserve the model version by setting 'preserve.model.version=true' to generate a consumer POM with <modelVersion>4.2.0</modelVersion>, which supports mixins"
131+
+ System.lineSeparator()
132+
+ " 2. Enable flattening by setting the property 'maven.consumer.pom.flatten=true' to remove mixins during transformation"
133+
+ System.lineSeparator()
134+
+ " 3. Remove the mixins from your POM");
135+
}
136+
83137
// Check if consumer POM flattening is disabled
84138
if (!flattenEnabled) {
85139
// When flattening is disabled, treat non-POM projects like parent POMs
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.maven.it;
20+
21+
import java.io.Reader;
22+
import java.nio.file.Files;
23+
import java.nio.file.Path;
24+
import java.nio.file.Paths;
25+
26+
import org.apache.maven.api.model.Model;
27+
import org.apache.maven.model.v4.MavenStaxReader;
28+
import org.junit.jupiter.api.Test;
29+
30+
import static org.junit.jupiter.api.Assertions.assertFalse;
31+
import static org.junit.jupiter.api.Assertions.assertTrue;
32+
33+
/**
34+
* This is a test set for <a href="https://github.com/apache/maven/issues/11456">GH-11456</a>.
35+
* @since 4.1.0
36+
*/
37+
class MavenITgh11456MixinsConsumerPomTest extends AbstractMavenIntegrationTestCase {
38+
39+
/**
40+
* Verify that Maven fails when a POM has non-empty mixins without flattening being enabled.
41+
*/
42+
@Test
43+
void testMixinsWithoutFlattening() throws Exception {
44+
Path basedir = extractResources("/gh-11456-mixins-consumer-pom/non-flattened").toPath();
45+
46+
Verifier verifier = newVerifier(basedir.toString());
47+
verifier.addCliArgument("-Dmaven.repo.local=" + basedir.resolve("repo"));
48+
verifier.addCliArgument("package");
49+
try {
50+
verifier.execute();
51+
} catch (VerificationException e) {
52+
// Expected to fail due to mixins without flattening
53+
}
54+
55+
verifier.verifyTextInLog("cannot be created because the POM contains mixins");
56+
verifier.verifyTextInLog("maven.consumer.pom.flatten=true");
57+
}
58+
59+
/**
60+
* Verify that Maven succeeds when mixins are used with flattening enabled.
61+
*/
62+
@Test
63+
void testMixinsWithFlattening() throws Exception {
64+
Path basedir = extractResources("/gh-11456-mixins-consumer-pom/flattened").toPath();
65+
66+
Verifier verifier = newVerifier(basedir.toString());
67+
verifier.addCliArgument("-Dmaven.repo.local=" + basedir.resolve("repo").toString());
68+
verifier.addCliArgument("package");
69+
verifier.execute();
70+
verifier.verifyErrorFreeLog();
71+
72+
// Verify consumer POM was created
73+
Path consumerPom = basedir.resolve(Paths.get(
74+
"target",
75+
"project-local-repo",
76+
"org.apache.maven.its.gh11456",
77+
"flattened",
78+
"1.0",
79+
"flattened-1.0-consumer.pom"));
80+
assertTrue(Files.exists(consumerPom), "consumer pom not found at " + consumerPom);
81+
82+
// Verify mixins are removed from consumer POM
83+
Model consumerPomModel;
84+
try (Reader r = Files.newBufferedReader(consumerPom)) {
85+
consumerPomModel = new MavenStaxReader().read(r);
86+
}
87+
assertTrue(
88+
consumerPomModel.getMixins().isEmpty(),
89+
"Mixins should be removed from consumer POM when flattening is enabled");
90+
}
91+
92+
/**
93+
* Verify that Maven succeeds when mixins are used with flattening enabled.
94+
*/
95+
@Test
96+
void testMixinsWithPreserveModelVersion() throws Exception {
97+
Path basedir = extractResources("/gh-11456-mixins-consumer-pom/preserve-model-version").toPath();
98+
99+
Verifier verifier = newVerifier(basedir.toString());
100+
verifier.addCliArgument("-Dmaven.repo.local=" + basedir.resolve("repo").toString());
101+
verifier.addCliArgument("package");
102+
verifier.execute();
103+
verifier.verifyErrorFreeLog();
104+
105+
// Verify consumer POM was created
106+
Path consumerPom = basedir.resolve(Paths.get(
107+
"target",
108+
"project-local-repo",
109+
"org.apache.maven.its.gh11456",
110+
"preserve-model-version",
111+
"1.0",
112+
"preserve-model-version-1.0-consumer.pom"));
113+
assertTrue(Files.exists(consumerPom), "consumer pom not found at " + consumerPom);
114+
115+
// Verify mixins are removed from consumer POM
116+
Model consumerPomModel;
117+
try (Reader r = Files.newBufferedReader(consumerPom)) {
118+
consumerPomModel = new MavenStaxReader().read(r);
119+
}
120+
assertFalse(
121+
consumerPomModel.getMixins().isEmpty(),
122+
"Mixins should be kept in consumer POM when preserveModelVersion is enabled");
123+
}
124+
}
125+

its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng5102MixinsTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public void testWithGav() throws Exception {
9090
verifier = newVerifier(new File(testDir, "project").getAbsolutePath());
9191
verifier.setAutoclean(false);
9292
verifier.deleteDirectory("target");
93-
verifier.addCliArgument("install");
93+
verifier.addCliArguments("install", "-Dmaven.consumer.pom.flatten");
9494
verifier.execute();
9595
verifier.verifyErrorFreeLog();
9696

@@ -126,7 +126,7 @@ public void testWithClassifier() throws Exception {
126126
verifier = newVerifier(new File(testDir, "project").getAbsolutePath());
127127
verifier.setAutoclean(false);
128128
verifier.deleteDirectory("target");
129-
verifier.addCliArgument("install");
129+
verifier.addCliArguments("install", "-Dmaven.consumer.pom.flatten");
130130
verifier.execute();
131131
verifier.verifyErrorFreeLog();
132132

its/core-it-suite/src/test/resources/gh-11456-mixins-consumer-pom/flattened/.mvn/.gitkeep

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
maven.consumer.pom.flatten=true
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Licensed to the Apache Software Foundation (ASF) under one
4+
or more contributor license agreements. See the NOTICE file
5+
distributed with this work for additional information
6+
regarding copyright ownership. The ASF licenses this file
7+
to you under the Apache License, Version 2.0 (the
8+
"License"); you may not use this file except in compliance
9+
with the License. You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing,
14+
software distributed under the License is distributed on an
15+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
KIND, either express or implied. See the License for the
17+
specific language governing permissions and limitations
18+
under the License.
19+
-->
20+
<project xmlns="http://maven.apache.org/POM/4.2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" root="true" xsi:schemaLocation="http://maven.apache.org/POM/4.2.0 http://maven.apache.org/xsd/maven-4.2.0.xsd">
21+
<modelVersion>4.2.0</modelVersion>
22+
<groupId>org.apache.maven.its.gh11456</groupId>
23+
<artifactId>flattened</artifactId>
24+
<version>1.0</version>
25+
<packaging>jar</packaging>
26+
27+
<name>Maven Integration Test :: GH-11456 :: Mixins with Consumer POM Flattened</name>
28+
<description>Test that Maven succeeds when mixins are used with flattening enabled.</description>
29+
30+
<mixins>
31+
<mixin>
32+
<groupId>org.apache.maven.its.gh11456</groupId>
33+
<artifactId>test-mixin-flattened</artifactId>
34+
<version>1.0</version>
35+
</mixin>
36+
</mixins>
37+
</project>
38+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.2.0">
3+
<modelVersion>4.2.0</modelVersion>
4+
<groupId>org.apache.maven.its.gh11456</groupId>
5+
<artifactId>test-mixin-flattened</artifactId>
6+
<version>1.0</version>
7+
<packaging>pom</packaging>
8+
9+
<properties>
10+
<test.property>from-mixin-flattened</test.property>
11+
</properties>
12+
</project>
13+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
public class Test {}
20+

its/core-it-suite/src/test/resources/gh-11456-mixins-consumer-pom/non-flattened/.mvn/.gitkeep

Whitespace-only changes.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Licensed to the Apache Software Foundation (ASF) under one
4+
or more contributor license agreements. See the NOTICE file
5+
distributed with this work for additional information
6+
regarding copyright ownership. The ASF licenses this file
7+
to you under the Apache License, Version 2.0 (the
8+
"License"); you may not use this file except in compliance
9+
with the License. You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing,
14+
software distributed under the License is distributed on an
15+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
KIND, either express or implied. See the License for the
17+
specific language governing permissions and limitations
18+
under the License.
19+
-->
20+
<project xmlns="http://maven.apache.org/POM/4.2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" root="true" xsi:schemaLocation="http://maven.apache.org/POM/4.2.0 http://maven.apache.org/xsd/maven-4.2.0.xsd">
21+
<modelVersion>4.2.0</modelVersion>
22+
<groupId>org.apache.maven.its.gh11456</groupId>
23+
<artifactId>non-flattened</artifactId>
24+
<version>1.0</version>
25+
<packaging>jar</packaging>
26+
27+
<name>Maven Integration Test :: GH-11456 :: Mixins with Consumer POM</name>
28+
<description>Test that Maven fails when mixins are used without flattening enabled.</description>
29+
30+
<mixins>
31+
<mixin>
32+
<groupId>org.apache.maven.its.gh11456</groupId>
33+
<artifactId>test-mixin</artifactId>
34+
<version>1.0</version>
35+
</mixin>
36+
</mixins>
37+
</project>
38+

0 commit comments

Comments
 (0)