This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git
The following commit(s) were added to refs/heads/master by this push:
new 0a8491c32 [MNG-7814] Use location tracking for settings (#1164)
0a8491c32 is described below
commit 0a8491c329782613dc58c000fabce67955cb47e5
Author: Guillaume Nodet <[email protected]>
AuthorDate: Mon Jun 19 12:39:14 2023 +0200
[MNG-7814] Use location tracking for settings (#1164)
---
.../apache/maven/settings/GlobalSettingsTest.java | 13 +-
api/maven-api-settings/pom.xml | 1 +
.../apache/maven/api/settings/InputLocation.java | 172 ++++
.../maven/api/settings/InputLocationTracker.java | 23 +
.../org/apache/maven/api/settings/InputSource.java | 47 +
api/maven-api-settings/src/main/mdo/settings.mdo | 52 +-
.../internal/impl/DefaultSettingsXmlFactory.java | 12 +-
.../settings/building/DefaultSettingsBuilder.java | 65 +-
.../maven/settings/io/DefaultSettingsReader.java | 12 +-
maven-settings/pom.xml | 28 +-
src/mdo/model-v3.vm | 16 +-
src/mdo/reader.vm | 1038 ++++++++++----------
12 files changed, 888 insertions(+), 591 deletions(-)
diff --git
a/apache-maven/src/test/java/org/apache/maven/settings/GlobalSettingsTest.java
b/apache-maven/src/test/java/org/apache/maven/settings/GlobalSettingsTest.java
index 9512d4a93..a8819f87b 100644
---
a/apache-maven/src/test/java/org/apache/maven/settings/GlobalSettingsTest.java
+++
b/apache-maven/src/test/java/org/apache/maven/settings/GlobalSettingsTest.java
@@ -19,12 +19,11 @@
package org.apache.maven.settings;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.nio.charset.StandardCharsets;
+import java.io.InputStream;
+import java.nio.file.Files;
-import org.apache.maven.settings.v4.SettingsXpp3Reader;
+import org.apache.maven.api.settings.InputSource;
+import org.apache.maven.settings.v4.SettingsXpp3ReaderEx;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -43,8 +42,8 @@ class GlobalSettingsTest {
File globalSettingsFile = new File(basedir,
"src/assembly/maven/conf/settings.xml");
assertTrue(globalSettingsFile.isFile(),
globalSettingsFile.getAbsolutePath());
- try (Reader reader = new InputStreamReader(new
FileInputStream(globalSettingsFile), StandardCharsets.UTF_8)) {
- new SettingsXpp3Reader().read(reader);
+ try (InputStream is =
Files.newInputStream(globalSettingsFile.toPath())) {
+ new SettingsXpp3ReaderEx().read(is, true, new
InputSource(globalSettingsFile.getAbsolutePath()));
}
}
}
diff --git a/api/maven-api-settings/pom.xml b/api/maven-api-settings/pom.xml
index 3a05752c6..db5265d22 100644
--- a/api/maven-api-settings/pom.xml
+++ b/api/maven-api-settings/pom.xml
@@ -61,6 +61,7 @@ under the License.
</templates>
<params>
<param>packageModelV4=org.apache.maven.api.settings</param>
+ <param>locationTracking=true</param>
</params>
</configuration>
</execution>
diff --git
a/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputLocation.java
b/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputLocation.java
new file mode 100644
index 000000000..b3ea38714
--- /dev/null
+++
b/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputLocation.java
@@ -0,0 +1,172 @@
+/*
+ * 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.api.settings;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Class InputLocation.
+ */
+public class InputLocation implements Serializable, InputLocationTracker {
+ private final int lineNumber;
+ private final int columnNumber;
+ private final InputSource source;
+ private final Map<Object, InputLocation> locations;
+
+ public InputLocation(InputSource source) {
+ this.lineNumber = -1;
+ this.columnNumber = -1;
+ this.source = source;
+ this.locations = Collections.singletonMap(0, this);
+ }
+
+ public InputLocation(int lineNumber, int columnNumber) {
+ this(lineNumber, columnNumber, null, null);
+ }
+
+ public InputLocation(int lineNumber, int columnNumber, InputSource source)
{
+ this(lineNumber, columnNumber, source, null);
+ }
+
+ public InputLocation(int lineNumber, int columnNumber, InputSource source,
Object selfLocationKey) {
+ this.lineNumber = lineNumber;
+ this.columnNumber = columnNumber;
+ this.source = source;
+ this.locations =
+ selfLocationKey != null ?
Collections.singletonMap(selfLocationKey, this) : Collections.emptyMap();
+ }
+
+ public InputLocation(int lineNumber, int columnNumber, InputSource source,
Map<Object, InputLocation> locations) {
+ this.lineNumber = lineNumber;
+ this.columnNumber = columnNumber;
+ this.source = source;
+ this.locations = ImmutableCollections.copy(locations);
+ }
+
+ public int getLineNumber() {
+ return lineNumber;
+ }
+
+ public int getColumnNumber() {
+ return columnNumber;
+ }
+
+ public InputSource getSource() {
+ return source;
+ }
+
+ public InputLocation getLocation(Object key) {
+ return locations != null ? locations.get(key) : null;
+ }
+
+ public Map<Object, InputLocation> getLocations() {
+ return locations;
+ }
+
+ /**
+ * Merges the {@code source} location into the {@code target} location.
+ *
+ * @param target the target location
+ * @param source the source location
+ * @param sourceDominant the boolean indicating of {@code source} is
dominant compared to {@code target}
+ * @return the merged location
+ */
+ public static InputLocation merge(InputLocation target, InputLocation
source, boolean sourceDominant) {
+ if (source == null) {
+ return target;
+ } else if (target == null) {
+ return source;
+ }
+
+ Map<Object, InputLocation> locations;
+ Map<Object, InputLocation> sourceLocations = source.locations;
+ Map<Object, InputLocation> targetLocations = target.locations;
+ if (sourceLocations == null) {
+ locations = targetLocations;
+ } else if (targetLocations == null) {
+ locations = sourceLocations;
+ } else {
+ locations = new LinkedHashMap<>();
+ locations.putAll(sourceDominant ? targetLocations :
sourceLocations);
+ locations.putAll(sourceDominant ? sourceLocations :
targetLocations);
+ }
+
+ return new InputLocation(target.getLineNumber(),
target.getColumnNumber(), target.getSource(), locations);
+ } // -- InputLocation merge( InputLocation, InputLocation, boolean )
+
+ /**
+ * Merges the {@code source} location into the {@code target} location.
+ * This method is used when the locations refer to lists and also merges
the indices.
+ *
+ * @param target the target location
+ * @param source the source location
+ * @param indices the list of integers for the indices
+ * @return the merged location
+ */
+ public static InputLocation merge(InputLocation target, InputLocation
source, Collection<Integer> indices) {
+ if (source == null) {
+ return target;
+ } else if (target == null) {
+ return source;
+ }
+
+ Map<Object, InputLocation> locations;
+ Map<Object, InputLocation> sourceLocations = source.locations;
+ Map<Object, InputLocation> targetLocations = target.locations;
+ if (sourceLocations == null) {
+ locations = targetLocations;
+ } else if (targetLocations == null) {
+ locations = sourceLocations;
+ } else {
+ locations = new LinkedHashMap<>();
+ for (int index : indices) {
+ InputLocation location;
+ if (index < 0) {
+ location = sourceLocations.get(~index);
+ } else {
+ location = targetLocations.get(index);
+ }
+ locations.put(locations.size(), location);
+ }
+ }
+
+ return new InputLocation(target.getLineNumber(),
target.getColumnNumber(), target.getSource(), locations);
+ } // -- InputLocation merge( InputLocation, InputLocation,
java.util.Collection )
+
+ /**
+ * Class StringFormatter.
+ *
+ * @version $Revision$ $Date$
+ */
+ public interface StringFormatter {
+
+ // -----------/
+ // - Methods -/
+ // -----------/
+
+ /**
+ * Method toString.
+ */
+ String toString(InputLocation location);
+ }
+}
diff --git
a/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputLocationTracker.java
b/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputLocationTracker.java
new file mode 100644
index 000000000..d49d72307
--- /dev/null
+++
b/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputLocationTracker.java
@@ -0,0 +1,23 @@
+/*
+ * 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.api.settings;
+
+public interface InputLocationTracker {
+ InputLocation getLocation(Object field);
+}
diff --git
a/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputSource.java
b/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputSource.java
new file mode 100644
index 000000000..2450c1d79
--- /dev/null
+++
b/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputSource.java
@@ -0,0 +1,47 @@
+/*
+ * 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.api.settings;
+
+import java.io.Serializable;
+
+/**
+ * Class InputSource.
+ */
+public class InputSource implements Serializable {
+
+ private final String location;
+
+ public InputSource(String location) {
+ this.location = location;
+ }
+
+ /**
+ * Get the path/URL of the settings definition or {@code null} if unknown.
+ *
+ * @return the location
+ */
+ public String getLocation() {
+ return this.location;
+ }
+
+ @Override
+ public String toString() {
+ return getLocation();
+ }
+}
diff --git a/api/maven-api-settings/src/main/mdo/settings.mdo
b/api/maven-api-settings/src/main/mdo/settings.mdo
index f1ec2e5bd..caef27588 100644
--- a/api/maven-api-settings/src/main/mdo/settings.mdo
+++ b/api/maven-api-settings/src/main/mdo/settings.mdo
@@ -266,7 +266,7 @@
</fields>
<codeSegments>
<codeSegment>
- <version>1.0.0+</version>
+ <version>1.0.0/1.2.0</version>
<code>
<![CDATA[
public Boolean getInteractiveMode()
@@ -1082,5 +1082,55 @@
</fields>
</class>
<!-- /BuildProfile support -->
+ <class locationTracker="locations">
+ <name>InputLocation</name>
+ <version>2.0.0+</version>
+ <fields>
+ <!-- line, column and source fields are auto-generated by Modello -->
+ </fields>
+ <codeSegments>
+ <codeSegment>
+ <version>2.0.0+</version>
+ <code>
+ <![CDATA[
+
+ @Override
+ public String toString() {
+ return getLineNumber() + " : " + getColumnNumber() + ", " +
getSource();
+ }
+ ]]>
+ </code>
+ </codeSegment>
+ </codeSegments>
+ </class>
+ <class sourceTracker="source">
+ <name>InputSource</name>
+ <version>2.0.0+</version>
+ <fields>
+ <field>
+ <name>location</name>
+ <version>2.0.0+</version>
+ <type>String</type>
+ <description>
+ <![CDATA[
+ The path/URL of the settings definition or {@code null} if unknown.
+ ]]>
+ </description>
+ </field>
+ </fields>
+ <codeSegments>
+ <codeSegment>
+ <version>2.0.0+</version>
+ <code>
+ <![CDATA[
+ @Override
+ public String toString() {
+ return getLocation();
+ }
+ ]]>
+ </code>
+ </codeSegment>
+ </codeSegments>
+ </class>
</classes>
</model>
diff --git
a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSettingsXmlFactory.java
b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSettingsXmlFactory.java
index 39303e9cd..811fd3c6b 100644
---
a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSettingsXmlFactory.java
+++
b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSettingsXmlFactory.java
@@ -28,14 +28,14 @@ import java.io.Writer;
import java.util.Objects;
import org.apache.maven.api.annotations.Nonnull;
-import org.apache.maven.api.model.InputSource;
import org.apache.maven.api.services.xml.SettingsXmlFactory;
import org.apache.maven.api.services.xml.XmlReaderException;
import org.apache.maven.api.services.xml.XmlReaderRequest;
import org.apache.maven.api.services.xml.XmlWriterException;
import org.apache.maven.api.services.xml.XmlWriterRequest;
+import org.apache.maven.api.settings.InputSource;
import org.apache.maven.api.settings.Settings;
-import org.apache.maven.settings.v4.SettingsXpp3Reader;
+import org.apache.maven.settings.v4.SettingsXpp3ReaderEx;
import org.apache.maven.settings.v4.SettingsXpp3Writer;
@Named
@@ -52,14 +52,14 @@ public class DefaultSettingsXmlFactory implements
SettingsXmlFactory {
try {
InputSource source = null;
if (request.getModelId() != null || request.getLocation() != null)
{
- source = new InputSource(request.getModelId(),
request.getLocation());
+ source = new InputSource(request.getLocation());
}
- SettingsXpp3Reader xml = new SettingsXpp3Reader();
+ SettingsXpp3ReaderEx xml = new SettingsXpp3ReaderEx();
xml.setAddDefaultEntities(request.isAddDefaultEntities());
if (reader != null) {
- return xml.read(reader, request.isStrict());
+ return xml.read(reader, request.isStrict(), source);
} else {
- return xml.read(inputStream, request.isStrict());
+ return xml.read(inputStream, request.isStrict(), source);
}
} catch (Exception e) {
throw new XmlReaderException("Unable to read settings", e);
diff --git
a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java
b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java
index 9eddc5c8b..6f8710179 100644
---
a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java
+++
b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java
@@ -24,12 +24,12 @@ import javax.inject.Singleton;
import java.io.File;
import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import org.apache.maven.api.settings.InputSource;
import org.apache.maven.building.FileSource;
import org.apache.maven.building.Source;
import org.apache.maven.settings.Server;
@@ -39,6 +39,7 @@ import org.apache.maven.settings.io.SettingsParseException;
import org.apache.maven.settings.io.SettingsReader;
import org.apache.maven.settings.io.SettingsWriter;
import org.apache.maven.settings.merge.MavenSettingsMerger;
+import org.apache.maven.settings.v4.SettingsTransformer;
import org.apache.maven.settings.validation.SettingsValidator;
import org.codehaus.plexus.interpolation.EnvarBasedValueSource;
import org.codehaus.plexus.interpolation.InterpolationException;
@@ -158,8 +159,9 @@ public class DefaultSettingsBuilder implements
SettingsBuilder {
Settings settings;
try {
- Map<String, ?> options =
Collections.singletonMap(SettingsReader.IS_STRICT, Boolean.TRUE);
-
+ Map<String, Object> options = new HashMap<>();
+ options.put(SettingsReader.IS_STRICT, Boolean.TRUE);
+ options.put(InputSource.class.getName(), new
InputSource(settingsSource.getLocation()));
try {
settings =
settingsReader.read(settingsSource.getInputStream(), options);
} catch (SettingsParseException e) {
@@ -211,15 +213,6 @@ public class DefaultSettingsBuilder implements
SettingsBuilder {
private Settings interpolate(
Settings settings, SettingsBuildingRequest request,
SettingsProblemCollector problems) {
- StringWriter writer = new StringWriter(1024 * 4);
-
- try {
- settingsWriter.write(writer, null, settings);
- } catch (IOException e) {
- throw new IllegalStateException("Failed to serialize settings to
memory", e);
- }
-
- String serializedSettings = writer.toString();
RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
@@ -238,37 +231,19 @@ public class DefaultSettingsBuilder implements
SettingsBuilder {
e);
}
- interpolator.addPostProcessor((expression, value) -> {
- if (value != null) {
- // we're going to parse this back in as XML so we need to
escape XML markup
- value = value.toString()
- .replace("&", "&")
- .replace("<", "<")
- .replace(">", ">");
- return value;
- }
- return null;
- });
-
- try {
- serializedSettings = interpolator.interpolate(serializedSettings,
"settings");
- } catch (InterpolationException e) {
- problems.add(
- SettingsProblem.Severity.ERROR, "Failed to interpolate
settings: " + e.getMessage(), -1, -1, e);
-
- return settings;
- }
-
- Settings result;
- try {
- Map<String, ?> options =
Collections.singletonMap(SettingsReader.IS_STRICT, Boolean.FALSE);
- result = settingsReader.read(new StringReader(serializedSettings),
options);
- } catch (IOException e) {
- problems.add(
- SettingsProblem.Severity.ERROR, "Failed to interpolate
settings: " + e.getMessage(), -1, -1, e);
- return settings;
- }
-
- return result;
+ return new Settings(new SettingsTransformer(value -> {
+ try {
+ return value != null ? interpolator.interpolate(value)
: null;
+ } catch (InterpolationException e) {
+ problems.add(
+ SettingsProblem.Severity.WARNING,
+ "Failed to interpolate settings: " +
e.getMessage(),
+ -1,
+ -1,
+ e);
+ return value;
+ }
+ })
+ .visit(settings.getDelegate()));
}
}
diff --git
a/maven-settings-builder/src/main/java/org/apache/maven/settings/io/DefaultSettingsReader.java
b/maven-settings-builder/src/main/java/org/apache/maven/settings/io/DefaultSettingsReader.java
index fc96ad1a2..a30e2bbd2 100644
---
a/maven-settings-builder/src/main/java/org/apache/maven/settings/io/DefaultSettingsReader.java
+++
b/maven-settings-builder/src/main/java/org/apache/maven/settings/io/DefaultSettingsReader.java
@@ -29,8 +29,9 @@ import java.nio.file.Files;
import java.util.Map;
import java.util.Objects;
+import org.apache.maven.api.settings.InputSource;
import org.apache.maven.settings.Settings;
-import org.apache.maven.settings.v4.SettingsXpp3Reader;
+import org.apache.maven.settings.v4.SettingsXpp3ReaderEx;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
/**
@@ -47,7 +48,8 @@ public class DefaultSettingsReader implements SettingsReader {
Objects.requireNonNull(input, "input cannot be null");
try (InputStream in = Files.newInputStream(input.toPath())) {
- return new Settings(new SettingsXpp3Reader().read(in,
isStrict(options)));
+ InputSource source = new InputSource(input.toString());
+ return new Settings(new SettingsXpp3ReaderEx().read(in,
isStrict(options), source));
} catch (XmlPullParserException e) {
throw new SettingsParseException(e.getMessage(),
e.getLineNumber(), e.getColumnNumber(), e);
}
@@ -58,7 +60,8 @@ public class DefaultSettingsReader implements SettingsReader {
Objects.requireNonNull(input, "input cannot be null");
try (Reader in = input) {
- return new Settings(new SettingsXpp3Reader().read(in,
isStrict(options)));
+ InputSource source = (InputSource)
options.get(InputSource.class.getName());
+ return new Settings(new SettingsXpp3ReaderEx().read(in,
isStrict(options), source));
} catch (XmlPullParserException e) {
throw new SettingsParseException(e.getMessage(),
e.getLineNumber(), e.getColumnNumber(), e);
}
@@ -69,7 +72,8 @@ public class DefaultSettingsReader implements SettingsReader {
Objects.requireNonNull(input, "input cannot be null");
try (InputStream in = input) {
- return new Settings(new SettingsXpp3Reader().read(in,
isStrict(options)));
+ InputSource source = (InputSource)
options.get(InputSource.class.getName());
+ return new Settings(new SettingsXpp3ReaderEx().read(in,
isStrict(options), source));
} catch (XmlPullParserException e) {
throw new SettingsParseException(e.getMessage(),
e.getLineNumber(), e.getColumnNumber(), e);
}
diff --git a/maven-settings/pom.xml b/maven-settings/pom.xml
index c27963e94..a87b0c0f7 100644
--- a/maven-settings/pom.xml
+++ b/maven-settings/pom.xml
@@ -60,6 +60,11 @@ under the License.
<models>
<model>src/main/mdo/settings.mdo</model>
</models>
+ <params>
+ <param>packageModelV3=org.apache.maven.settings</param>
+ <param>packageModelV4=org.apache.maven.api.settings</param>
+ <param>packageToolV4=org.apache.maven.settings.v4</param>
+ </params>
</configuration>
<executions>
<execution>
@@ -70,18 +75,31 @@ under the License.
<phase>generate-sources</phase>
<configuration>
<templates>
- <template>model-v3.vm</template>
<template>merger.vm</template>
+ <template>transformer.vm</template>
<template>reader.vm</template>
+ <template>reader-ex.vm</template>
<template>writer.vm</template>
+ <template>writer-ex.vm</template>
</templates>
- <params>
- <param>packageModelV3=org.apache.maven.settings</param>
- <param>packageModelV4=org.apache.maven.api.settings</param>
- <param>packageToolV4=org.apache.maven.settings.v4</param>
+ <params combine.children="append">
+ <param>locationTracking=true</param>
</params>
</configuration>
</execution>
+ <execution>
+ <id>v3</id>
+ <goals>
+ <goal>velocity</goal>
+ </goals>
+ <phase>generate-sources</phase>
+ <configuration>
+ <version>1.2.0</version>
+ <templates>
+ <template>model-v3.vm</template>
+ </templates>
+ </configuration>
+ </execution>
</executions>
</plugin>
<plugin>
diff --git a/src/mdo/model-v3.vm b/src/mdo/model-v3.vm
index afa0d498a..5508c618f 100644
--- a/src/mdo/model-v3.vm
+++ b/src/mdo/model-v3.vm
@@ -183,9 +183,17 @@ public class ${class.name}
public void set${cap}(${type} ${field.name}) {
#if ($field.type == "DOM")
- if (!Objects.equals(((Xpp3Dom) ${field.name}).getDom(),
getDelegate().${pfx}${cap}())) {
- update(getDelegate().with${cap}(((Xpp3Dom)
${field.name}).getDom()));
- ((Xpp3Dom) ${field.name}).setChildrenTracking(this::replace);
+ if (${field.name} instanceof Xpp3Dom) {
+ if (!Objects.equals(((Xpp3Dom) ${field.name}).getDom(),
getDelegate().${pfx}${cap}())) {
+ update(getDelegate().with${cap}(((Xpp3Dom)
${field.name}).getDom()));
+ ((Xpp3Dom) ${field.name}).setChildrenTracking(this::replace);
+ }
+ } else if (${field.name} == null) {
+ if (getDelegate().${pfx}${cap}() != null) {
+ update(getDelegate().with${cap}(null));
+ }
+ } else {
+ throw new IllegalArgumentException("Expected an Xpp3Dom object but
received: " + ${field.name});
}
#elseif( $field.type == "java.util.Properties" )
Map<String, String> map = ${field.name}.entrySet().stream()
@@ -194,7 +202,7 @@ public class ${class.name}
update(getDelegate().with${cap}(map));
}
#else
- if (!Objects.equals(${field.name}, getDelegate().${pfx}${cap}())) {
+ if (!Objects.equals(${field.name}, ${pfx}${cap}())) {
#if ( $field.to != "String" && $field.type == "java.util.List" &&
$field.multiplicity == "*" )
update(getDelegate().with${cap}(
${field.name}.stream().map(c ->
c.getDelegate()).collect(Collectors.toList())));
diff --git a/src/mdo/reader.vm b/src/mdo/reader.vm
index b95ea6128..a1b86af1d 100644
--- a/src/mdo/reader.vm
+++ b/src/mdo/reader.vm
@@ -74,305 +74,595 @@ public class ${className} {
}
/**
- * Method checkFieldWithDuplicate.
+ * @see ReaderFactory#newXmlReader
*
- * @param parser a parser object.
- * @param parsed a parsed object.
- * @param alias a alias object.
- * @param tagName a tagName object.
+ * @param reader a reader object.
+ * @param strict a strict object.
+ * @throws IOException IOException if any.
* @throws XmlPullParserException XmlPullParserException if
* any.
- * @return boolean
+ * @return ${root.name}
*/
- private boolean checkFieldWithDuplicate(XmlPullParser parser, String
tagName, String alias, Set<String> parsed)
- throws XmlPullParserException {
- if (!(parser.getName().equals(tagName) ||
parser.getName().equals(alias))) {
- return false;
- }
- if (!parsed.add(tagName)) {
- throw new XmlPullParserException("Duplicated tag: '" + tagName +
"'", parser, null);
- }
- return true;
- } //-- boolean checkFieldWithDuplicate(XmlPullParser, String, String,
Set<String>)
+ public ${root.name} read(Reader reader, boolean strict) throws
IOException, XmlPullParserException {
+ XmlPullParser parser = addDefaultEntities ? new
MXParser(EntityReplacementMap.defaultEntityReplacementMap) : new MXParser();
+ parser.setInput(reader);
+ return read(parser, strict);
+ } //-- ${root.name} read(Reader, boolean)
/**
- * Method checkUnknownAttribute.
+ * @see ReaderFactory#newXmlReader
*
- * @param parser a parser object.
- * @param strict a strict object.
- * @param tagName a tagName object.
- * @param attribute a attribute object.
+ * @param reader a reader object.
+ * @throws IOException IOException if any.
* @throws XmlPullParserException XmlPullParserException if
* any.
- * @throws IOException IOException if any.
+ * @return ${root.name}
*/
- private void checkUnknownAttribute(XmlPullParser parser, String attribute,
String tagName, boolean strict)
- throws XmlPullParserException, IOException {
- // strictXmlAttributes = true for model: if strict == true, not only
elements are checked but attributes too
- if (strict) {
- throw new XmlPullParserException("Unknown attribute '" + attribute
+ "' for tag '" + tagName + "'", parser, null);
- }
- } //-- void checkUnknownAttribute(XmlPullParser, String, String, boolean)
+ public ${root.name} read(Reader reader) throws IOException,
XmlPullParserException {
+ return read(reader, true);
+ } //-- ${root.name} read(Reader)
/**
- * Method checkUnknownElement.
+ * Method read.
*
- * @param parser a parser object.
+ * @param in a in object.
* @param strict a strict object.
- * @throws XmlPullParserException XmlPullParserException if
- * any.
* @throws IOException IOException if any.
- */
- private void checkUnknownElement(XmlPullParser parser, boolean strict)
- throws XmlPullParserException, IOException {
- if (strict) {
- throw new XmlPullParserException("Unrecognised tag: '" +
parser.getName() + "'", parser, null);
- }
-
- for (int unrecognizedTagCount = 1; unrecognizedTagCount > 0;) {
- int eventType = parser.next();
- if (eventType == XmlPullParser.START_TAG) {
- unrecognizedTagCount++;
- } else if (eventType == XmlPullParser.END_TAG) {
- unrecognizedTagCount--;
- }
- }
- } //-- void checkUnknownElement(XmlPullParser, boolean)
-
- /**
- * Returns the state of the "add default entities" flag.
- *
- * @return boolean
- */
- public boolean getAddDefaultEntities() {
- return addDefaultEntities;
- } //-- boolean getAddDefaultEntities()
-
- /**
- * Method getBooleanValue.
- *
- * @param s a s object.
- * @param parser a parser object.
- * @param attribute a attribute object.
* @throws XmlPullParserException XmlPullParserException if
* any.
- * @return boolean
+ * @return ${root.name}
*/
- private boolean getBooleanValue(String s, String attribute, XmlPullParser
parser)
- throws XmlPullParserException {
- return getBooleanValue(s, attribute, parser, false);
- } //-- boolean getBooleanValue(String, String, XmlPullParser)
+ public ${root.name} read(InputStream in, boolean strict) throws
IOException, XmlPullParserException {
+ return read(ReaderFactory.newXmlReader(in), strict);
+ } //-- ${root.name} read(InputStream, boolean)
/**
- * Method getBooleanValue.
+ * Method read.
*
- * @param s a s object.
- * @param defaultValue a defaultValue object.
- * @param parser a parser object.
- * @param attribute a attribute object.
+ * @param in a in object.
+ * @throws IOException IOException if any.
* @throws XmlPullParserException XmlPullParserException if
* any.
- * @return boolean
+ * @return ${root.name}
*/
- private boolean getBooleanValue(String s, String attribute, XmlPullParser
parser, boolean defaultValue)
- throws XmlPullParserException {
- if (s != null && s.length() != 0) {
- return Boolean.valueOf(s).booleanValue();
- }
- return defaultValue;
- } //-- boolean getBooleanValue(String, String, XmlPullParser, String)
+ public ${root.name} read(InputStream in) throws IOException,
XmlPullParserException {
+ return read(ReaderFactory.newXmlReader(in));
+ } //-- ${root.name} read(InputStream)
/**
- * Method getByteValue.
+ * Method read.
*
- * @param s a s object.
- * @param strict a strict object.
* @param parser a parser object.
- * @param attribute a attribute object.
+ * @param strict a strict object.
+ * @throws IOException IOException if any.
* @throws XmlPullParserException XmlPullParserException if
* any.
- * @return byte
+ * @return ${root.name}
*/
- private byte getByteValue(String s, String attribute, XmlPullParser
parser, boolean strict)
- throws XmlPullParserException {
- if (s != null) {
- try {
- return Byte.valueOf(s).byteValue();
- } catch (NumberFormatException nfe) {
- if (strict) {
- throw new XmlPullParserException("Unable to parse element
'" + attribute + "', must be a byte", parser, nfe);
+ public ${root.name} read(XmlPullParser parser, boolean strict) throws
IOException, XmlPullParserException {
+ $rootUcapName $rootLcapName = null;
+ int eventType = parser.getEventType();
+ boolean parsed = false;
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_TAG) {
+ if (strict && ! "${rootTag}".equals(parser.getName())) {
+ throw new XmlPullParserException("Expected root element
'${rootTag}' but found '" + parser.getName() + "'", parser, null);
+ } else if (parsed) {
+ // fallback, already expected a XmlPullParserException due
to invalid XML
+ throw new XmlPullParserException("Duplicated tag:
'${rootTag}'", parser, null);
}
+ $rootLcapName = parse${rootUcapName}(parser, strict);
+ parsed = true;
}
+ eventType = parser.next();
}
- return 0;
- } //-- byte getByteValue(String, String, XmlPullParser, boolean)
-
- /**
- * Method getCharacterValue.
- *
- * @param s a s object.
- * @param parser a parser object.
- * @param attribute a attribute object.
- * @throws XmlPullParserException XmlPullParserException if
- * any.
- * @return char
- */
- private char getCharacterValue(String s, String attribute, XmlPullParser
parser)
- throws XmlPullParserException {
- if (s != null) {
- return s.charAt(0);
+ if (parsed) {
+ return $rootLcapName;
}
- return 0;
- } //-- char getCharacterValue(String, String, XmlPullParser)
-
- /**
- * Method getDateValue.
- *
- * @param s a s object.
- * @param parser a parser object.
- * @param attribute a attribute object.
- * @throws XmlPullParserException XmlPullParserException if
- * any.
- * @return Date
- */
- private Date getDateValue(String s, String attribute, XmlPullParser parser)
- throws XmlPullParserException {
- return getDateValue(s, attribute, null, parser);
- } //-- Date getDateValue(String, String, XmlPullParser)
+ throw new XmlPullParserException("Expected root element '${rootTag}'
but found no element at all: invalid XML document", parser, null);
+ } //-- ${root.name} read(XmlPullParser, boolean)
- /**
- * Method getDateValue.
- *
- * @param s a s object.
- * @param parser a parser object.
- * @param dateFormat a dateFormat object.
- * @param attribute a attribute object.
- * @throws XmlPullParserException XmlPullParserException if
- * any.
- * @return Date
- */
- private Date getDateValue(String s, String attribute, String dateFormat,
XmlPullParser parser)
- throws XmlPullParserException {
- if (s != null) {
- String effectiveDateFormat = dateFormat;
- if (dateFormat == null) {
- effectiveDateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS";
+#foreach ( $class in $model.allClasses )
+ #if ( $class.name != "InputSource" && $class.name != "InputLocation" )
+ #set ( $classUcapName = $Helper.capitalise( $class.name ) )
+ #set ( $classLcapName = $Helper.uncapitalise( $class.name ) )
+ #set ( $ancestors = $Helper.ancestors( $class ) )
+ #set ( $allFields = [] )
+ #foreach ( $cl in $ancestors )
+ #set ( $dummy = $allFields.addAll( $cl.getFields($version) ) )
+ #end
+ private ${classUcapName} parse${classUcapName}(XmlPullParser parser,
boolean strict)
+ throws IOException, XmlPullParserException {
+ String tagName = parser.getName();
+ ${classUcapName}.Builder ${classLcapName} =
${classUcapName}.newBuilder(true);
+ for (int i = parser.getAttributeCount() - 1; i >= 0; i--) {
+ String name = parser.getAttributeName(i);
+ String value = parser.getAttributeValue(i);
+ if (name.indexOf(':') >= 0) {
+ // just ignore attributes with non-default namespace (for
example: xmlns:xsi)
+ #if ( $class == $root )
+ } else if ("xmlns".equals(name)) {
+ // ignore xmlns attribute in root class, which is a reserved
attribute name
+ #end
}
- if ("long".equals(effectiveDateFormat)) {
- try {
- return new java.util.Date(Long.parseLong(s));
- } catch (NumberFormatException e) {
- throw new XmlPullParserException(e.getMessage(), parser,
e);
- }
- } else {
- try {
- DateFormat dateParser = new
java.text.SimpleDateFormat(effectiveDateFormat, java.util.Locale.US);
- return dateParser.parse(s);
- } catch (java.text.ParseException e) {
- throw new XmlPullParserException(e.getMessage(), parser,
e);
- }
+ #foreach ( $field in $allFields )
+ #if ( $Helper.xmlFieldMetadata( $field ).attribute )
+ #set ( $fieldTagName = $Helper.xmlFieldMetadata( $field ).tagName )
+ #set ( $fieldCapName = $Helper.capitalise( $field.name ) )
+ else if ("$fieldTagName".equals(name)) {
+ #if ( $field.type == "String" )
+ ${classLcapName}.${field.name}(interpolatedTrimmed(value,
"$fieldTagName"));
+ #elseif ( $field.type == "boolean" || $field.type == "Boolean" )
+
${classLcapName}.${field.name}(getBooleanValue(interpolatedTrimmed(value,
"$fieldTagName"), "$fieldTagName", parser, ${field.defaultValue}));
+ #else
+ // TODO: type=${field.type} to=${field.to}
multiplicity=${field.multiplicity}
+ #end
+ }
+ #end
+ #end
+ else {
+ checkUnknownAttribute(parser, name, tagName, strict);
}
}
- return null;
- } //-- Date getDateValue(String, String, String, XmlPullParser)
-
- /**
- * Method getDoubleValue.
- *
- * @param s a s object.
- * @param strict a strict object.
- * @param parser a parser object.
- * @param attribute a attribute object.
- * @throws XmlPullParserException XmlPullParserException if
- * any.
- * @return double
- */
- private double getDoubleValue(String s, String attribute, XmlPullParser
parser, boolean strict)
- throws XmlPullParserException {
- if (s != null) {
- try {
- return Double.valueOf(s).doubleValue();
- } catch (NumberFormatException nfe) {
- if (strict) {
- throw new XmlPullParserException("Unable to parse element
'" + attribute + "', must be a floating point number", parser, nfe);
+ Set<String> parsed = new HashSet<>();
+ #foreach ( $field in $allFields )
+ #if ( $Helper.isFlatItems( $field ) )
+ List<$field.to> ${field.name} = new ArrayList<>();
+ #end
+ #end
+ while ((strict ? parser.nextTag() : nextTag(parser)) ==
XmlPullParser.START_TAG) {
+ String childName = checkDuplicate(parser.getName(), parser,
parsed);
+ switch (childName) {
+ #set( $ift = "if" )
+ #foreach ( $field in $allFields )
+ #if ( ! $Helper.xmlFieldMetadata( $field ).attribute && !
$Helper.xmlFieldMetadata( $field ).transient )
+ #set ( $fieldTagName = $Helper.xmlFieldMetadata( $field ).tagName )
+ #if ( ! $fieldTagName )
+ #set ( $fieldTagName = $field.name )
+ #end
+ #if ( $Helper.isFlatItems( $field ) )
+ #set ( $fieldTagName = $Helper.singular( $fieldTagName ) )
+ #end
+ #set ( $fieldCapName = $Helper.capitalise( $field.name ) )
+ case "${fieldTagName}": {
+ #if ( $field.type == "String" )
+
${classLcapName}.${field.name}(interpolatedTrimmed(parser.nextText(),
"${fieldTagName}"));
+ break;
+ #elseif ( $field.type == "boolean" || $field.type == "Boolean" )
+
${classLcapName}.${field.name}(getBooleanValue(interpolatedTrimmed(parser.nextText(),
"${fieldTagName}"), "${fieldTagName}", parser, ${field.defaultValue}));
+ break;
+ #elseif ( $field.type == "int" )
+
${classLcapName}.${field.name}(getIntegerValue(interpolatedTrimmed(parser.nextText(),
"${fieldTagName}"), "${fieldTagName}", parser, strict, ${field.defaultValue}));
+ break;
+ #elseif ( $field.type == "DOM" )
+
${classLcapName}.${field.name}(XmlNodeBuilder.build(parser, true));
+ break;
+ #elseif ( $field.type == "java.util.List" && $field.to == "String" &&
$field.multiplicity == "*" )
+ List<String> ${field.name} = new ArrayList<>();
+ while (parser.nextTag() == XmlPullParser.START_TAG) {
+ if
("${Helper.singular($fieldTagName)}".equals(parser.getName())) {
+
${field.name}.add(interpolatedTrimmed(parser.nextText(), "${fieldTagName}"));
+ } else {
+ checkUnknownElement(parser, strict);
+ }
+ }
+ ${classLcapName}.${field.name}(${field.name});
+ break;
+ #elseif ( $field.type == "java.util.Properties" && $field.to == "String"
&& $field.multiplicity == "*" )
+ Map<String, String> ${field.name} = new LinkedHashMap<>();
+ while (parser.nextTag() == XmlPullParser.START_TAG) {
+ String key = parser.getName();
+ String value = parser.nextText().trim();
+ ${field.name}.put(key, value);
+ }
+ ${classLcapName}.${field.name}(${field.name});
+ break;
+ #elseif ( $field.to && $field.multiplicity == "1" )
+
${classLcapName}.${field.name}(parse${field.toClass.name}(parser, strict));
+ break;
+ #elseif ( $field.to && $field.multiplicity == "*" &&
$Helper.isFlatItems( $field ) )
+ ${field.name}.add(parse${field.toClass.name}(parser,
strict));
+ break;
+ #elseif ( $field.to && $field.multiplicity == "*" )
+ List<$field.to> ${field.name} = new ArrayList<>();
+ while (parser.nextTag() == XmlPullParser.START_TAG) {
+ if
("${Helper.singular($fieldTagName)}".equals(parser.getName())) {
+
${field.name}.add(parse${field.toClass.name}(parser, strict));
+ } else {
+ checkUnknownElement(parser, strict);
+ }
+ }
+ ${classLcapName}.${field.name}(${field.name});
+ break;
+ #else
+ // TODO: type=${field.type} to=${field.to}
multiplicity=${field.multiplicity}
+ break;
+ #end
+ }
+ #set( $ift = "else if" )
+ #end
+ #end
+ default: {
+ checkUnknownElement(parser, strict);
+ break;
}
}
}
- return 0;
- } //-- double getDoubleValue(String, String, XmlPullParser, boolean)
+ #foreach ( $field in $allFields )
+ #if ( $Helper.isFlatItems( $field ) )
+ ${classLcapName}.${field.name}(${field.name});
+ #end
+ #end
+ #if ( $class == $root )
+ ${classLcapName}.modelEncoding(parser.getInputEncoding());
+ #end
+ return ${classLcapName}.build();
+ }
+
+ #end
+#end
+
+ private String checkDuplicate(String tagName, XmlPullParser parser,
Set<String> parsed) throws XmlPullParserException {
+#set( $aliases = { } )
+#set( $flats = { } )
+#foreach( $class in $model.allClasses )
+ #foreach ( $field in $class.getFields($version) )
+ #set ( $fieldTagName = $Helper.xmlFieldMetadata( $field ).tagName )
+ #if ( ! $fieldTagName )
+ #set ( $fieldTagName = $field.name )
+ #end
+ #if ( $field.alias )
+ #set ( $dummy = $aliases.put( $field.alias, $fieldTagName ) )
+ #end
+ #if ( $Helper.isFlatItems( $field ) )
+ #set ( $fieldTagName = $Helper.singular($fieldTagName) )
+ #set ( $dummy = $flats.put( $fieldTagName, "" ) )
+ #end
+ #end
+#end
+#if ( ! ${aliases.isEmpty()} )
+ switch (tagName) {
+ #foreach( $entry in $aliases.entrySet() )
+ case "${entry.key}":
+ tagName = "${entry.value}";
+ #end
+ }
+#end
+#if ( ! ${flats.isEmpty()} )
+ switch (tagName) {
+ #foreach( $entry in $flats.entrySet() )
+ case "${entry.key}":
+ #end
+ break;
+ default:
+ if (!parsed.add(tagName)) {
+ throw new XmlPullParserException("Duplicated tag: '" +
tagName + "'", parser, null);
+ }
+ }
+#end
+ return tagName;
+ }
/**
- * Method getFloatValue.
+ * Sets the state of the "add default entities" flag.
+ *
+ * @param addDefaultEntities a addDefaultEntities object.
+ */
+ public void setAddDefaultEntities(boolean addDefaultEntities) {
+ this.addDefaultEntities = addDefaultEntities;
+ } //-- void setAddDefaultEntities(boolean)
+
+ public static interface ContentTransformer {
+ /**
+ * Interpolate the value read from the xpp3 document
+ * @param source The source value
+ * @param fieldName A description of the field being interpolated. The
implementation may use this to
+ * log stuff.
+ * @return The interpolated value.
+ */
+ String transform(String source, String fieldName);
+ }
+
+ /**
+ * Method checkFieldWithDuplicate.
*
- * @param s a s object.
- * @param strict a strict object.
* @param parser a parser object.
- * @param attribute a attribute object.
+ * @param parsed a parsed object.
+ * @param alias a alias object.
+ * @param tagName a tagName object.
* @throws XmlPullParserException XmlPullParserException if
* any.
- * @return float
+ * @return boolean
*/
- private float getFloatValue(String s, String attribute, XmlPullParser
parser, boolean strict)
- throws XmlPullParserException {
- if (s != null) {
- try {
- return Float.valueOf(s).floatValue();
- } catch (NumberFormatException nfe) {
- if (strict) {
- throw new XmlPullParserException("Unable to parse element
'" + attribute + "', must be a floating point number", parser, nfe);
- }
- }
+ private boolean checkFieldWithDuplicate(XmlPullParser parser, String
tagName, String alias, Set<String> parsed)
+ throws XmlPullParserException {
+ if (!(parser.getName().equals(tagName) ||
parser.getName().equals(alias))) {
+ return false;
}
- return 0;
- } //-- float getFloatValue(String, String, XmlPullParser, boolean)
+ if (!parsed.add(tagName)) {
+ throw new XmlPullParserException("Duplicated tag: '" + tagName +
"'", parser, null);
+ }
+ return true;
+ } //-- boolean checkFieldWithDuplicate(XmlPullParser, String, String,
Set<String>)
/**
- * Method getIntegerValue.
+ * Method checkUnknownAttribute.
*
- * @param s a s object.
* @param parser a parser object.
+ * @param strict a strict object.
+ * @param tagName a tagName object.
* @param attribute a attribute object.
* @throws XmlPullParserException XmlPullParserException if
* any.
- * @return int
+ * @throws IOException IOException if any.
*/
- private int getIntegerValue(String s, String attribute, XmlPullParser
parser, boolean strict)
- throws XmlPullParserException {
- return getIntegerValue(s, attribute, parser, strict, 0);
- } //-- int getBooleanValue(String, String, XmlPullParser)
+ private void checkUnknownAttribute(XmlPullParser parser, String attribute,
String tagName, boolean strict)
+ throws XmlPullParserException, IOException {
+ // strictXmlAttributes = true for model: if strict == true, not only
elements are checked but attributes too
+ if (strict) {
+ throw new XmlPullParserException("Unknown attribute '" + attribute
+ "' for tag '" + tagName + "'", parser, null);
+ }
+ } //-- void checkUnknownAttribute(XmlPullParser, String, String, boolean)
/**
- * Method getIntegerValue.
+ * Method checkUnknownElement.
*
- * @param s a s object.
- * @param strict a strict object.
* @param parser a parser object.
- * @param attribute a attribute object.
+ * @param strict a strict object.
* @throws XmlPullParserException XmlPullParserException if
* any.
- * @return int
+ * @throws IOException IOException if any.
*/
- private int getIntegerValue(String s, String attribute, XmlPullParser
parser, boolean strict, int defaultValue)
- throws XmlPullParserException {
- if (s != null) {
- try {
- return Integer.valueOf(s).intValue();
- } catch (NumberFormatException nfe) {
- if (strict) {
- throw new XmlPullParserException("Unable to parse element
'" + attribute + "', must be an integer", parser, nfe);
- }
+ private void checkUnknownElement(XmlPullParser parser, boolean strict)
+ throws XmlPullParserException, IOException {
+ if (strict) {
+ throw new XmlPullParserException("Unrecognised tag: '" +
parser.getName() + "'", parser, null);
+ }
+
+ for (int unrecognizedTagCount = 1; unrecognizedTagCount > 0;) {
+ int eventType = parser.next();
+ if (eventType == XmlPullParser.START_TAG) {
+ unrecognizedTagCount++;
+ } else if (eventType == XmlPullParser.END_TAG) {
+ unrecognizedTagCount--;
}
}
- return defaultValue;
- } //-- int getIntegerValue(String, String, XmlPullParser, boolean, int)
+ } //-- void checkUnknownElement(XmlPullParser, boolean)
/**
- * Method getLongValue.
+ * Returns the state of the "add default entities" flag.
*
- * @param s a s object.
- * @param strict a strict object.
- * @param parser a parser object.
- * @param attribute a attribute object.
+ * @return boolean
+ */
+ public boolean getAddDefaultEntities() {
+ return addDefaultEntities;
+ } //-- boolean getAddDefaultEntities()
+
+ /**
+ * Method getBooleanValue.
+ *
+ * @param s a s object.
+ * @param parser a parser object.
+ * @param attribute a attribute object.
+ * @throws XmlPullParserException XmlPullParserException if
+ * any.
+ * @return boolean
+ */
+ private boolean getBooleanValue(String s, String attribute, XmlPullParser
parser)
+ throws XmlPullParserException {
+ return getBooleanValue(s, attribute, parser, false);
+ } //-- boolean getBooleanValue(String, String, XmlPullParser)
+
+ /**
+ * Method getBooleanValue.
+ *
+ * @param s a s object.
+ * @param defaultValue a defaultValue object.
+ * @param parser a parser object.
+ * @param attribute a attribute object.
+ * @throws XmlPullParserException XmlPullParserException if
+ * any.
+ * @return boolean
+ */
+ private boolean getBooleanValue(String s, String attribute, XmlPullParser
parser, boolean defaultValue)
+ throws XmlPullParserException {
+ if (s != null && s.length() != 0) {
+ return Boolean.valueOf(s).booleanValue();
+ }
+ return defaultValue;
+ } //-- boolean getBooleanValue(String, String, XmlPullParser, String)
+
+ /**
+ * Method getByteValue.
+ *
+ * @param s a s object.
+ * @param strict a strict object.
+ * @param parser a parser object.
+ * @param attribute a attribute object.
+ * @throws XmlPullParserException XmlPullParserException if
+ * any.
+ * @return byte
+ */
+ private byte getByteValue(String s, String attribute, XmlPullParser
parser, boolean strict)
+ throws XmlPullParserException {
+ if (s != null) {
+ try {
+ return Byte.valueOf(s).byteValue();
+ } catch (NumberFormatException nfe) {
+ if (strict) {
+ throw new XmlPullParserException("Unable to parse element
'" + attribute + "', must be a byte", parser, nfe);
+ }
+ }
+ }
+ return 0;
+ } //-- byte getByteValue(String, String, XmlPullParser, boolean)
+
+ /**
+ * Method getCharacterValue.
+ *
+ * @param s a s object.
+ * @param parser a parser object.
+ * @param attribute a attribute object.
+ * @throws XmlPullParserException XmlPullParserException if
+ * any.
+ * @return char
+ */
+ private char getCharacterValue(String s, String attribute, XmlPullParser
parser)
+ throws XmlPullParserException {
+ if (s != null) {
+ return s.charAt(0);
+ }
+ return 0;
+ } //-- char getCharacterValue(String, String, XmlPullParser)
+
+ /**
+ * Method getDateValue.
+ *
+ * @param s a s object.
+ * @param parser a parser object.
+ * @param attribute a attribute object.
+ * @throws XmlPullParserException XmlPullParserException if
+ * any.
+ * @return Date
+ */
+ private Date getDateValue(String s, String attribute, XmlPullParser parser)
+ throws XmlPullParserException {
+ return getDateValue(s, attribute, null, parser);
+ } //-- Date getDateValue(String, String, XmlPullParser)
+
+ /**
+ * Method getDateValue.
+ *
+ * @param s a s object.
+ * @param parser a parser object.
+ * @param dateFormat a dateFormat object.
+ * @param attribute a attribute object.
+ * @throws XmlPullParserException XmlPullParserException if
+ * any.
+ * @return Date
+ */
+ private Date getDateValue(String s, String attribute, String dateFormat,
XmlPullParser parser)
+ throws XmlPullParserException {
+ if (s != null) {
+ String effectiveDateFormat = dateFormat;
+ if (dateFormat == null) {
+ effectiveDateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS";
+ }
+ if ("long".equals(effectiveDateFormat)) {
+ try {
+ return new java.util.Date(Long.parseLong(s));
+ } catch (NumberFormatException e) {
+ throw new XmlPullParserException(e.getMessage(), parser,
e);
+ }
+ } else {
+ try {
+ DateFormat dateParser = new
java.text.SimpleDateFormat(effectiveDateFormat, java.util.Locale.US);
+ return dateParser.parse(s);
+ } catch (java.text.ParseException e) {
+ throw new XmlPullParserException(e.getMessage(), parser,
e);
+ }
+ }
+ }
+ return null;
+ } //-- Date getDateValue(String, String, String, XmlPullParser)
+
+ /**
+ * Method getDoubleValue.
+ *
+ * @param s a s object.
+ * @param strict a strict object.
+ * @param parser a parser object.
+ * @param attribute a attribute object.
+ * @throws XmlPullParserException XmlPullParserException if
+ * any.
+ * @return double
+ */
+ private double getDoubleValue(String s, String attribute, XmlPullParser
parser, boolean strict)
+ throws XmlPullParserException {
+ if (s != null) {
+ try {
+ return Double.valueOf(s).doubleValue();
+ } catch (NumberFormatException nfe) {
+ if (strict) {
+ throw new XmlPullParserException("Unable to parse element
'" + attribute + "', must be a floating point number", parser, nfe);
+ }
+ }
+ }
+ return 0;
+ } //-- double getDoubleValue(String, String, XmlPullParser, boolean)
+
+ /**
+ * Method getFloatValue.
+ *
+ * @param s a s object.
+ * @param strict a strict object.
+ * @param parser a parser object.
+ * @param attribute a attribute object.
+ * @throws XmlPullParserException XmlPullParserException if
+ * any.
+ * @return float
+ */
+ private float getFloatValue(String s, String attribute, XmlPullParser
parser, boolean strict)
+ throws XmlPullParserException {
+ if (s != null) {
+ try {
+ return Float.valueOf(s).floatValue();
+ } catch (NumberFormatException nfe) {
+ if (strict) {
+ throw new XmlPullParserException("Unable to parse element
'" + attribute + "', must be a floating point number", parser, nfe);
+ }
+ }
+ }
+ return 0;
+ } //-- float getFloatValue(String, String, XmlPullParser, boolean)
+
+ /**
+ * Method getIntegerValue.
+ *
+ * @param s a s object.
+ * @param parser a parser object.
+ * @param attribute a attribute object.
+ * @throws XmlPullParserException XmlPullParserException if
+ * any.
+ * @return int
+ */
+ private int getIntegerValue(String s, String attribute, XmlPullParser
parser, boolean strict)
+ throws XmlPullParserException {
+ return getIntegerValue(s, attribute, parser, strict, 0);
+ } //-- int getBooleanValue(String, String, XmlPullParser)
+
+ /**
+ * Method getIntegerValue.
+ *
+ * @param s a s object.
+ * @param strict a strict object.
+ * @param parser a parser object.
+ * @param attribute a attribute object.
+ * @throws XmlPullParserException XmlPullParserException if
+ * any.
+ * @return int
+ */
+ private int getIntegerValue(String s, String attribute, XmlPullParser
parser, boolean strict, int defaultValue)
+ throws XmlPullParserException {
+ if (s != null) {
+ try {
+ return Integer.valueOf(s).intValue();
+ } catch (NumberFormatException nfe) {
+ if (strict) {
+ throw new XmlPullParserException("Unable to parse element
'" + attribute + "', must be an integer", parser, nfe);
+ }
+ }
+ }
+ return defaultValue;
+ } //-- int getIntegerValue(String, String, XmlPullParser, boolean, int)
+
+ /**
+ * Method getLongValue.
+ *
+ * @param s a s object.
+ * @param strict a strict object.
+ * @param parser a parser object.
+ * @param attribute a attribute object.
* @throws XmlPullParserException XmlPullParserException if
* any.
* @return long
@@ -481,294 +771,4 @@ public class ${className} {
return eventType;
} //-- int nextTag(XmlPullParser)
- /**
- * @see ReaderFactory#newXmlReader
- *
- * @param reader a reader object.
- * @param strict a strict object.
- * @throws IOException IOException if any.
- * @throws XmlPullParserException XmlPullParserException if
- * any.
- * @return ${root.name}
- */
- public ${root.name} read(Reader reader, boolean strict) throws
IOException, XmlPullParserException {
- XmlPullParser parser = addDefaultEntities ? new
MXParser(EntityReplacementMap.defaultEntityReplacementMap) : new MXParser();
- parser.setInput(reader);
- return read(parser, strict);
- } //-- ${root.name} read(Reader, boolean)
-
- /**
- * @see ReaderFactory#newXmlReader
- *
- * @param reader a reader object.
- * @throws IOException IOException if any.
- * @throws XmlPullParserException XmlPullParserException if
- * any.
- * @return ${root.name}
- */
- public ${root.name} read(Reader reader) throws IOException,
XmlPullParserException {
- return read(reader, true);
- } //-- ${root.name} read(Reader)
-
- /**
- * Method read.
- *
- * @param in a in object.
- * @param strict a strict object.
- * @throws IOException IOException if any.
- * @throws XmlPullParserException XmlPullParserException if
- * any.
- * @return ${root.name}
- */
- public ${root.name} read(InputStream in, boolean strict) throws
IOException, XmlPullParserException {
- return read(ReaderFactory.newXmlReader(in), strict);
- } //-- ${root.name} read(InputStream, boolean)
-
- /**
- * Method read.
- *
- * @param in a in object.
- * @throws IOException IOException if any.
- * @throws XmlPullParserException XmlPullParserException if
- * any.
- * @return ${root.name}
- */
- public ${root.name} read(InputStream in) throws IOException,
XmlPullParserException {
- return read(ReaderFactory.newXmlReader(in));
- } //-- ${root.name} read(InputStream)
-
- /**
- * Method read.
- *
- * @param parser a parser object.
- * @param strict a strict object.
- * @throws IOException IOException if any.
- * @throws XmlPullParserException XmlPullParserException if
- * any.
- * @return ${root.name}
- */
- public ${root.name} read(XmlPullParser parser, boolean strict) throws
IOException, XmlPullParserException {
- $rootUcapName $rootLcapName = null;
- int eventType = parser.getEventType();
- boolean parsed = false;
- while (eventType != XmlPullParser.END_DOCUMENT) {
- if (eventType == XmlPullParser.START_TAG) {
- if (strict && ! "${rootTag}".equals(parser.getName())) {
- throw new XmlPullParserException("Expected root element
'${rootTag}' but found '" + parser.getName() + "'", parser, null);
- } else if (parsed) {
- // fallback, already expected a XmlPullParserException due
to invalid XML
- throw new XmlPullParserException("Duplicated tag:
'${rootTag}'", parser, null);
- }
- $rootLcapName = parse${rootUcapName}(parser, strict);
- parsed = true;
- }
- eventType = parser.next();
- }
- if (parsed) {
- return $rootLcapName;
- }
- throw new XmlPullParserException("Expected root element '${rootTag}'
but found no element at all: invalid XML document", parser, null);
- } //-- ${root.name} read(XmlPullParser, boolean)
-
-#foreach ( $class in $model.allClasses )
- #if ( $class.name != "InputSource" && $class.name != "InputLocation" )
- #set ( $classUcapName = $Helper.capitalise( $class.name ) )
- #set ( $classLcapName = $Helper.uncapitalise( $class.name ) )
- #set ( $ancestors = $Helper.ancestors( $class ) )
- #set ( $allFields = [] )
- #foreach ( $cl in $ancestors )
- #set ( $dummy = $allFields.addAll( $cl.getFields($version) ) )
- #end
- private ${classUcapName} parse${classUcapName}(XmlPullParser parser,
boolean strict)
- throws IOException, XmlPullParserException {
- String tagName = parser.getName();
- ${classUcapName}.Builder ${classLcapName} =
${classUcapName}.newBuilder(true);
- for (int i = parser.getAttributeCount() - 1; i >= 0; i--) {
- String name = parser.getAttributeName(i);
- String value = parser.getAttributeValue(i);
- if (name.indexOf(':') >= 0) {
- // just ignore attributes with non-default namespace (for
example: xmlns:xsi)
- #if ( $class == $root )
- } else if ("xmlns".equals(name)) {
- // ignore xmlns attribute in root class, which is a reserved
attribute name
- #end
- }
- #foreach ( $field in $allFields )
- #if ( $Helper.xmlFieldMetadata( $field ).attribute )
- #set ( $fieldTagName = $Helper.xmlFieldMetadata( $field ).tagName )
- #set ( $fieldCapName = $Helper.capitalise( $field.name ) )
- else if ("$fieldTagName".equals(name)) {
- #if ( $field.type == "String" )
- ${classLcapName}.${field.name}(interpolatedTrimmed(value,
"$fieldTagName"));
- #elseif ( $field.type == "boolean" || $field.type == "Boolean" )
-
${classLcapName}.${field.name}(getBooleanValue(interpolatedTrimmed(value,
"$fieldTagName"), "$fieldTagName", parser, ${field.defaultValue}));
- #else
- // TODO: type=${field.type} to=${field.to}
multiplicity=${field.multiplicity}
- #end
- }
- #end
- #end
- else {
- checkUnknownAttribute(parser, name, tagName, strict);
- }
- }
- Set<String> parsed = new HashSet<>();
- #foreach ( $field in $allFields )
- #if ( $Helper.isFlatItems( $field ) )
- List<$field.to> ${field.name} = new ArrayList<>();
- #end
- #end
- while ((strict ? parser.nextTag() : nextTag(parser)) ==
XmlPullParser.START_TAG) {
- String childName = checkDuplicate(parser.getName(), parser,
parsed);
- switch (childName) {
- #set( $ift = "if" )
- #foreach ( $field in $allFields )
- #if ( ! $Helper.xmlFieldMetadata( $field ).attribute && !
$Helper.xmlFieldMetadata( $field ).transient )
- #set ( $fieldTagName = $Helper.xmlFieldMetadata( $field ).tagName )
- #if ( ! $fieldTagName )
- #set ( $fieldTagName = $field.name )
- #end
- #if ( $Helper.isFlatItems( $field ) )
- #set ( $fieldTagName = $Helper.singular( $fieldTagName ) )
- #end
- #set ( $fieldCapName = $Helper.capitalise( $field.name ) )
- case "${fieldTagName}": {
- #if ( $field.type == "String" )
-
${classLcapName}.${field.name}(interpolatedTrimmed(parser.nextText(),
"${fieldTagName}"));
- break;
- #elseif ( $field.type == "boolean" || $field.type == "Boolean" )
-
${classLcapName}.${field.name}(getBooleanValue(interpolatedTrimmed(parser.nextText(),
"${fieldTagName}"), "${fieldTagName}", parser, ${field.defaultValue}));
- break;
- #elseif ( $field.type == "int" )
-
${classLcapName}.${field.name}(getIntegerValue(interpolatedTrimmed(parser.nextText(),
"${fieldTagName}"), "${fieldTagName}", parser, strict, ${field.defaultValue}));
- break;
- #elseif ( $field.type == "DOM" )
-
${classLcapName}.${field.name}(XmlNodeBuilder.build(parser, true));
- break;
- #elseif ( $field.type == "java.util.List" && $field.to == "String" &&
$field.multiplicity == "*" )
- List<String> ${field.name} = new ArrayList<>();
- while (parser.nextTag() == XmlPullParser.START_TAG) {
- if
("${Helper.singular($fieldTagName)}".equals(parser.getName())) {
-
${field.name}.add(interpolatedTrimmed(parser.nextText(), "${fieldTagName}"));
- } else {
- checkUnknownElement(parser, strict);
- }
- }
- ${classLcapName}.${field.name}(${field.name});
- break;
- #elseif ( $field.type == "java.util.Properties" && $field.to == "String"
&& $field.multiplicity == "*" )
- Map<String, String> ${field.name} = new LinkedHashMap<>();
- while (parser.nextTag() == XmlPullParser.START_TAG) {
- String key = parser.getName();
- String value = parser.nextText().trim();
- ${field.name}.put(key, value);
- }
- ${classLcapName}.${field.name}(${field.name});
- break;
- #elseif ( $field.to && $field.multiplicity == "1" )
-
${classLcapName}.${field.name}(parse${field.toClass.name}(parser, strict));
- break;
- #elseif ( $field.to && $field.multiplicity == "*" &&
$Helper.isFlatItems( $field ) )
- ${field.name}.add(parse${field.toClass.name}(parser,
strict));
- break;
- #elseif ( $field.to && $field.multiplicity == "*" )
- List<$field.to> ${field.name} = new ArrayList<>();
- while (parser.nextTag() == XmlPullParser.START_TAG) {
- if
("${Helper.singular($fieldTagName)}".equals(parser.getName())) {
-
${field.name}.add(parse${field.toClass.name}(parser, strict));
- } else {
- checkUnknownElement(parser, strict);
- }
- }
- ${classLcapName}.${field.name}(${field.name});
- break;
- #else
- // TODO: type=${field.type} to=${field.to}
multiplicity=${field.multiplicity}
- break;
- #end
- }
- #set( $ift = "else if" )
- #end
- #end
- default: {
- checkUnknownElement(parser, strict);
- break;
- }
- }
- }
- #foreach ( $field in $allFields )
- #if ( $Helper.isFlatItems( $field ) )
- ${classLcapName}.${field.name}(${field.name});
- #end
- #end
- #if ( $class == $root )
- ${classLcapName}.modelEncoding(parser.getInputEncoding());
- #end
- return ${classLcapName}.build();
- }
-
- #end
-#end
-
- private String checkDuplicate(String tagName, XmlPullParser parser,
Set<String> parsed) throws XmlPullParserException {
-#set( $aliases = { } )
-#set( $flats = { } )
-#foreach( $class in $model.allClasses )
- #foreach ( $field in $class.getFields($version) )
- #set ( $fieldTagName = $Helper.xmlFieldMetadata( $field ).tagName )
- #if ( ! $fieldTagName )
- #set ( $fieldTagName = $field.name )
- #end
- #if ( $field.alias )
- #set ( $dummy = $aliases.put( $field.alias, $fieldTagName ) )
- #end
- #if ( $Helper.isFlatItems( $field ) )
- #set ( $fieldTagName = $Helper.singular($fieldTagName) )
- #set ( $dummy = $flats.put( $fieldTagName, "" ) )
- #end
- #end
-#end
-#if ( ! ${aliases.isEmpty()} )
- switch (tagName) {
- #foreach( $entry in $aliases.entrySet() )
- case "${entry.key}":
- tagName = "${entry.value}";
- #end
- }
-#end
-#if ( ! ${flats.isEmpty()} )
- switch (tagName) {
- #foreach( $entry in $flats.entrySet() )
- case "${entry.key}":
- #end
- break;
- default:
- if (!parsed.add(tagName)) {
- throw new XmlPullParserException("Duplicated tag: '" +
tagName + "'", parser, null);
- }
- }
-#end
- return tagName;
- }
-
- /**
- * Sets the state of the "add default entities" flag.
- *
- * @param addDefaultEntities a addDefaultEntities object.
- */
- public void setAddDefaultEntities(boolean addDefaultEntities) {
- this.addDefaultEntities = addDefaultEntities;
- } //-- void setAddDefaultEntities(boolean)
-
- public static interface ContentTransformer {
- /**
- * Interpolate the value read from the xpp3 document
- * @param source The source value
- * @param fieldName A description of the field being interpolated. The
implementation may use this to
- * log stuff.
- * @return The interpolated value.
- */
- String transform(String source, String fieldName);
- }
-
}