Skip to content

Commit ab594c5

Browse files
committed
Downgrade model version in consumer/build pom as needed
1 parent aece05f commit ab594c5

File tree

14 files changed

+693
-29
lines changed

14 files changed

+693
-29
lines changed

api/maven-api-model/src/main/mdo/maven.mdo

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@
214214
</field>
215215
<field xml.attribute="true" xml.tagName="root">
216216
<name>root</name>
217-
<version>4.0.0+</version>
217+
<version>4.1.0+</version>
218218
<description>
219219
<![CDATA[
220220
Indicates that this project is the root project, located in the upper directory of the source tree.
@@ -225,6 +225,19 @@
225225
<type>boolean</type>
226226
<defaultValue>false</defaultValue>
227227
</field>
228+
<field xml.attribute="true" xml.tagName="downgrade.model.version">
229+
<name>downgradeModelVersion</name>
230+
<version>4.1.0+</version>
231+
<description>
232+
<![CDATA[
233+
Indicates if the build POM for this project should be downgraded to the lowest
234+
compatible version.
235+
<br><b>Since</b>: Maven 4.0.0
236+
]]>
237+
</description>
238+
<type>boolean</type>
239+
<defaultValue>true</defaultValue>
240+
</field>
228241
<field>
229242
<name>inceptionYear</name>
230243
<version>3.0.0+</version>

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

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import org.apache.maven.model.building.TransformerContext;
4848
import org.apache.maven.model.transform.RawToConsumerPomXMLFilterFactory;
4949
import org.apache.maven.model.transform.stax.XmlUtils;
50+
import org.apache.maven.model.v4.MavenModelVersion;
5051
import org.apache.maven.model.v4.MavenStaxWriter;
5152
import org.apache.maven.project.MavenProject;
5253
import org.apache.maven.project.artifact.ProjectArtifact;
@@ -74,6 +75,10 @@ public final class ConsumerPomArtifactTransformer {
7475

7576
private static final String BUILD_POM_CLASSIFIER = "build";
7677

78+
private static final String NAMESPACE_FORMAT = "http://maven.apache.org/POM/%s";
79+
80+
private static final String SCHEMA_LOCATION_FORMAT = "https://maven.apache.org/xsd/maven-%s.xsd";
81+
7782
private final Set<Path> toDelete = new CopyOnWriteArraySet<>();
7883

7984
public void injectTransformedArtifacts(MavenProject project, RepositorySystemSession session) throws IOException {
@@ -193,7 +198,7 @@ private Collection<Artifact> replacePom(Collection<Artifact> artifacts) {
193198
/**
194199
* Consumer POM is transformed from original POM.
195200
*/
196-
private static class ConsumerPomArtifact extends TransformedArtifact {
201+
static class ConsumerPomArtifact extends TransformedArtifact {
197202

198203
private MavenProject project;
199204

@@ -210,9 +215,19 @@ private ConsumerPomArtifact(MavenProject mavenProject, Path target) {
210215
@Override
211216
public void transform(Path src, Path dest) {
212217
Model model = project.getModel().getDelegate();
218+
transform(model, dest);
219+
}
220+
221+
static void transform(Model model, Path dest) {
213222
boolean isBom = BOM_PACKAGING.equals(model.getPackaging());
214-
Model.Builder builder =
215-
prune(Model.newBuilder(model, true).root(false).parent(null).build(null), model, isBom);
223+
Model.Builder builder = prune(
224+
Model.newBuilder(model, true)
225+
.downgradeModelVersion(false)
226+
.root(false)
227+
.parent(null)
228+
.build(null),
229+
model,
230+
isBom);
216231
if (isBom) {
217232
builder.packaging(POM_PACKAGING);
218233
}
@@ -221,15 +236,21 @@ public void transform(Path src, Path dest) {
221236
.collect(Collectors.toList()));
222237

223238
Model consumer = builder.build();
239+
String version = new MavenModelVersion().getModelVersion(consumer);
240+
consumer = consumer.withModelVersion(version).withDowngradeModelVersion(true);
224241

225242
try (Writer w = Files.newBufferedWriter(dest)) {
226-
new MavenStaxWriter().write(w, consumer);
243+
MavenStaxWriter writer = new MavenStaxWriter();
244+
writer.setNamespace(String.format(NAMESPACE_FORMAT, version));
245+
writer.setSchemaLocation(String.format(SCHEMA_LOCATION_FORMAT, version));
246+
writer.setAddLocationInformation(false);
247+
writer.write(w, consumer);
227248
} catch (XMLStreamException | IOException e) {
228249
throw new RuntimeException(e);
229250
}
230251
}
231252

232-
private <T extends ModelBase.Builder> T prune(T builder, ModelBase model, boolean isBom) {
253+
static <T extends ModelBase.Builder> T prune(T builder, ModelBase model, boolean isBom) {
233254
builder.properties(null).reporting(null).pluginRepositories(null);
234255
if (model.getDistributionManagement() != null
235256
&& model.getDistributionManagement().getRelocation() != null) {

maven-core/src/test/java/org/apache/maven/internal/transformation/ConsumerPomArtifactTransformerTest.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import org.apache.maven.model.Model;
2828
import org.apache.maven.model.building.TransformerContext;
29+
import org.apache.maven.model.v4.MavenStaxReader;
2930
import org.apache.maven.project.MavenProject;
3031
import org.eclipse.aether.RepositorySystemSession;
3132
import org.eclipse.aether.SessionData;
@@ -39,7 +40,7 @@
3940

4041
class ConsumerPomArtifactTransformerTest {
4142
@Test
42-
void transform() throws Exception {
43+
void buildTransform() throws Exception {
4344
Path beforePomFile =
4445
Paths.get("src/test/resources/projects/transform/before.pom").toAbsolutePath();
4546
Path afterPomFile =
@@ -52,6 +53,21 @@ beforePomFile, new NoTransformerContext())) {
5253
}
5354
}
5455

56+
@Test
57+
void consumerTransform() throws Exception {
58+
Path beforePomFile = Paths.get("src/test/resources/projects/transform/consumer-before.pom")
59+
.toAbsolutePath();
60+
Path afterPomFile = Paths.get("src/test/resources/projects/transform/consumer-after.pom")
61+
.toAbsolutePath();
62+
Path tempFile = Files.createTempFile("", ".pom");
63+
Files.delete(tempFile);
64+
try (InputStream expected = Files.newInputStream(beforePomFile)) {
65+
Model model = new Model(new MavenStaxReader().read(expected));
66+
ConsumerPomArtifactTransformer.ConsumerPomArtifact.transform(model.getDelegate(), tempFile);
67+
}
68+
XmlAssert.assertThat(afterPomFile.toFile()).and(tempFile.toFile()).areIdentical();
69+
}
70+
5571
@Test
5672
void injectTransformedArtifactsWithoutPomShouldNotInjectAnyArtifacts() throws IOException {
5773
MavenProject emptyProject = new MavenProject();
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<groupId>test</groupId>
7+
<artifactId>test</artifactId>
8+
<version>0.1-SNAPSHOT</version>
9+
<packaging>pom</packaging>
10+
<modules>
11+
<module>lib</module>
12+
<module>app</module>
13+
</modules>
14+
<profiles>
15+
<profile>
16+
<id>default-active</id>
17+
<activation>
18+
<activeByDefault>true</activeByDefault>
19+
</activation>
20+
</profile>
21+
<profile>
22+
<id>file</id>
23+
<activation>
24+
<file>
25+
<exists>simple.xml</exists>
26+
</file>
27+
</activation>
28+
</profile>
29+
</profiles>
30+
</project>
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<!--
4+
Licensed to the Apache Software Foundation (ASF) under one
5+
or more contributor license agreements. See the NOTICE file
6+
distributed with this work for additional information
7+
regarding copyright ownership. The ASF licenses this file
8+
to you under the Apache License, Version 2.0 (the
9+
"License"); you may not use this file except in compliance
10+
with the License. You may obtain a copy of the License at
11+
12+
http://www.apache.org/licenses/LICENSE-2.0
13+
14+
Unless required by applicable law or agreed to in writing,
15+
software distributed under the License is distributed on an
16+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17+
KIND, either express or implied. See the License for the
18+
specific language governing permissions and limitations
19+
under the License.
20+
-->
21+
22+
<project xmlns="http://maven.apache.org/POM/4.1.0"
23+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
24+
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 https://maven.apache.org/xsd/maven-4.1.0.xsd"
25+
root="true">
26+
<modelVersion>4.1.0</modelVersion>
27+
28+
<groupId>test</groupId>
29+
<artifactId>test</artifactId>
30+
<version>0.1-SNAPSHOT</version>
31+
<packaging>pom</packaging>
32+
33+
<modules>
34+
<module>lib</module> <!-- the library -->
35+
<module>app</module> <!-- the application -->
36+
</modules>
37+
38+
<build>
39+
<pluginManagement>
40+
<plugins>
41+
<plugin>
42+
<groupId>org.apache.maven.plugins</groupId>
43+
<artifactId>maven-compiler-plugin</artifactId>
44+
<version>2.1</version>
45+
<configuration>
46+
<source> 1.5 </source>
47+
<target xml:space="preserve"> 1.5 </target>
48+
</configuration>
49+
</plugin>
50+
</plugins>
51+
</pluginManagement>
52+
<plugins>
53+
<plugin>
54+
<groupId>org.apache.maven.plugins</groupId>
55+
<artifactId>maven-compiler-plugin</artifactId>
56+
<executions>
57+
<execution>
58+
<id>test</id>
59+
</execution>
60+
</executions>
61+
</plugin>
62+
</plugins>
63+
</build>
64+
65+
<profiles>
66+
<profile>
67+
<id>default-active</id>
68+
<activation>
69+
<activeByDefault>true</activeByDefault>
70+
</activation>
71+
<properties>
72+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
73+
</properties>
74+
</profile>
75+
<profile>
76+
<id>file</id>
77+
<activation>
78+
<file>
79+
<exists>simple.xml</exists>
80+
</file>
81+
</activation>
82+
<properties>
83+
<profile.file>activated</profile.file>
84+
</properties>
85+
</profile>
86+
</profiles>
87+
</project>

maven-model-transform/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ under the License.
2828
<name>Maven Model XML Transform</name>
2929

3030
<dependencies>
31+
<dependency>
32+
<groupId>org.apache.maven</groupId>
33+
<artifactId>maven-model</artifactId>
34+
</dependency>
3135
<dependency>
3236
<groupId>org.codehaus.plexus</groupId>
3337
<artifactId>plexus-xml</artifactId>
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
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.model.transform;
20+
21+
import javax.xml.stream.XMLStreamException;
22+
import javax.xml.stream.XMLStreamReader;
23+
24+
import java.util.ArrayList;
25+
import java.util.List;
26+
27+
import org.apache.maven.api.model.Model;
28+
import org.apache.maven.model.transform.stax.BufferingParser;
29+
import org.apache.maven.model.v4.MavenModelVersion;
30+
import org.apache.maven.model.v4.MavenStaxReader;
31+
32+
public class ModelVersionDowngradeXMLFilter extends BufferingParser {
33+
34+
public static final String NAMESPACE_PREFIX = "http://maven.apache.org/POM/";
35+
36+
private final List<Event> buffer = new ArrayList<>();
37+
38+
public ModelVersionDowngradeXMLFilter(XMLStreamReader delegate) {
39+
super(delegate);
40+
}
41+
42+
@Override
43+
protected boolean accept() throws XMLStreamException {
44+
Event e = bufferEvent();
45+
buffer.add(e);
46+
if (e.event == XMLStreamReader.END_DOCUMENT) {
47+
ReplayParser p = new ReplayParser(this);
48+
buffer.forEach(p::pushEvent);
49+
p.next();
50+
String version;
51+
Model model = new MavenStaxReader().read(p, false, null);
52+
if (model.isDowngradeModelVersion()) {
53+
model = model.withDowngradeModelVersion(false);
54+
version = new MavenModelVersion().getModelVersion(model);
55+
} else {
56+
version = model.getModelVersion();
57+
}
58+
int depth = 0;
59+
boolean isModelVersion = false;
60+
for (Event event : buffer) {
61+
event.namespace = NAMESPACE_PREFIX + version;
62+
// rewrite namespace
63+
if (event.namespaces != null) {
64+
for (int i = 0; i < event.namespaces.length; i++) {
65+
if (event.namespaces[i].uri.startsWith(NAMESPACE_PREFIX)) {
66+
event.namespaces[i].uri = event.namespace;
67+
}
68+
}
69+
}
70+
// rewrite xsi:schemaLocation attribute
71+
if (event.attributes != null) {
72+
for (Attribute attribute : event.attributes) {
73+
if (attribute.namespace.equals("http://www.w3.org/2001/XMLSchema-instance")
74+
&& attribute.name.equals("schemaLocation")) {
75+
attribute.value = attribute
76+
.value
77+
.replaceAll(
78+
"\\Q" + NAMESPACE_PREFIX + "\\E[0-9]\\.[0-9]\\.[0-9]",
79+
NAMESPACE_PREFIX + version)
80+
.replaceAll(
81+
"http(s?)://maven\\.apache\\.org/xsd/maven-[0-9]\\.[0-9]\\.[0-9]\\.xsd",
82+
"https://maven.apache.org/xsd/maven-" + version + ".xsd");
83+
}
84+
}
85+
}
86+
// Rewrite modelVersion
87+
if (event.event == XMLStreamReader.START_ELEMENT) {
88+
depth++;
89+
isModelVersion = depth == 2 && event.name.equals("modelVersion");
90+
}
91+
if (event.event == XMLStreamReader.CHARACTERS && isModelVersion) {
92+
event.text = version;
93+
}
94+
if (event.event == XMLStreamReader.END_ELEMENT) {
95+
depth--;
96+
isModelVersion = false;
97+
}
98+
pushEvent(event);
99+
}
100+
}
101+
return false;
102+
}
103+
104+
static class ReplayParser extends BufferingParser {
105+
ReplayParser(XMLStreamReader delegate) {
106+
super(delegate);
107+
}
108+
109+
public void pushEvent(Event e) {
110+
super.pushEvent(e);
111+
}
112+
}
113+
}

maven-model-transform/src/main/java/org/apache/maven/model/transform/ModelVersionXMLFilter.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@
2727

2828
public class ModelVersionXMLFilter extends NodeBufferingParser {
2929

30-
private static final Pattern S_FILTER = Pattern.compile("\\s+");
3130
public static final String NAMESPACE_PREFIX = "http://maven.apache.org/POM/";
3231

32+
private static final Pattern S_FILTER = Pattern.compile("\\s+");
33+
3334
public ModelVersionXMLFilter(XMLStreamReader delegate) {
3435
super(delegate, "project");
3536
}

0 commit comments

Comments
 (0)