mirror of https://github.com/apache/maven.git
[MNG-7876] Add model version analysis and downgrade (#1235)
This commit is contained in:
parent
46fd5e9586
commit
45075233c7
|
@ -214,7 +214,7 @@
|
|||
</field>
|
||||
<field xml.attribute="true" xml.tagName="root">
|
||||
<name>root</name>
|
||||
<version>4.0.0+</version>
|
||||
<version>4.1.0+</version>
|
||||
<description>
|
||||
<![CDATA[
|
||||
Indicates that this project is the root project, located in the upper directory of the source tree.
|
||||
|
@ -225,6 +225,19 @@
|
|||
<type>boolean</type>
|
||||
<defaultValue>false</defaultValue>
|
||||
</field>
|
||||
<field xml.attribute="true" xml.tagName="preserve.model.version">
|
||||
<name>preserveModelVersion</name>
|
||||
<version>4.1.0+</version>
|
||||
<description>
|
||||
<![CDATA[
|
||||
Indicates if the build POM for this project should be preserved or downgraded to the lowest
|
||||
compatible version.
|
||||
<br><b>Since</b>: Maven 4.0.0
|
||||
]]>
|
||||
</description>
|
||||
<type>boolean</type>
|
||||
<defaultValue>false</defaultValue>
|
||||
</field>
|
||||
<field>
|
||||
<name>inceptionYear</name>
|
||||
<version>3.0.0+</version>
|
||||
|
|
|
@ -18,7 +18,7 @@ under the License.
|
|||
-->
|
||||
|
||||
<project>
|
||||
<modelVersion>4.0.1</modelVersion>
|
||||
<modelVersion>4.9.1</modelVersion>
|
||||
<groupId>tests.project</groupId>
|
||||
<artifactId>future-model-version</artifactId>
|
||||
<version>1</version>
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>0.1-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<configuration>
|
||||
<source> 1.5 </source>
|
||||
<target xml:space="preserve"> 1.5 </target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>default-active</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>file</id>
|
||||
<activation>
|
||||
<file>
|
||||
<exists>simple.xml</exists>
|
||||
</file>
|
||||
</activation>
|
||||
<properties>
|
||||
<profile.file>activated</profile.file>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
|
@ -0,0 +1,87 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 https://maven.apache.org/xsd/maven-4.1.0.xsd"
|
||||
root="true">
|
||||
<modelVersion>4.1.0</modelVersion>
|
||||
|
||||
<groupId>test</groupId>
|
||||
<artifactId>test</artifactId>
|
||||
<version>0.1-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>lib</module> <!-- the library -->
|
||||
<module>app</module> <!-- the application -->
|
||||
</modules>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<configuration>
|
||||
<source> 1.5 </source>
|
||||
<target xml:space="preserve"> 1.5 </target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>default-active</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>file</id>
|
||||
<activation>
|
||||
<file>
|
||||
<exists>simple.xml</exists>
|
||||
</file>
|
||||
</activation>
|
||||
<properties>
|
||||
<profile.file>activated</profile.file>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
|
@ -59,6 +59,7 @@ import org.apache.maven.model.building.ModelProblem.Version;
|
|||
import org.apache.maven.model.building.ModelProblemCollector;
|
||||
import org.apache.maven.model.building.ModelProblemCollectorRequest;
|
||||
import org.apache.maven.model.interpolation.ModelVersionProcessor;
|
||||
import org.apache.maven.model.v4.MavenModelVersion;
|
||||
import org.codehaus.plexus.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
@ -143,15 +144,11 @@ public class DefaultModelValidator implements ModelValidator {
|
|||
|
||||
Severity errOn30 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0);
|
||||
|
||||
// [MNG-6074] Maven should produce an error if no model version has been set in a POM file used to build an
|
||||
// effective model.
|
||||
//
|
||||
// As of 3.4, the model version is mandatory even in raw models. The XML element still is optional in the
|
||||
// XML schema and this will not change anytime soon. We do not want to build effective models based on
|
||||
// models without a version starting with 3.4.
|
||||
validateStringNotEmpty("modelVersion", problems, Severity.ERROR, Version.V20, m.getModelVersion(), m);
|
||||
|
||||
validateModelVersion(problems, m.getModelVersion(), m, "4.0.0");
|
||||
// The file pom may not contain the modelVersion yet, as it may be set later by the
|
||||
// ModelVersionXMLFilter.
|
||||
if (m.getModelVersion() != null && !m.getModelVersion().isEmpty()) {
|
||||
validateModelVersion(problems, m.getModelVersion(), m, "4.0.0", "4.1.0");
|
||||
}
|
||||
|
||||
validateStringNoExpression("groupId", problems, Severity.WARNING, Version.V20, m.getGroupId(), m);
|
||||
if (parent == null) {
|
||||
|
@ -257,6 +254,28 @@ public class DefaultModelValidator implements ModelValidator {
|
|||
public void validateRawModel(Model ma, ModelBuildingRequest request, ModelProblemCollector problems) {
|
||||
org.apache.maven.api.model.Model m = ma.getDelegate();
|
||||
|
||||
// [MNG-6074] Maven should produce an error if no model version has been set in a POM file used to build an
|
||||
// effective model.
|
||||
//
|
||||
// As of 3.4, the model version is mandatory even in raw models. The XML element still is optional in the
|
||||
// XML schema and this will not change anytime soon. We do not want to build effective models based on
|
||||
// models without a version starting with 3.4.
|
||||
validateStringNotEmpty("modelVersion", problems, Severity.ERROR, Version.V20, m.getModelVersion(), m);
|
||||
|
||||
validateModelVersion(problems, m.getModelVersion(), m, "4.0.0", "4.1.0");
|
||||
|
||||
String minVersion = new MavenModelVersion().getModelVersion(m);
|
||||
if (m.getModelVersion() != null && compareModelVersions(minVersion, m.getModelVersion()) > 0) {
|
||||
addViolation(
|
||||
problems,
|
||||
Severity.FATAL,
|
||||
Version.V40,
|
||||
"model",
|
||||
null,
|
||||
"the model contains elements that require a model version of " + minVersion,
|
||||
m);
|
||||
}
|
||||
|
||||
Parent parent = m.getParent();
|
||||
|
||||
if (parent != null) {
|
||||
|
|
|
@ -61,13 +61,19 @@ public class SimpleProblemCollector implements ModelProblemCollector {
|
|||
public void add(ModelProblemCollectorRequest req) {
|
||||
switch (req.getSeverity()) {
|
||||
case FATAL:
|
||||
fatals.add(req.getMessage());
|
||||
if (!fatals.contains(req.getMessage())) {
|
||||
fatals.add(req.getMessage());
|
||||
}
|
||||
break;
|
||||
case ERROR:
|
||||
errors.add(req.getMessage());
|
||||
if (!errors.contains(req.getMessage())) {
|
||||
errors.add(req.getMessage());
|
||||
}
|
||||
break;
|
||||
case WARNING:
|
||||
warnings.add(req.getMessage());
|
||||
if (!warnings.contains(req.getMessage())) {
|
||||
warnings.add(req.getMessage());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,10 @@ under the License.
|
|||
<name>Maven Model XML Transform</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-model</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.plexus</groupId>
|
||||
<artifactId>plexus-xml</artifactId>
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
package org.apache.maven.model.transform;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamReader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.maven.api.model.Model;
|
||||
import org.apache.maven.model.transform.stax.BufferingParser;
|
||||
import org.apache.maven.model.v4.MavenModelVersion;
|
||||
import org.apache.maven.model.v4.MavenStaxReader;
|
||||
|
||||
public class ModelVersionDowngradeXMLFilter extends BufferingParser {
|
||||
|
||||
public static final String NAMESPACE_PREFIX = "http://maven.apache.org/POM/";
|
||||
|
||||
private final List<Event> buffer = new ArrayList<>();
|
||||
|
||||
public ModelVersionDowngradeXMLFilter(XMLStreamReader delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean accept() throws XMLStreamException {
|
||||
Event e = bufferEvent();
|
||||
buffer.add(e);
|
||||
if (e.event == XMLStreamReader.END_DOCUMENT) {
|
||||
ReplayParser p = new ReplayParser(this);
|
||||
buffer.forEach(p::pushEvent);
|
||||
p.next();
|
||||
String version;
|
||||
Model model = new MavenStaxReader().read(p, false, null);
|
||||
if (model.isPreserveModelVersion()) {
|
||||
version = model.getModelVersion();
|
||||
} else {
|
||||
model = model.withPreserveModelVersion(false);
|
||||
version = new MavenModelVersion().getModelVersion(model);
|
||||
}
|
||||
int depth = 0;
|
||||
boolean isModelVersion = false;
|
||||
for (Event event : buffer) {
|
||||
event.namespace = NAMESPACE_PREFIX + version;
|
||||
// rewrite namespace
|
||||
if (event.namespaces != null) {
|
||||
for (int i = 0; i < event.namespaces.length; i++) {
|
||||
if (event.namespaces[i].uri.startsWith(NAMESPACE_PREFIX)) {
|
||||
event.namespaces[i].uri = event.namespace;
|
||||
}
|
||||
}
|
||||
}
|
||||
// rewrite xsi:schemaLocation attribute
|
||||
if (event.attributes != null) {
|
||||
for (Attribute attribute : event.attributes) {
|
||||
if (attribute.namespace.equals("http://www.w3.org/2001/XMLSchema-instance")
|
||||
&& attribute.name.equals("schemaLocation")) {
|
||||
attribute.value = attribute
|
||||
.value
|
||||
.replaceAll(
|
||||
"\\Q" + NAMESPACE_PREFIX + "\\E[0-9]\\.[0-9]\\.[0-9]",
|
||||
NAMESPACE_PREFIX + version)
|
||||
.replaceAll(
|
||||
"http(s?)://maven\\.apache\\.org/xsd/maven-[0-9]\\.[0-9]\\.[0-9]\\.xsd",
|
||||
"https://maven.apache.org/xsd/maven-" + version + ".xsd");
|
||||
}
|
||||
}
|
||||
}
|
||||
// Rewrite modelVersion
|
||||
if (event.event == XMLStreamReader.START_ELEMENT) {
|
||||
depth++;
|
||||
isModelVersion = depth == 2 && event.name.equals("modelVersion");
|
||||
}
|
||||
if (event.event == XMLStreamReader.CHARACTERS && isModelVersion) {
|
||||
event.text = version;
|
||||
}
|
||||
if (event.event == XMLStreamReader.END_ELEMENT) {
|
||||
depth--;
|
||||
isModelVersion = false;
|
||||
}
|
||||
pushEvent(event);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static class ReplayParser extends BufferingParser {
|
||||
ReplayParser(XMLStreamReader delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
public void pushEvent(Event e) {
|
||||
super.pushEvent(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,9 +27,10 @@ import org.apache.maven.model.transform.stax.NodeBufferingParser;
|
|||
|
||||
public class ModelVersionXMLFilter extends NodeBufferingParser {
|
||||
|
||||
private static final Pattern S_FILTER = Pattern.compile("\\s+");
|
||||
public static final String NAMESPACE_PREFIX = "http://maven.apache.org/POM/";
|
||||
|
||||
private static final Pattern S_FILTER = Pattern.compile("\\s+");
|
||||
|
||||
public ModelVersionXMLFilter(XMLStreamReader delegate) {
|
||||
super(delegate, "project");
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@ public class RawToConsumerPomXMLFilterFactory {
|
|||
parser = new ModulesXMLFilter(parser);
|
||||
// Adjust relativePath
|
||||
parser = new RelativePathXMLFilter(parser);
|
||||
// Downgrade modelVersion if needed
|
||||
parser = new ModelVersionDowngradeXMLFilter(parser);
|
||||
|
||||
return parser;
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ class ConsumerPomXMLFilterTest extends AbstractXMLFilterTests {
|
|||
+ "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n"
|
||||
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
|
||||
+ " xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0\n"
|
||||
+ " http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n"
|
||||
+ " https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n"
|
||||
+ " <modelVersion>4.0.0</modelVersion>\n"
|
||||
+ " <groupId>org.sonatype.mavenbook.multispring</groupId>\n"
|
||||
+ " <artifactId>parent</artifactId>\n"
|
||||
|
@ -163,7 +163,7 @@ class ConsumerPomXMLFilterTest extends AbstractXMLFilterTests {
|
|||
+ "\n"
|
||||
+ "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n"
|
||||
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
|
||||
+ " xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n"
|
||||
+ " xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n"
|
||||
+ " <modelVersion>4.0.0</modelVersion>\n"
|
||||
+ " <parent>\n"
|
||||
+ " <groupId>org.apache.maven</groupId>\n"
|
||||
|
@ -226,4 +226,82 @@ class ConsumerPomXMLFilterTest extends AbstractXMLFilterTests {
|
|||
String actual = transform(input);
|
||||
assertThat(actual).and(expected).areIdentical();
|
||||
}
|
||||
|
||||
@Test
|
||||
void downgradeModelVersion() throws Exception {
|
||||
String input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
+ "<project xmlns=\"http://maven.apache.org/POM/4.1.0\"\n"
|
||||
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
|
||||
+ " xsi:schemaLocation=\"http://maven.apache.org/POM/4.1.0\n"
|
||||
+ " http://maven.apache.org/xsd/maven-4.1.0.xsd\">\n"
|
||||
+ " <modelVersion>4.1.0</modelVersion>\n"
|
||||
+ " <groupId>org.sonatype.mavenbook.multispring</groupId>\n"
|
||||
+ " <artifactId>parent</artifactId>\n"
|
||||
+ " <version>0.9-SNAPSHOT</version>\n"
|
||||
+ " <packaging>pom</packaging>\n"
|
||||
+ "</project>";
|
||||
String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
+ "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n"
|
||||
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
|
||||
+ " xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0\n"
|
||||
+ " https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n"
|
||||
+ " <modelVersion>4.0.0</modelVersion>\n"
|
||||
+ " <groupId>org.sonatype.mavenbook.multispring</groupId>\n"
|
||||
+ " <artifactId>parent</artifactId>\n"
|
||||
+ " <version>0.9-SNAPSHOT</version>\n"
|
||||
+ " <packaging>pom</packaging>\n"
|
||||
+ "</project>";
|
||||
String actual = transform(input);
|
||||
assertThat(actual).and(expected).ignoreWhitespace().areIdentical();
|
||||
}
|
||||
|
||||
@Test
|
||||
void downgradeNotModelVersion() throws Exception {
|
||||
String input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
+ "<project xmlns=\"http://maven.apache.org/POM/4.1.0\"\n"
|
||||
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
|
||||
+ " xsi:schemaLocation=\"http://maven.apache.org/POM/4.1.0 http://maven.apache.org/xsd/maven-4.1.0.xsd\""
|
||||
+ " preserve.model.version=\"true\">\n"
|
||||
+ " <modelVersion>4.1.0</modelVersion>\n"
|
||||
+ " <groupId>org.sonatype.mavenbook.multispring</groupId>\n"
|
||||
+ " <artifactId>parent</artifactId>\n"
|
||||
+ " <version>0.9-SNAPSHOT</version>\n"
|
||||
+ " <packaging>pom</packaging>\n"
|
||||
+ " <build>"
|
||||
+ " <plugins>\n"
|
||||
+ " <plugin>\n"
|
||||
+ " <executions>\n"
|
||||
+ " <execution>\n"
|
||||
+ " <priority>1</priority>\n"
|
||||
+ " </execution>\n"
|
||||
+ " </executions>\n"
|
||||
+ " </plugin>\n"
|
||||
+ " </plugins>\n"
|
||||
+ " </build>\n"
|
||||
+ "</project>";
|
||||
String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
+ "<project xmlns=\"http://maven.apache.org/POM/4.1.0\"\n"
|
||||
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
|
||||
+ " preserve.model.version=\"true\""
|
||||
+ " xsi:schemaLocation=\"http://maven.apache.org/POM/4.1.0 https://maven.apache.org/xsd/maven-4.1.0.xsd\">\n"
|
||||
+ " <modelVersion>4.1.0</modelVersion>\n"
|
||||
+ " <groupId>org.sonatype.mavenbook.multispring</groupId>\n"
|
||||
+ " <artifactId>parent</artifactId>\n"
|
||||
+ " <version>0.9-SNAPSHOT</version>\n"
|
||||
+ " <packaging>pom</packaging>\n"
|
||||
+ " <build>"
|
||||
+ " <plugins>\n"
|
||||
+ " <plugin>\n"
|
||||
+ " <executions>\n"
|
||||
+ " <execution>\n"
|
||||
+ " <priority>1</priority>\n"
|
||||
+ " </execution>\n"
|
||||
+ " </executions>\n"
|
||||
+ " </plugin>\n"
|
||||
+ " </plugins>\n"
|
||||
+ " </build>\n"
|
||||
+ "</project>";
|
||||
String actual = transform(input);
|
||||
assertThat(actual).and(expected).ignoreWhitespace().areIdentical();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@ under the License.
|
|||
<param>packageModelV4=org.apache.maven.api.model</param>
|
||||
<param>packageToolV4=org.apache.maven.model.v4</param>
|
||||
<param>isMavenModel=true</param>
|
||||
<param>minimalVersion=4.0.0</param>
|
||||
</params>
|
||||
</configuration>
|
||||
<executions>
|
||||
|
@ -123,6 +124,7 @@ under the License.
|
|||
<template>writer-ex.vm</template>
|
||||
<template>reader-stax.vm</template>
|
||||
<template>writer-stax.vm</template>
|
||||
<template>model-version.vm</template>
|
||||
</templates>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.
|
||||
*/
|
||||
package org.apache.maven.model.v4;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.apache.maven.api.model.Model;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class MavenModelVersionTest {
|
||||
|
||||
private static Model model;
|
||||
|
||||
@BeforeAll
|
||||
static void setup() throws Exception {
|
||||
try (InputStream is = MavenModelVersionTest.class.getResourceAsStream("/xml/pom.xml")) {
|
||||
model = new MavenStaxReader().read(is);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testV4Model() {
|
||||
assertEquals("4.0.0", new MavenModelVersion().getModelVersion(model));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testV4ModelVersion() {
|
||||
Model m = model.withModelVersion("4.1.0");
|
||||
assertEquals("4.0.0", new MavenModelVersion().getModelVersion(m));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testV4ModelRoot() {
|
||||
Model m = model.withRoot(true);
|
||||
assertEquals("4.1.0", new MavenModelVersion().getModelVersion(m));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testV4ModelPreserveModelVersion() {
|
||||
Model m = model.withPreserveModelVersion(true);
|
||||
assertEquals("4.1.0", new MavenModelVersion().getModelVersion(m));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
#*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*#
|
||||
#parse ( "common.vm" )
|
||||
#
|
||||
#set ( $package = "${packageToolV4}" )
|
||||
#set ( $className = "${model.name}ModelVersion" )
|
||||
#
|
||||
#set ( $root = $model.getClass( $model.getRoot($version), $version ) )
|
||||
#
|
||||
#MODELLO-VELOCITY#SAVE-OUTPUT-TO ${package.replace('.','/')}/${className}.java
|
||||
// =================== DO NOT EDIT THIS FILE ====================
|
||||
// Generated by Modello Velocity from ${template}
|
||||
// template, any modifications will be overwritten.
|
||||
// ==============================================================
|
||||
package ${package};
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.maven.api.annotations.Generated;
|
||||
import org.apache.maven.api.xml.XmlNode;
|
||||
#foreach ( $class in $model.allClasses )
|
||||
import ${packageModelV4}.${class.Name};
|
||||
#end
|
||||
|
||||
@Generated
|
||||
public class ${className} {
|
||||
|
||||
public String getModelVersion(${root.name} model) {
|
||||
Objects.requireNonNull(model, "model cannot be null");
|
||||
|
||||
#set ( $String = $model.getClass().forName("java.lang.String") )
|
||||
#set ( $Comparator = $model.getClass().forName("java.util.Comparator") )
|
||||
#set ( $LinkedHashSet = $model.getClass().forName("java.util.LinkedHashSet") )
|
||||
#set ( $HashMap = $model.getClass().forName("java.util.HashMap") )
|
||||
#set ( $TreeSet = $model.getClass().forName("java.util.TreeSet") )
|
||||
#set ( $Version = $model.getClass().forName("org.codehaus.modello.model.Version") )
|
||||
#set ( $versions = $TreeSet.getConstructor( $Comparator ).newInstance( $Comparator.reverseOrder() ) )
|
||||
#foreach ( $class in $model.allClasses )
|
||||
#set ( $dummy = $versions.add( $class.versionRange.fromVersion ) )
|
||||
#foreach ( $field in $class.allFields )
|
||||
#if ( ! $Helper.xmlFieldMetadata( $field ).transient )
|
||||
#set ( $dummy = $versions.add( $field.versionRange.fromVersion ) )
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
#if ( $minimalVersion )
|
||||
#set ( $minimal = $Version.getConstructor( $String ).newInstance( $minimalVersion ) )
|
||||
#set ( $versions = $versions.headSet( $minimal, false ) )
|
||||
#else
|
||||
#set ( $dummy = $versions.remove( $Version.getConstructor( $String ).newInstance( "0.0.0" ) ) )
|
||||
#end
|
||||
#set ( $dummy = $versions.remove( $Version.getConstructor( $String ).newInstance( "32767.32767.32767" ) ) )
|
||||
#foreach ( $version in $versions )
|
||||
#set ( $v = $version.toString().replace('.', '_') )
|
||||
// ${version}
|
||||
if (is_${v}(model)) {
|
||||
return "${version}";
|
||||
}
|
||||
#end
|
||||
#if ( $minimalVersion )
|
||||
return "$minimalVersion";
|
||||
#else
|
||||
return null;
|
||||
#end
|
||||
}
|
||||
|
||||
#foreach ( $version in $versions )
|
||||
#set ( $v = $version.toString().replace('.', '_') )
|
||||
#set ( $classesToCheck = $TreeSet.newInstance() )
|
||||
#set ( $classToFields = $HashMap.newInstance() )
|
||||
#foreach($unused in [1..10])
|
||||
#foreach ( $class in $model.allClasses )
|
||||
#foreach ( $field in $class.allFields )
|
||||
#if ( ! $Helper.xmlFieldMetadata( $field ).transient )
|
||||
#set ( $newInVersion = $field.versionRange.fromVersion.equals($version) )
|
||||
#set ( $isAsso = false )
|
||||
#if ( $field.toClass )
|
||||
#set ( $ancestors = $Helper.ancestors( $field.toClass ) )
|
||||
#foreach ( $cl in $ancestors )
|
||||
#if ( $classToFields.containsKey( $cl ) )
|
||||
#set ( $isAsso = true )
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
#if ( $newInVersion || $isAsso )
|
||||
#set ( $fields = $classToFields.get( $class ) )
|
||||
#if ( ! $fields )
|
||||
#set ( $fields = $LinkedHashSet.newInstance() )
|
||||
#set ( $dummy = $classToFields.put( $class, $fields ) )
|
||||
#end
|
||||
#set( $dummy = $fields.add($field) )
|
||||
#if ( $dummy )
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
#foreach ( $class in $classToFields.keySet() )
|
||||
#set ( $var = $Helper.uncapitalise( $class.name ) )
|
||||
private boolean is_${v}(${class.name} ${var}) {
|
||||
return ${var} != null && (
|
||||
#set ( $pfx = " " )
|
||||
#if ( $class.superClass )
|
||||
#if ( $classToFields.containsKey( $model.getClass( $class.superClass, $version ) ) )
|
||||
$pfx is_${v}((${class.superClass}) ${var})
|
||||
#set ( $pfx = "||" )
|
||||
#end
|
||||
#end
|
||||
#foreach ( $field in $classToFields.get( $class ) )
|
||||
#if ( $field.isManyMultiplicity() )
|
||||
#if ( $classToFields.containsKey( $model.getClass( $field.type ) ) )
|
||||
$pfx ${var}.get${Helper.capitalise($field.name)}().stream().anyMatch(this::is_${v}) // ${class.name} : ${field.name}
|
||||
#else
|
||||
$pfx !${var}.get${Helper.capitalise($field.name)}().isEmpty() // ${class.name} : ${field.name}
|
||||
#end
|
||||
#elseif ( $field.isOneMultiplicity() )
|
||||
$pfx is_${v}(${var}.get${Helper.capitalise($field.name)}()) // ${class.name} : ${field.name}
|
||||
#elseif ( $field.type == "boolean" || $field.type == "Boolean" )
|
||||
$pfx has(${var}.is${Helper.capitalise($field.name)}()) // ${class.name} : ${field.name}
|
||||
#else
|
||||
$pfx has(${var}.get${Helper.capitalise($field.name)}()) // ${class.name} : ${field.name}
|
||||
#end
|
||||
#set ( $pfx = "||" )
|
||||
#end
|
||||
);
|
||||
}
|
||||
#end
|
||||
|
||||
#end
|
||||
private boolean has(String str) {
|
||||
return str != null;
|
||||
}
|
||||
|
||||
private boolean has(Path path) {
|
||||
return path != null;
|
||||
}
|
||||
|
||||
private boolean has(boolean bool) {
|
||||
return bool;
|
||||
}
|
||||
|
||||
private boolean has(int val) {
|
||||
return val != 0;
|
||||
}
|
||||
|
||||
private boolean has(List<?> list) {
|
||||
return !list.isEmpty();
|
||||
}
|
||||
|
||||
}
|
|
@ -84,10 +84,25 @@ public class ${className} {
|
|||
//--------------------------/
|
||||
|
||||
/**
|
||||
* Field NAMESPACE.
|
||||
* Default namespace.
|
||||
*/
|
||||
private static final String NAMESPACE = "${namespace}";
|
||||
|
||||
/**
|
||||
* Default schemaLocation.
|
||||
*/
|
||||
private static final String SCHEMA_LOCATION = "${schemaLocation}";
|
||||
|
||||
/**
|
||||
* Field namespace.
|
||||
*/
|
||||
private String namespace = NAMESPACE;
|
||||
|
||||
/**
|
||||
* Field schemaLocation.
|
||||
*/
|
||||
private String schemaLocation = SCHEMA_LOCATION;
|
||||
|
||||
/**
|
||||
* Field fileComment.
|
||||
*/
|
||||
|
@ -106,6 +121,24 @@ public class ${className} {
|
|||
//- Methods -/
|
||||
//-----------/
|
||||
|
||||
/**
|
||||
* Method setNamespace.
|
||||
*
|
||||
* @param namespace the namespace to use.
|
||||
*/
|
||||
public void setNamespace(String namespace) {
|
||||
this.namespace = Objects.requireNonNull(namespace);
|
||||
} //-- void setNamespace(String)
|
||||
|
||||
/**
|
||||
* Method setSchemaLocation.
|
||||
*
|
||||
* @param schemaLocation the schema location to use.
|
||||
*/
|
||||
public void setSchemaLocation(String schemaLocation) {
|
||||
this.schemaLocation = Objects.requireNonNull(schemaLocation);
|
||||
} //-- void setSchemaLocation(String)
|
||||
|
||||
/**
|
||||
* Method setFileComment.
|
||||
*
|
||||
|
@ -183,12 +216,12 @@ public class ${className} {
|
|||
serializer.writeComment(this.fileComment);
|
||||
serializer.writeCharacters("\n");
|
||||
}
|
||||
serializer.writeStartElement("", tagName, NAMESPACE);
|
||||
serializer.writeNamespace("", NAMESPACE);
|
||||
serializer.writeStartElement("", tagName, namespace);
|
||||
serializer.writeNamespace("", namespace);
|
||||
serializer.writeNamespace("xsi", W3C_XML_SCHEMA_INSTANCE_NS_URI);
|
||||
serializer.writeAttribute(W3C_XML_SCHEMA_INSTANCE_NS_URI, "schemaLocation", NAMESPACE + " ${schemaLocation}");
|
||||
serializer.writeAttribute(W3C_XML_SCHEMA_INSTANCE_NS_URI, "schemaLocation", namespace + " " + schemaLocation);
|
||||
#else
|
||||
serializer.writeStartElement(NAMESPACE, tagName);
|
||||
serializer.writeStartElement(namespace, tagName);
|
||||
#end
|
||||
#foreach ( $field in $allFields )
|
||||
#if ( $Helper.xmlFieldMetadata( $field ).attribute )
|
||||
|
@ -283,7 +316,7 @@ public class ${className} {
|
|||
#end
|
||||
if (list != null && !list.isEmpty()) {
|
||||
if (!flat) {
|
||||
serializer.writeStartElement(NAMESPACE, tagName);
|
||||
serializer.writeStartElement(namespace, tagName);
|
||||
}
|
||||
int index = 0;
|
||||
#if ( $locationTracking )
|
||||
|
@ -307,7 +340,7 @@ public class ${className} {
|
|||
private <T> void writeProperties(String tagName, Map<String, String> props, XMLStreamWriter serializer) throws IOException, XMLStreamException {
|
||||
#end
|
||||
if (props != null && !props.isEmpty()) {
|
||||
serializer.writeStartElement(NAMESPACE, tagName);
|
||||
serializer.writeStartElement(namespace, tagName);
|
||||
#if ( $locationTracking )
|
||||
InputLocation location = locationTracker != null ? locationTracker.getLocation(tagName) : null;
|
||||
#end
|
||||
|
@ -326,7 +359,7 @@ public class ${className} {
|
|||
|
||||
private void writeDom(XmlNode dom, XMLStreamWriter serializer) throws IOException, XMLStreamException {
|
||||
if (dom != null) {
|
||||
serializer.writeStartElement(NAMESPACE, dom.getName());
|
||||
serializer.writeStartElement(namespace, dom.getName());
|
||||
for (Map.Entry<String, String> attr : dom.getAttributes().entrySet()) {
|
||||
if (attr.getKey().startsWith("xml:")) {
|
||||
serializer.writeAttribute("http://www.w3.org/XML/1998/namespace",
|
||||
|
@ -357,7 +390,7 @@ public class ${className} {
|
|||
private void writeTag(String tagName, String defaultValue, String value, XMLStreamWriter serializer) throws IOException, XMLStreamException {
|
||||
#end
|
||||
if (value != null && !Objects.equals(defaultValue, value)) {
|
||||
serializer.writeStartElement(NAMESPACE, tagName);
|
||||
serializer.writeStartElement(namespace, tagName);
|
||||
serializer.writeCharacters(value);
|
||||
serializer.writeEndElement();
|
||||
#if ( $locationTracking )
|
||||
|
|
Loading…
Reference in New Issue