diff --git a/api/maven-api-model/src/main/mdo/maven.mdo b/api/maven-api-model/src/main/mdo/maven.mdo index 1cf8f2ea49..2caa1077d9 100644 --- a/api/maven-api-model/src/main/mdo/maven.mdo +++ b/api/maven-api-model/src/main/mdo/maven.mdo @@ -214,7 +214,7 @@ root - 4.0.0+ + 4.1.0+ boolean false + + preserveModelVersion + 4.1.0+ + + Since: Maven 4.0.0 + ]]> + + boolean + false + inceptionYear 3.0.0+ diff --git a/maven-core/src/test/resources/projects/future-model-version-pom.xml b/maven-core/src/test/resources/projects/future-model-version-pom.xml index 1a73a44434..c76f97ce12 100644 --- a/maven-core/src/test/resources/projects/future-model-version-pom.xml +++ b/maven-core/src/test/resources/projects/future-model-version-pom.xml @@ -18,7 +18,7 @@ under the License. --> - 4.0.1 + 4.9.1 tests.project future-model-version 1 diff --git a/maven-core/src/test/resources/projects/transform/consumer-after.pom b/maven-core/src/test/resources/projects/transform/consumer-after.pom new file mode 100644 index 0000000000..2f7ef91990 --- /dev/null +++ b/maven-core/src/test/resources/projects/transform/consumer-after.pom @@ -0,0 +1,81 @@ + + + + + + 4.0.0 + + test + test + 0.1-SNAPSHOT + pom + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.1 + + 1.5 + 1.5 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + test + + + + + + + + + default-active + + true + + + UTF-8 + + + + file + + + simple.xml + + + + activated + + + + diff --git a/maven-core/src/test/resources/projects/transform/consumer-before.pom b/maven-core/src/test/resources/projects/transform/consumer-before.pom new file mode 100644 index 0000000000..60d0ccedf3 --- /dev/null +++ b/maven-core/src/test/resources/projects/transform/consumer-before.pom @@ -0,0 +1,87 @@ + + + + + + 4.1.0 + + test + test + 0.1-SNAPSHOT + pom + + + lib + app + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.1 + + 1.5 + 1.5 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + test + + + + + + + + + default-active + + true + + + UTF-8 + + + + file + + + simple.xml + + + + activated + + + + diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java b/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java index 2594dd9c35..39d76a6bbc 100644 --- a/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java +++ b/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java @@ -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) { diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/building/SimpleProblemCollector.java b/maven-model-builder/src/test/java/org/apache/maven/model/building/SimpleProblemCollector.java index 41d9a79fc2..9271005875 100644 --- a/maven-model-builder/src/test/java/org/apache/maven/model/building/SimpleProblemCollector.java +++ b/maven-model-builder/src/test/java/org/apache/maven/model/building/SimpleProblemCollector.java @@ -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; } } diff --git a/maven-model-transform/pom.xml b/maven-model-transform/pom.xml index 50a90c7ec4..26edb7a2e6 100644 --- a/maven-model-transform/pom.xml +++ b/maven-model-transform/pom.xml @@ -28,6 +28,10 @@ under the License. Maven Model XML Transform + + org.apache.maven + maven-model + org.codehaus.plexus plexus-xml diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ModelVersionDowngradeXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ModelVersionDowngradeXMLFilter.java new file mode 100644 index 0000000000..7207fc446b --- /dev/null +++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ModelVersionDowngradeXMLFilter.java @@ -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 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); + } + } +} diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ModelVersionXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ModelVersionXMLFilter.java index 645030aeee..1b721f7145 100644 --- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ModelVersionXMLFilter.java +++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ModelVersionXMLFilter.java @@ -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"); } diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RawToConsumerPomXMLFilterFactory.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/RawToConsumerPomXMLFilterFactory.java index 08af39e7d4..b69dcda756 100644 --- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RawToConsumerPomXMLFilterFactory.java +++ b/maven-model-transform/src/main/java/org/apache/maven/model/transform/RawToConsumerPomXMLFilterFactory.java @@ -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; } diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ConsumerPomXMLFilterTest.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/ConsumerPomXMLFilterTest.java index 9352984fe9..37e69d8665 100644 --- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ConsumerPomXMLFilterTest.java +++ b/maven-model-transform/src/test/java/org/apache/maven/model/transform/ConsumerPomXMLFilterTest.java @@ -120,7 +120,7 @@ class ConsumerPomXMLFilterTest extends AbstractXMLFilterTests { + "\n" + + " https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n" + " 4.0.0\n" + " org.sonatype.mavenbook.multispring\n" + " parent\n" @@ -163,7 +163,7 @@ class ConsumerPomXMLFilterTest extends AbstractXMLFilterTests { + "\n" + "\n" + + " xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n" + " 4.0.0\n" + " \n" + " org.apache.maven\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 = "\n" + + "\n" + + " 4.1.0\n" + + " org.sonatype.mavenbook.multispring\n" + + " parent\n" + + " 0.9-SNAPSHOT\n" + + " pom\n" + + ""; + String expected = "\n" + + "\n" + + " 4.0.0\n" + + " org.sonatype.mavenbook.multispring\n" + + " parent\n" + + " 0.9-SNAPSHOT\n" + + " pom\n" + + ""; + String actual = transform(input); + assertThat(actual).and(expected).ignoreWhitespace().areIdentical(); + } + + @Test + void downgradeNotModelVersion() throws Exception { + String input = "\n" + + "\n" + + " 4.1.0\n" + + " org.sonatype.mavenbook.multispring\n" + + " parent\n" + + " 0.9-SNAPSHOT\n" + + " pom\n" + + " " + + " \n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + String expected = "\n" + + "\n" + + " 4.1.0\n" + + " org.sonatype.mavenbook.multispring\n" + + " parent\n" + + " 0.9-SNAPSHOT\n" + + " pom\n" + + " " + + " \n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + String actual = transform(input); + assertThat(actual).and(expected).ignoreWhitespace().areIdentical(); + } } diff --git a/maven-model/pom.xml b/maven-model/pom.xml index 95cfaafa27..42e759edaf 100644 --- a/maven-model/pom.xml +++ b/maven-model/pom.xml @@ -82,6 +82,7 @@ under the License. packageModelV4=org.apache.maven.api.model packageToolV4=org.apache.maven.model.v4 isMavenModel=true + minimalVersion=4.0.0 @@ -123,6 +124,7 @@ under the License. + diff --git a/maven-model/src/test/java/org/apache/maven/model/v4/MavenModelVersionTest.java b/maven-model/src/test/java/org/apache/maven/model/v4/MavenModelVersionTest.java new file mode 100644 index 0000000000..ff2abdc981 --- /dev/null +++ b/maven-model/src/test/java/org/apache/maven/model/v4/MavenModelVersionTest.java @@ -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)); + } +} diff --git a/src/mdo/model-version.vm b/src/mdo/model-version.vm new file mode 100644 index 0000000000..67586b6342 --- /dev/null +++ b/src/mdo/model-version.vm @@ -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(); + } + +} diff --git a/src/mdo/writer-stax.vm b/src/mdo/writer-stax.vm index cb9097cfe8..b0ec820ebc 100644 --- a/src/mdo/writer-stax.vm +++ b/src/mdo/writer-stax.vm @@ -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 void writeProperties(String tagName, Map 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 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 )