From 0a8491c329782613dc58c000fabce67955cb47e5 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Mon, 19 Jun 2023 12:39:14 +0200 Subject: [PATCH] [MNG-7814] Use location tracking for settings (#1164) --- .../maven/settings/GlobalSettingsTest.java | 13 +- api/maven-api-settings/pom.xml | 1 + .../maven/api/settings/InputLocation.java | 172 ++++ .../api/settings/InputLocationTracker.java | 23 + .../maven/api/settings/InputSource.java | 47 + .../src/main/mdo/settings.mdo | 52 +- .../impl/DefaultSettingsXmlFactory.java | 12 +- .../building/DefaultSettingsBuilder.java | 65 +- .../settings/io/DefaultSettingsReader.java | 12 +- maven-settings/pom.xml | 28 +- src/mdo/model-v3.vm | 16 +- src/mdo/reader.vm | 816 +++++++++--------- 12 files changed, 777 insertions(+), 480 deletions(-) create mode 100644 api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputLocation.java create mode 100644 api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputLocationTracker.java create mode 100644 api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputSource.java 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 9512d4a934..a8819f87b6 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 3a05752c60..db5265d229 100644 --- a/api/maven-api-settings/pom.xml +++ b/api/maven-api-settings/pom.xml @@ -61,6 +61,7 @@ under the License. packageModelV4=org.apache.maven.api.settings + locationTracking=true 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 0000000000..b3ea387142 --- /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 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 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 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 locations; + Map sourceLocations = source.locations; + Map 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 indices) { + if (source == null) { + return target; + } else if (target == null) { + return source; + } + + Map locations; + Map sourceLocations = source.locations; + Map 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 0000000000..d49d723076 --- /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 0000000000..2450c1d798 --- /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 f1ec2e5bdc..caef275880 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 @@ - 1.0.0+ + 1.0.0/1.2.0 + + InputLocation + 2.0.0+ + + + + + + 2.0.0+ + + + + + + + + InputSource + 2.0.0+ + + + location + 2.0.0+ + String + + + + + + + + 2.0.0+ + + + + + + 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 39303e9cd0..811fd3c6b2 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 9eddc5c8b4..6f87101795 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 options = Collections.singletonMap(SettingsReader.IS_STRICT, Boolean.TRUE); - + Map 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 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 fc96ad1a23..a30e2bbd21 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 c27963e941..a87b0c0f70 100644 --- a/maven-settings/pom.xml +++ b/maven-settings/pom.xml @@ -60,6 +60,11 @@ under the License. src/main/mdo/settings.mdo + + packageModelV3=org.apache.maven.settings + packageModelV4=org.apache.maven.api.settings + packageToolV4=org.apache.maven.settings.v4 + @@ -70,18 +75,31 @@ under the License. generate-sources - + + + - - packageModelV3=org.apache.maven.settings - packageModelV4=org.apache.maven.api.settings - packageToolV4=org.apache.maven.settings.v4 + + locationTracking=true + + v3 + + velocity + + generate-sources + + 1.2.0 + + + + + diff --git a/src/mdo/model-v3.vm b/src/mdo/model-v3.vm index afa0d498ad..5508c618f4 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 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 b95ea61283..a1b86af1d5 100644 --- a/src/mdo/reader.vm +++ b/src/mdo/reader.vm @@ -73,414 +73,6 @@ public class ${className} { this.contentTransformer = contentTransformer; } - /** - * Method checkFieldWithDuplicate. - * - * @param parser a parser object. - * @param parsed a parsed object. - * @param alias a alias object. - * @param tagName a tagName object. - * @throws XmlPullParserException XmlPullParserException if - * any. - * @return boolean - */ - private boolean checkFieldWithDuplicate(XmlPullParser parser, String tagName, String alias, Set 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) - - /** - * Method checkUnknownAttribute. - * - * @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. - * @throws IOException IOException if any. - */ - 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 checkUnknownElement. - * - * @param parser a parser 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 - */ - 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 - */ - private long getLongValue(String s, String attribute, XmlPullParser parser, boolean strict) - throws XmlPullParserException { - if (s != null) { - try { - return Long.valueOf(s).longValue(); - } catch (NumberFormatException nfe) { - if (strict) { - throw new XmlPullParserException("Unable to parse element '" + attribute + "', must be a long integer", parser, nfe); - } - } - } - return 0; - } //-- long getLongValue(String, String, XmlPullParser, boolean) - - /** - * Method getRequiredAttributeValue. - * - * @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 String - */ - private String getRequiredAttributeValue(String s, String attribute, XmlPullParser parser, boolean strict) - throws XmlPullParserException { - if (s == null) { - if (strict) { - throw new XmlPullParserException("Missing required value for attribute '" + attribute + "'", parser, null); - } - } - return s; - } //-- String getRequiredAttributeValue(String, String, XmlPullParser, boolean) - - /** - * Method getShortValue. - * - * @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 short - */ - private short getShortValue(String s, String attribute, XmlPullParser parser, boolean strict) - throws XmlPullParserException { - if (s != null) { - try { - return Short.valueOf(s).shortValue(); - } catch (NumberFormatException nfe) { - if (strict) { - throw new XmlPullParserException("Unable to parse element '" + attribute + "', must be a short integer", parser, nfe); - } - } - } - return 0; - } //-- short getShortValue(String, String, XmlPullParser, boolean) - - /** - * Method getTrimmedValue. - * - * @param s a s object. - * @return String - */ - private String getTrimmedValue(String s) { - if (s != null) { - s = s.trim(); - } - return s; - } //-- String getTrimmedValue(String) - - /** - * Method interpolatedTrimmed. - * - * @param value a value object. - * @param context a context object. - * @return String - */ - private String interpolatedTrimmed(String value, String context) { - return getTrimmedValue(contentTransformer.transform(value, context)); - } //-- String interpolatedTrimmed(String, String) - - /** - * Method nextTag. - * - * @param parser a parser object. - * @throws IOException IOException if any. - * @throws XmlPullParserException XmlPullParserException if - * any. - * @return int - */ - private int nextTag(XmlPullParser parser) throws IOException, XmlPullParserException { - int eventType = parser.next(); - if (eventType == XmlPullParser.TEXT) { - eventType = parser.next(); - } - if (eventType != XmlPullParser.START_TAG && eventType != XmlPullParser.END_TAG) { - throw new XmlPullParserException("expected START_TAG or END_TAG not " + XmlPullParser.TYPES[eventType], parser, null); - } - return eventType; - } //-- int nextTag(XmlPullParser) - /** * @see ReaderFactory#newXmlReader * @@ -771,4 +363,412 @@ public class ${className} { String transform(String source, String fieldName); } + /** + * Method checkFieldWithDuplicate. + * + * @param parser a parser object. + * @param parsed a parsed object. + * @param alias a alias object. + * @param tagName a tagName object. + * @throws XmlPullParserException XmlPullParserException if + * any. + * @return boolean + */ + private boolean checkFieldWithDuplicate(XmlPullParser parser, String tagName, String alias, Set 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) + + /** + * Method checkUnknownAttribute. + * + * @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. + * @throws IOException IOException if any. + */ + 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 checkUnknownElement. + * + * @param parser a parser 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 + */ + 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 + */ + private long getLongValue(String s, String attribute, XmlPullParser parser, boolean strict) + throws XmlPullParserException { + if (s != null) { + try { + return Long.valueOf(s).longValue(); + } catch (NumberFormatException nfe) { + if (strict) { + throw new XmlPullParserException("Unable to parse element '" + attribute + "', must be a long integer", parser, nfe); + } + } + } + return 0; + } //-- long getLongValue(String, String, XmlPullParser, boolean) + + /** + * Method getRequiredAttributeValue. + * + * @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 String + */ + private String getRequiredAttributeValue(String s, String attribute, XmlPullParser parser, boolean strict) + throws XmlPullParserException { + if (s == null) { + if (strict) { + throw new XmlPullParserException("Missing required value for attribute '" + attribute + "'", parser, null); + } + } + return s; + } //-- String getRequiredAttributeValue(String, String, XmlPullParser, boolean) + + /** + * Method getShortValue. + * + * @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 short + */ + private short getShortValue(String s, String attribute, XmlPullParser parser, boolean strict) + throws XmlPullParserException { + if (s != null) { + try { + return Short.valueOf(s).shortValue(); + } catch (NumberFormatException nfe) { + if (strict) { + throw new XmlPullParserException("Unable to parse element '" + attribute + "', must be a short integer", parser, nfe); + } + } + } + return 0; + } //-- short getShortValue(String, String, XmlPullParser, boolean) + + /** + * Method getTrimmedValue. + * + * @param s a s object. + * @return String + */ + private String getTrimmedValue(String s) { + if (s != null) { + s = s.trim(); + } + return s; + } //-- String getTrimmedValue(String) + + /** + * Method interpolatedTrimmed. + * + * @param value a value object. + * @param context a context object. + * @return String + */ + private String interpolatedTrimmed(String value, String context) { + return getTrimmedValue(contentTransformer.transform(value, context)); + } //-- String interpolatedTrimmed(String, String) + + /** + * Method nextTag. + * + * @param parser a parser object. + * @throws IOException IOException if any. + * @throws XmlPullParserException XmlPullParserException if + * any. + * @return int + */ + private int nextTag(XmlPullParser parser) throws IOException, XmlPullParserException { + int eventType = parser.next(); + if (eventType == XmlPullParser.TEXT) { + eventType = parser.next(); + } + if (eventType != XmlPullParser.START_TAG && eventType != XmlPullParser.END_TAG) { + throw new XmlPullParserException("expected START_TAG or END_TAG not " + XmlPullParser.TYPES[eventType], parser, null); + } + return eventType; + } //-- int nextTag(XmlPullParser) + }