elharo commented on code in PR #2029:
URL: https://github.com/apache/maven/pull/2029#discussion_r1904259241


##########
api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlNode.java:
##########
@@ -18,121 +18,244 @@
  */
 package org.apache.maven.api.xml;
 
+import javax.xml.stream.XMLStreamException;
+
+import java.io.Serializable;
+import java.io.StringWriter;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
-
-import org.apache.maven.api.annotations.Experimental;
-import org.apache.maven.api.annotations.Immutable;
-import org.apache.maven.api.annotations.Nonnull;
-import org.apache.maven.api.annotations.Nullable;
-import org.apache.maven.api.annotations.ThreadSafe;
+import java.util.Objects;
+import java.util.function.Function;
 
 /**
- * An immutable xml node.
- *
- * @since 4.0.0
+ *  NOTE: remove all the util code in here when separated, this class should 
be pure data.
  */
-@Experimental
-@ThreadSafe
-@Immutable
-public interface XmlNode {
+public class XmlNode implements Serializable {
+    private static final long serialVersionUID = 2567894443061173996L;
 
-    String CHILDREN_COMBINATION_MODE_ATTRIBUTE = "combine.children";
+    public static final String CHILDREN_COMBINATION_MODE_ATTRIBUTE = 
"combine.children";
 
-    String CHILDREN_COMBINATION_MERGE = "merge";
+    public static final String CHILDREN_COMBINATION_MERGE = "merge";
 
-    String CHILDREN_COMBINATION_APPEND = "append";
+    public static final String CHILDREN_COMBINATION_APPEND = "append";
 
     /**
      * This default mode for combining children DOMs during merge means that 
where element names match, the process will
      * try to merge the element data, rather than putting the dominant and 
recessive elements (which share the same
      * element name) as siblings in the resulting DOM.
      */
-    String DEFAULT_CHILDREN_COMBINATION_MODE = CHILDREN_COMBINATION_MERGE;
+    public static final String DEFAULT_CHILDREN_COMBINATION_MODE = 
CHILDREN_COMBINATION_MERGE;
 
-    String SELF_COMBINATION_MODE_ATTRIBUTE = "combine.self";
+    public static final String SELF_COMBINATION_MODE_ATTRIBUTE = 
"combine.self";
 
-    String SELF_COMBINATION_OVERRIDE = "override";
+    public static final String SELF_COMBINATION_OVERRIDE = "override";
 
-    String SELF_COMBINATION_MERGE = "merge";
+    public static final String SELF_COMBINATION_MERGE = "merge";
 
-    String SELF_COMBINATION_REMOVE = "remove";
+    public static final String SELF_COMBINATION_REMOVE = "remove";
 
     /**
      * In case of complex XML structures, combining can be done based on id.
      */
-    String ID_COMBINATION_MODE_ATTRIBUTE = "combine.id";
+    public static final String ID_COMBINATION_MODE_ATTRIBUTE = "combine.id";
 
     /**
      * In case of complex XML structures, combining can be done based on keys.
      * This is a comma separated list of attribute names.
      */
-    String KEYS_COMBINATION_MODE_ATTRIBUTE = "combine.keys";
+    public static final String KEYS_COMBINATION_MODE_ATTRIBUTE = 
"combine.keys";
 
     /**
      * This default mode for combining a DOM node during merge means that 
where element names match, the process will
      * try to merge the element attributes and values, rather than overriding 
the recessive element completely with the
      * dominant one. This means that wherever the dominant element doesn't 
provide the value or a particular attribute,
      * that value or attribute will be set from the recessive DOM node.
      */
-    String DEFAULT_SELF_COMBINATION_MODE = SELF_COMBINATION_MERGE;
+    public static final String DEFAULT_SELF_COMBINATION_MODE = 
SELF_COMBINATION_MERGE;
+
+    protected final String prefix;
+
+    protected final String namespaceUri;
+
+    protected final String name;
+
+    protected final String value;
+
+    protected final Map<String, String> attributes;
+
+    protected final List<XmlNode> children;
+
+    protected final Object location;
+
+    public XmlNode(String name) {
+        this(name, null, null, null, null);
+    }
+
+    public XmlNode(String name, String value) {
+        this(name, value, null, null, null);
+    }
+
+    public XmlNode(XmlNode from, String name) {
+        this(name, from.getValue(), from.getAttributes(), from.getChildren(), 
from.getInputLocation());
+    }
+
+    public XmlNode(String name, String value, Map<String, String> attributes, 
List<XmlNode> children, Object location) {
+        this("", "", name, value, attributes, children, location);
+    }
+
+    public XmlNode(
+            String prefix,
+            String namespaceUri,
+            String name,
+            String value,
+            Map<String, String> attributes,
+            List<XmlNode> children,
+            Object location) {
+        this.prefix = prefix == null ? "" : prefix;
+        this.namespaceUri = namespaceUri == null ? "" : namespaceUri;
+        this.name = Objects.requireNonNull(name);
+        this.value = value;
+        this.attributes = ImmutableCollections.copy(attributes);
+        this.children = ImmutableCollections.copy(children);
+        this.location = location;
+    }
+    // ----------------------------------------------------------------------
+    // Name handling
+    // ----------------------------------------------------------------------
+
+    public String getPrefix() {
+        return prefix;
+    }
 
-    @Nonnull
-    String getName();
+    public String getNamespaceUri() {
+        return namespaceUri;
+    }
 
-    @Nonnull
-    String getNamespaceUri();
+    public String getName() {
+        return name;
+    }
 
-    @Nonnull
-    String getPrefix();
+    // ----------------------------------------------------------------------
+    // Value handling
+    // ----------------------------------------------------------------------
 
-    @Nullable
-    String getValue();
+    public String getValue() {
+        return value;
+    }
 
-    @Nonnull
-    Map<String, String> getAttributes();
+    // ----------------------------------------------------------------------
+    // Attribute handling
+    // ----------------------------------------------------------------------
 
-    @Nullable
-    String getAttribute(@Nonnull String name);
+    public Map<String, String> getAttributes() {

Review Comment:
   needs javadoc, particularly about immutability



##########
api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlNode.java:
##########
@@ -18,121 +18,244 @@
  */
 package org.apache.maven.api.xml;
 
+import javax.xml.stream.XMLStreamException;
+
+import java.io.Serializable;
+import java.io.StringWriter;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
-
-import org.apache.maven.api.annotations.Experimental;
-import org.apache.maven.api.annotations.Immutable;
-import org.apache.maven.api.annotations.Nonnull;
-import org.apache.maven.api.annotations.Nullable;
-import org.apache.maven.api.annotations.ThreadSafe;
+import java.util.Objects;
+import java.util.function.Function;
 
 /**
- * An immutable xml node.
- *
- * @since 4.0.0
+ *  NOTE: remove all the util code in here when separated, this class should 
be pure data.

Review Comment:
   let's do this now, maybe even in a preceding PR



##########
api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlNode.java:
##########
@@ -18,121 +18,244 @@
  */
 package org.apache.maven.api.xml;
 
+import javax.xml.stream.XMLStreamException;
+
+import java.io.Serializable;
+import java.io.StringWriter;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
-
-import org.apache.maven.api.annotations.Experimental;
-import org.apache.maven.api.annotations.Immutable;
-import org.apache.maven.api.annotations.Nonnull;
-import org.apache.maven.api.annotations.Nullable;
-import org.apache.maven.api.annotations.ThreadSafe;
+import java.util.Objects;
+import java.util.function.Function;
 
 /**
- * An immutable xml node.
- *
- * @since 4.0.0
+ *  NOTE: remove all the util code in here when separated, this class should 
be pure data.
  */
-@Experimental
-@ThreadSafe
-@Immutable
-public interface XmlNode {
+public class XmlNode implements Serializable {
+    private static final long serialVersionUID = 2567894443061173996L;
 
-    String CHILDREN_COMBINATION_MODE_ATTRIBUTE = "combine.children";
+    public static final String CHILDREN_COMBINATION_MODE_ATTRIBUTE = 
"combine.children";
 
-    String CHILDREN_COMBINATION_MERGE = "merge";
+    public static final String CHILDREN_COMBINATION_MERGE = "merge";
 
-    String CHILDREN_COMBINATION_APPEND = "append";
+    public static final String CHILDREN_COMBINATION_APPEND = "append";
 
     /**
      * This default mode for combining children DOMs during merge means that 
where element names match, the process will
      * try to merge the element data, rather than putting the dominant and 
recessive elements (which share the same
      * element name) as siblings in the resulting DOM.
      */
-    String DEFAULT_CHILDREN_COMBINATION_MODE = CHILDREN_COMBINATION_MERGE;
+    public static final String DEFAULT_CHILDREN_COMBINATION_MODE = 
CHILDREN_COMBINATION_MERGE;
 
-    String SELF_COMBINATION_MODE_ATTRIBUTE = "combine.self";
+    public static final String SELF_COMBINATION_MODE_ATTRIBUTE = 
"combine.self";
 
-    String SELF_COMBINATION_OVERRIDE = "override";
+    public static final String SELF_COMBINATION_OVERRIDE = "override";
 
-    String SELF_COMBINATION_MERGE = "merge";
+    public static final String SELF_COMBINATION_MERGE = "merge";
 
-    String SELF_COMBINATION_REMOVE = "remove";
+    public static final String SELF_COMBINATION_REMOVE = "remove";
 
     /**
      * In case of complex XML structures, combining can be done based on id.
      */
-    String ID_COMBINATION_MODE_ATTRIBUTE = "combine.id";
+    public static final String ID_COMBINATION_MODE_ATTRIBUTE = "combine.id";
 
     /**
      * In case of complex XML structures, combining can be done based on keys.
      * This is a comma separated list of attribute names.
      */
-    String KEYS_COMBINATION_MODE_ATTRIBUTE = "combine.keys";
+    public static final String KEYS_COMBINATION_MODE_ATTRIBUTE = 
"combine.keys";
 
     /**
      * This default mode for combining a DOM node during merge means that 
where element names match, the process will
      * try to merge the element attributes and values, rather than overriding 
the recessive element completely with the
      * dominant one. This means that wherever the dominant element doesn't 
provide the value or a particular attribute,
      * that value or attribute will be set from the recessive DOM node.
      */
-    String DEFAULT_SELF_COMBINATION_MODE = SELF_COMBINATION_MERGE;
+    public static final String DEFAULT_SELF_COMBINATION_MODE = 
SELF_COMBINATION_MERGE;
+
+    protected final String prefix;
+
+    protected final String namespaceUri;
+
+    protected final String name;
+
+    protected final String value;
+
+    protected final Map<String, String> attributes;
+
+    protected final List<XmlNode> children;
+
+    protected final Object location;
+
+    public XmlNode(String name) {
+        this(name, null, null, null, null);
+    }
+
+    public XmlNode(String name, String value) {
+        this(name, value, null, null, null);
+    }
+
+    public XmlNode(XmlNode from, String name) {
+        this(name, from.getValue(), from.getAttributes(), from.getChildren(), 
from.getInputLocation());
+    }
+
+    public XmlNode(String name, String value, Map<String, String> attributes, 
List<XmlNode> children, Object location) {
+        this("", "", name, value, attributes, children, location);
+    }
+
+    public XmlNode(
+            String prefix,
+            String namespaceUri,
+            String name,
+            String value,
+            Map<String, String> attributes,
+            List<XmlNode> children,
+            Object location) {
+        this.prefix = prefix == null ? "" : prefix;
+        this.namespaceUri = namespaceUri == null ? "" : namespaceUri;
+        this.name = Objects.requireNonNull(name);
+        this.value = value;
+        this.attributes = ImmutableCollections.copy(attributes);
+        this.children = ImmutableCollections.copy(children);
+        this.location = location;
+    }
+    // ----------------------------------------------------------------------
+    // Name handling
+    // ----------------------------------------------------------------------
+
+    public String getPrefix() {
+        return prefix;
+    }
 
-    @Nonnull
-    String getName();
+    public String getNamespaceUri() {
+        return namespaceUri;
+    }
 
-    @Nonnull
-    String getNamespaceUri();
+    public String getName() {
+        return name;
+    }
 
-    @Nonnull
-    String getPrefix();
+    // ----------------------------------------------------------------------
+    // Value handling
+    // ----------------------------------------------------------------------
 
-    @Nullable
-    String getValue();
+    public String getValue() {
+        return value;
+    }
 
-    @Nonnull
-    Map<String, String> getAttributes();
+    // ----------------------------------------------------------------------
+    // Attribute handling
+    // ----------------------------------------------------------------------
 
-    @Nullable
-    String getAttribute(@Nonnull String name);
+    public Map<String, String> getAttributes() {
+        return attributes;
+    }
 
-    @Nonnull
-    List<XmlNode> getChildren();
+    public String getAttribute(String name) {
+        return attributes.get(name);
+    }
 
-    @Nullable
-    XmlNode getChild(String name);
+    // ----------------------------------------------------------------------
+    // Child handling
+    // ----------------------------------------------------------------------
 
-    @Nullable
-    Object getInputLocation();
+    public XmlNode getChild(String name) {
+        if (name != null) {
+            ListIterator<XmlNode> it = children.listIterator(children.size());
+            while (it.hasPrevious()) {
+                XmlNode child = it.previous();
+                if (name.equals(child.getName())) {
+                    return child;
+                }
+            }
+        }
+        return null;
+    }
+
+    public List<XmlNode> getChildren() {
+        return children;
+    }
 
-    default XmlNode merge(@Nullable XmlNode source) {
-        return merge(source, (Boolean) null);
+    public int getChildCount() {
+        return children.size();
     }
 
-    XmlNode merge(@Nullable XmlNode source, @Nullable Boolean 
childMergeOverride);
+    // ----------------------------------------------------------------------
+    // Input location handling
+    // ----------------------------------------------------------------------
 
     /**
-     * Merge recessive into dominant and return either {@code dominant}
-     * with merged information or a clone of {@code recessive} if
-     * {@code dominant} is {@code null}.
-     *
-     * @param dominant the node
-     * @param recessive if {@code null}, nothing will happen
-     * @return the merged node
+     * @since 3.2.0
+     * @return input location
      */
-    @Nullable
-    static XmlNode merge(@Nullable XmlNode dominant, @Nullable XmlNode 
recessive) {
-        return merge(dominant, recessive, null);
+    public Object getInputLocation() {
+        return location;
+    }
+
+    // ----------------------------------------------------------------------
+    // Standard object handling
+    // ----------------------------------------------------------------------
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        XmlNode that = (XmlNode) o;
+        return Objects.equals(this.name, that.name)
+                && Objects.equals(this.value, that.value)
+                && Objects.equals(this.attributes, that.attributes)
+                && Objects.equals(this.children, that.children);
     }
 
-    @Nullable
-    static XmlNode merge(
-            @Nullable XmlNode dominant, @Nullable XmlNode recessive, @Nullable 
Boolean childMergeOverride) {
-        if (recessive == null) {
-            return dominant;
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, value, attributes, children);
+    }
+
+    @Override
+    public String toString() {
+        try {
+            return toStringXml();
+        } catch (XMLStreamException e) {
+            return toStringObject();
         }
-        if (dominant == null) {
-            return recessive;
+    }
+
+    public String toStringXml() throws XMLStreamException {
+        StringWriter writer = new StringWriter();
+        XmlNodeWriter.write(writer, this);
+        return writer.toString();
+    }
+
+    public String toStringObject() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("XmlNode[");
+        boolean w = false;
+        w = addToStringField(sb, prefix, o -> !o.isEmpty(), "prefix", w);
+        w = addToStringField(sb, namespaceUri, o -> !o.isEmpty(), 
"namespaceUri", w);
+        w = addToStringField(sb, name, o -> !o.isEmpty(), "name", w);
+        w = addToStringField(sb, value, o -> !o.isEmpty(), "value", w);
+        w = addToStringField(sb, attributes, o -> !o.isEmpty(), "attributes", 
w);
+        w = addToStringField(sb, children, o -> !o.isEmpty(), "children", w);
+        w = addToStringField(sb, location, Objects::nonNull, "location", w);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    private static <T> boolean addToStringField(StringBuilder sb, T o, 
Function<T, Boolean> p, String n, boolean w) {

Review Comment:
   rename w variable and other variables; in general avoid single letter names



##########
api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlNode.java:
##########
@@ -18,121 +18,244 @@
  */
 package org.apache.maven.api.xml;
 
+import javax.xml.stream.XMLStreamException;
+
+import java.io.Serializable;
+import java.io.StringWriter;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
-
-import org.apache.maven.api.annotations.Experimental;
-import org.apache.maven.api.annotations.Immutable;
-import org.apache.maven.api.annotations.Nonnull;
-import org.apache.maven.api.annotations.Nullable;
-import org.apache.maven.api.annotations.ThreadSafe;
+import java.util.Objects;
+import java.util.function.Function;
 
 /**
- * An immutable xml node.
- *
- * @since 4.0.0
+ *  NOTE: remove all the util code in here when separated, this class should 
be pure data.
  */
-@Experimental
-@ThreadSafe
-@Immutable
-public interface XmlNode {
+public class XmlNode implements Serializable {
+    private static final long serialVersionUID = 2567894443061173996L;
 
-    String CHILDREN_COMBINATION_MODE_ATTRIBUTE = "combine.children";
+    public static final String CHILDREN_COMBINATION_MODE_ATTRIBUTE = 
"combine.children";
 
-    String CHILDREN_COMBINATION_MERGE = "merge";
+    public static final String CHILDREN_COMBINATION_MERGE = "merge";
 
-    String CHILDREN_COMBINATION_APPEND = "append";
+    public static final String CHILDREN_COMBINATION_APPEND = "append";
 
     /**
      * This default mode for combining children DOMs during merge means that 
where element names match, the process will
      * try to merge the element data, rather than putting the dominant and 
recessive elements (which share the same
      * element name) as siblings in the resulting DOM.
      */
-    String DEFAULT_CHILDREN_COMBINATION_MODE = CHILDREN_COMBINATION_MERGE;
+    public static final String DEFAULT_CHILDREN_COMBINATION_MODE = 
CHILDREN_COMBINATION_MERGE;
 
-    String SELF_COMBINATION_MODE_ATTRIBUTE = "combine.self";
+    public static final String SELF_COMBINATION_MODE_ATTRIBUTE = 
"combine.self";
 
-    String SELF_COMBINATION_OVERRIDE = "override";
+    public static final String SELF_COMBINATION_OVERRIDE = "override";
 
-    String SELF_COMBINATION_MERGE = "merge";
+    public static final String SELF_COMBINATION_MERGE = "merge";
 
-    String SELF_COMBINATION_REMOVE = "remove";
+    public static final String SELF_COMBINATION_REMOVE = "remove";
 
     /**
      * In case of complex XML structures, combining can be done based on id.
      */
-    String ID_COMBINATION_MODE_ATTRIBUTE = "combine.id";
+    public static final String ID_COMBINATION_MODE_ATTRIBUTE = "combine.id";
 
     /**
      * In case of complex XML structures, combining can be done based on keys.
      * This is a comma separated list of attribute names.
      */
-    String KEYS_COMBINATION_MODE_ATTRIBUTE = "combine.keys";
+    public static final String KEYS_COMBINATION_MODE_ATTRIBUTE = 
"combine.keys";
 
     /**
      * This default mode for combining a DOM node during merge means that 
where element names match, the process will
      * try to merge the element attributes and values, rather than overriding 
the recessive element completely with the
      * dominant one. This means that wherever the dominant element doesn't 
provide the value or a particular attribute,
      * that value or attribute will be set from the recessive DOM node.
      */
-    String DEFAULT_SELF_COMBINATION_MODE = SELF_COMBINATION_MERGE;
+    public static final String DEFAULT_SELF_COMBINATION_MODE = 
SELF_COMBINATION_MERGE;
+
+    protected final String prefix;
+
+    protected final String namespaceUri;
+
+    protected final String name;
+
+    protected final String value;
+
+    protected final Map<String, String> attributes;
+
+    protected final List<XmlNode> children;
+
+    protected final Object location;
+
+    public XmlNode(String name) {
+        this(name, null, null, null, null);
+    }
+
+    public XmlNode(String name, String value) {
+        this(name, value, null, null, null);
+    }
+
+    public XmlNode(XmlNode from, String name) {
+        this(name, from.getValue(), from.getAttributes(), from.getChildren(), 
from.getInputLocation());
+    }
+
+    public XmlNode(String name, String value, Map<String, String> attributes, 
List<XmlNode> children, Object location) {
+        this("", "", name, value, attributes, children, location);
+    }
+
+    public XmlNode(
+            String prefix,
+            String namespaceUri,
+            String name,
+            String value,
+            Map<String, String> attributes,
+            List<XmlNode> children,
+            Object location) {
+        this.prefix = prefix == null ? "" : prefix;
+        this.namespaceUri = namespaceUri == null ? "" : namespaceUri;
+        this.name = Objects.requireNonNull(name);
+        this.value = value;
+        this.attributes = ImmutableCollections.copy(attributes);
+        this.children = ImmutableCollections.copy(children);
+        this.location = location;
+    }
+    // ----------------------------------------------------------------------
+    // Name handling
+    // ----------------------------------------------------------------------
+
+    public String getPrefix() {
+        return prefix;
+    }
 
-    @Nonnull
-    String getName();
+    public String getNamespaceUri() {
+        return namespaceUri;
+    }
 
-    @Nonnull
-    String getNamespaceUri();
+    public String getName() {
+        return name;
+    }
 
-    @Nonnull
-    String getPrefix();
+    // ----------------------------------------------------------------------
+    // Value handling
+    // ----------------------------------------------------------------------
 
-    @Nullable
-    String getValue();
+    public String getValue() {
+        return value;
+    }
 
-    @Nonnull
-    Map<String, String> getAttributes();
+    // ----------------------------------------------------------------------
+    // Attribute handling
+    // ----------------------------------------------------------------------
 
-    @Nullable
-    String getAttribute(@Nonnull String name);
+    public Map<String, String> getAttributes() {
+        return attributes;
+    }
 
-    @Nonnull
-    List<XmlNode> getChildren();
+    public String getAttribute(String name) {
+        return attributes.get(name);
+    }
 
-    @Nullable
-    XmlNode getChild(String name);
+    // ----------------------------------------------------------------------
+    // Child handling
+    // ----------------------------------------------------------------------
 
-    @Nullable
-    Object getInputLocation();
+    public XmlNode getChild(String name) {
+        if (name != null) {
+            ListIterator<XmlNode> it = children.listIterator(children.size());
+            while (it.hasPrevious()) {
+                XmlNode child = it.previous();
+                if (name.equals(child.getName())) {
+                    return child;
+                }
+            }
+        }
+        return null;
+    }
+
+    public List<XmlNode> getChildren() {
+        return children;
+    }
 
-    default XmlNode merge(@Nullable XmlNode source) {
-        return merge(source, (Boolean) null);
+    public int getChildCount() {
+        return children.size();
     }
 
-    XmlNode merge(@Nullable XmlNode source, @Nullable Boolean 
childMergeOverride);
+    // ----------------------------------------------------------------------
+    // Input location handling
+    // ----------------------------------------------------------------------
 
     /**
-     * Merge recessive into dominant and return either {@code dominant}
-     * with merged information or a clone of {@code recessive} if
-     * {@code dominant} is {@code null}.
-     *
-     * @param dominant the node
-     * @param recessive if {@code null}, nothing will happen
-     * @return the merged node
+     * @since 3.2.0
+     * @return input location
      */
-    @Nullable
-    static XmlNode merge(@Nullable XmlNode dominant, @Nullable XmlNode 
recessive) {
-        return merge(dominant, recessive, null);
+    public Object getInputLocation() {
+        return location;
+    }
+
+    // ----------------------------------------------------------------------
+    // Standard object handling
+    // ----------------------------------------------------------------------
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        XmlNode that = (XmlNode) o;
+        return Objects.equals(this.name, that.name)
+                && Objects.equals(this.value, that.value)
+                && Objects.equals(this.attributes, that.attributes)
+                && Objects.equals(this.children, that.children);
     }
 
-    @Nullable
-    static XmlNode merge(
-            @Nullable XmlNode dominant, @Nullable XmlNode recessive, @Nullable 
Boolean childMergeOverride) {
-        if (recessive == null) {
-            return dominant;
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, value, attributes, children);
+    }
+
+    @Override
+    public String toString() {
+        try {
+            return toStringXml();
+        } catch (XMLStreamException e) {
+            return toStringObject();
         }
-        if (dominant == null) {
-            return recessive;
+    }
+
+    public String toStringXml() throws XMLStreamException {
+        StringWriter writer = new StringWriter();
+        XmlNodeWriter.write(writer, this);
+        return writer.toString();
+    }
+
+    public String toStringObject() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("XmlNode[");
+        boolean w = false;
+        w = addToStringField(sb, prefix, o -> !o.isEmpty(), "prefix", w);
+        w = addToStringField(sb, namespaceUri, o -> !o.isEmpty(), 
"namespaceUri", w);

Review Comment:
   why is this variable reassigned?



##########
api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlNode.java:
##########
@@ -18,121 +18,244 @@
  */
 package org.apache.maven.api.xml;
 
+import javax.xml.stream.XMLStreamException;
+
+import java.io.Serializable;
+import java.io.StringWriter;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
-
-import org.apache.maven.api.annotations.Experimental;
-import org.apache.maven.api.annotations.Immutable;
-import org.apache.maven.api.annotations.Nonnull;
-import org.apache.maven.api.annotations.Nullable;
-import org.apache.maven.api.annotations.ThreadSafe;
+import java.util.Objects;
+import java.util.function.Function;
 
 /**
- * An immutable xml node.
- *
- * @since 4.0.0
+ *  NOTE: remove all the util code in here when separated, this class should 
be pure data.
  */
-@Experimental
-@ThreadSafe
-@Immutable
-public interface XmlNode {
+public class XmlNode implements Serializable {
+    private static final long serialVersionUID = 2567894443061173996L;

Review Comment:
   remove



##########
api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlNode.java:
##########
@@ -18,121 +18,244 @@
  */
 package org.apache.maven.api.xml;
 
+import javax.xml.stream.XMLStreamException;
+
+import java.io.Serializable;
+import java.io.StringWriter;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
-
-import org.apache.maven.api.annotations.Experimental;
-import org.apache.maven.api.annotations.Immutable;
-import org.apache.maven.api.annotations.Nonnull;
-import org.apache.maven.api.annotations.Nullable;
-import org.apache.maven.api.annotations.ThreadSafe;
+import java.util.Objects;
+import java.util.function.Function;
 
 /**
- * An immutable xml node.
- *
- * @since 4.0.0
+ *  NOTE: remove all the util code in here when separated, this class should 
be pure data.
  */
-@Experimental
-@ThreadSafe
-@Immutable
-public interface XmlNode {
+public class XmlNode implements Serializable {
+    private static final long serialVersionUID = 2567894443061173996L;
 
-    String CHILDREN_COMBINATION_MODE_ATTRIBUTE = "combine.children";
+    public static final String CHILDREN_COMBINATION_MODE_ATTRIBUTE = 
"combine.children";
 
-    String CHILDREN_COMBINATION_MERGE = "merge";
+    public static final String CHILDREN_COMBINATION_MERGE = "merge";
 
-    String CHILDREN_COMBINATION_APPEND = "append";
+    public static final String CHILDREN_COMBINATION_APPEND = "append";
 
     /**
      * This default mode for combining children DOMs during merge means that 
where element names match, the process will
      * try to merge the element data, rather than putting the dominant and 
recessive elements (which share the same
      * element name) as siblings in the resulting DOM.
      */
-    String DEFAULT_CHILDREN_COMBINATION_MODE = CHILDREN_COMBINATION_MERGE;
+    public static final String DEFAULT_CHILDREN_COMBINATION_MODE = 
CHILDREN_COMBINATION_MERGE;
 
-    String SELF_COMBINATION_MODE_ATTRIBUTE = "combine.self";
+    public static final String SELF_COMBINATION_MODE_ATTRIBUTE = 
"combine.self";
 
-    String SELF_COMBINATION_OVERRIDE = "override";
+    public static final String SELF_COMBINATION_OVERRIDE = "override";
 
-    String SELF_COMBINATION_MERGE = "merge";
+    public static final String SELF_COMBINATION_MERGE = "merge";
 
-    String SELF_COMBINATION_REMOVE = "remove";
+    public static final String SELF_COMBINATION_REMOVE = "remove";
 
     /**
      * In case of complex XML structures, combining can be done based on id.
      */
-    String ID_COMBINATION_MODE_ATTRIBUTE = "combine.id";
+    public static final String ID_COMBINATION_MODE_ATTRIBUTE = "combine.id";
 
     /**
      * In case of complex XML structures, combining can be done based on keys.
      * This is a comma separated list of attribute names.
      */
-    String KEYS_COMBINATION_MODE_ATTRIBUTE = "combine.keys";
+    public static final String KEYS_COMBINATION_MODE_ATTRIBUTE = 
"combine.keys";
 
     /**
      * This default mode for combining a DOM node during merge means that 
where element names match, the process will
      * try to merge the element attributes and values, rather than overriding 
the recessive element completely with the
      * dominant one. This means that wherever the dominant element doesn't 
provide the value or a particular attribute,
      * that value or attribute will be set from the recessive DOM node.
      */
-    String DEFAULT_SELF_COMBINATION_MODE = SELF_COMBINATION_MERGE;
+    public static final String DEFAULT_SELF_COMBINATION_MODE = 
SELF_COMBINATION_MERGE;
+
+    protected final String prefix;
+
+    protected final String namespaceUri;
+
+    protected final String name;
+
+    protected final String value;
+
+    protected final Map<String, String> attributes;
+
+    protected final List<XmlNode> children;
+
+    protected final Object location;
+
+    public XmlNode(String name) {
+        this(name, null, null, null, null);
+    }
+
+    public XmlNode(String name, String value) {
+        this(name, value, null, null, null);
+    }
+
+    public XmlNode(XmlNode from, String name) {
+        this(name, from.getValue(), from.getAttributes(), from.getChildren(), 
from.getInputLocation());
+    }
+
+    public XmlNode(String name, String value, Map<String, String> attributes, 
List<XmlNode> children, Object location) {
+        this("", "", name, value, attributes, children, location);
+    }
+
+    public XmlNode(
+            String prefix,
+            String namespaceUri,
+            String name,
+            String value,
+            Map<String, String> attributes,
+            List<XmlNode> children,
+            Object location) {
+        this.prefix = prefix == null ? "" : prefix;
+        this.namespaceUri = namespaceUri == null ? "" : namespaceUri;
+        this.name = Objects.requireNonNull(name);
+        this.value = value;
+        this.attributes = ImmutableCollections.copy(attributes);
+        this.children = ImmutableCollections.copy(children);
+        this.location = location;
+    }
+    // ----------------------------------------------------------------------
+    // Name handling
+    // ----------------------------------------------------------------------
+
+    public String getPrefix() {
+        return prefix;
+    }
 
-    @Nonnull
-    String getName();
+    public String getNamespaceUri() {
+        return namespaceUri;
+    }
 
-    @Nonnull
-    String getNamespaceUri();
+    public String getName() {
+        return name;
+    }
 
-    @Nonnull
-    String getPrefix();
+    // ----------------------------------------------------------------------
+    // Value handling
+    // ----------------------------------------------------------------------
 
-    @Nullable
-    String getValue();
+    public String getValue() {
+        return value;
+    }
 
-    @Nonnull
-    Map<String, String> getAttributes();
+    // ----------------------------------------------------------------------
+    // Attribute handling
+    // ----------------------------------------------------------------------
 
-    @Nullable
-    String getAttribute(@Nonnull String name);
+    public Map<String, String> getAttributes() {
+        return attributes;
+    }
 
-    @Nonnull
-    List<XmlNode> getChildren();
+    public String getAttribute(String name) {
+        return attributes.get(name);
+    }
 
-    @Nullable
-    XmlNode getChild(String name);
+    // ----------------------------------------------------------------------
+    // Child handling
+    // ----------------------------------------------------------------------
 
-    @Nullable
-    Object getInputLocation();
+    public XmlNode getChild(String name) {
+        if (name != null) {
+            ListIterator<XmlNode> it = children.listIterator(children.size());
+            while (it.hasPrevious()) {
+                XmlNode child = it.previous();
+                if (name.equals(child.getName())) {
+                    return child;
+                }
+            }
+        }
+        return null;
+    }
+
+    public List<XmlNode> getChildren() {
+        return children;
+    }
 
-    default XmlNode merge(@Nullable XmlNode source) {
-        return merge(source, (Boolean) null);
+    public int getChildCount() {
+        return children.size();
     }
 
-    XmlNode merge(@Nullable XmlNode source, @Nullable Boolean 
childMergeOverride);
+    // ----------------------------------------------------------------------
+    // Input location handling
+    // ----------------------------------------------------------------------
 
     /**
-     * Merge recessive into dominant and return either {@code dominant}
-     * with merged information or a clone of {@code recessive} if
-     * {@code dominant} is {@code null}.
-     *
-     * @param dominant the node
-     * @param recessive if {@code null}, nothing will happen
-     * @return the merged node
+     * @since 3.2.0
+     * @return input location
      */
-    @Nullable
-    static XmlNode merge(@Nullable XmlNode dominant, @Nullable XmlNode 
recessive) {
-        return merge(dominant, recessive, null);
+    public Object getInputLocation() {
+        return location;
+    }
+
+    // ----------------------------------------------------------------------
+    // Standard object handling
+    // ----------------------------------------------------------------------
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        XmlNode that = (XmlNode) o;
+        return Objects.equals(this.name, that.name)
+                && Objects.equals(this.value, that.value)
+                && Objects.equals(this.attributes, that.attributes)
+                && Objects.equals(this.children, that.children);
     }
 
-    @Nullable
-    static XmlNode merge(
-            @Nullable XmlNode dominant, @Nullable XmlNode recessive, @Nullable 
Boolean childMergeOverride) {
-        if (recessive == null) {
-            return dominant;
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, value, attributes, children);
+    }
+
+    @Override
+    public String toString() {
+        try {
+            return toStringXml();
+        } catch (XMLStreamException e) {
+            return toStringObject();
         }
-        if (dominant == null) {
-            return recessive;
+    }
+
+    public String toStringXml() throws XMLStreamException {
+        StringWriter writer = new StringWriter();
+        XmlNodeWriter.write(writer, this);
+        return writer.toString();
+    }
+
+    public String toStringObject() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("XmlNode[");
+        boolean w = false;

Review Comment:
   rename variable



##########
api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlNode.java:
##########
@@ -18,121 +18,244 @@
  */
 package org.apache.maven.api.xml;
 
+import javax.xml.stream.XMLStreamException;
+
+import java.io.Serializable;
+import java.io.StringWriter;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
-
-import org.apache.maven.api.annotations.Experimental;
-import org.apache.maven.api.annotations.Immutable;
-import org.apache.maven.api.annotations.Nonnull;
-import org.apache.maven.api.annotations.Nullable;
-import org.apache.maven.api.annotations.ThreadSafe;
+import java.util.Objects;
+import java.util.function.Function;
 
 /**
- * An immutable xml node.
- *
- * @since 4.0.0
+ *  NOTE: remove all the util code in here when separated, this class should 
be pure data.
  */
-@Experimental
-@ThreadSafe
-@Immutable
-public interface XmlNode {
+public class XmlNode implements Serializable {
+    private static final long serialVersionUID = 2567894443061173996L;
 
-    String CHILDREN_COMBINATION_MODE_ATTRIBUTE = "combine.children";
+    public static final String CHILDREN_COMBINATION_MODE_ATTRIBUTE = 
"combine.children";
 
-    String CHILDREN_COMBINATION_MERGE = "merge";
+    public static final String CHILDREN_COMBINATION_MERGE = "merge";
 
-    String CHILDREN_COMBINATION_APPEND = "append";
+    public static final String CHILDREN_COMBINATION_APPEND = "append";
 
     /**
      * This default mode for combining children DOMs during merge means that 
where element names match, the process will
      * try to merge the element data, rather than putting the dominant and 
recessive elements (which share the same
      * element name) as siblings in the resulting DOM.
      */
-    String DEFAULT_CHILDREN_COMBINATION_MODE = CHILDREN_COMBINATION_MERGE;
+    public static final String DEFAULT_CHILDREN_COMBINATION_MODE = 
CHILDREN_COMBINATION_MERGE;
 
-    String SELF_COMBINATION_MODE_ATTRIBUTE = "combine.self";
+    public static final String SELF_COMBINATION_MODE_ATTRIBUTE = 
"combine.self";
 
-    String SELF_COMBINATION_OVERRIDE = "override";
+    public static final String SELF_COMBINATION_OVERRIDE = "override";
 
-    String SELF_COMBINATION_MERGE = "merge";
+    public static final String SELF_COMBINATION_MERGE = "merge";
 
-    String SELF_COMBINATION_REMOVE = "remove";
+    public static final String SELF_COMBINATION_REMOVE = "remove";
 
     /**
      * In case of complex XML structures, combining can be done based on id.
      */
-    String ID_COMBINATION_MODE_ATTRIBUTE = "combine.id";
+    public static final String ID_COMBINATION_MODE_ATTRIBUTE = "combine.id";
 
     /**
      * In case of complex XML structures, combining can be done based on keys.
      * This is a comma separated list of attribute names.
      */
-    String KEYS_COMBINATION_MODE_ATTRIBUTE = "combine.keys";
+    public static final String KEYS_COMBINATION_MODE_ATTRIBUTE = 
"combine.keys";
 
     /**
      * This default mode for combining a DOM node during merge means that 
where element names match, the process will
      * try to merge the element attributes and values, rather than overriding 
the recessive element completely with the
      * dominant one. This means that wherever the dominant element doesn't 
provide the value or a particular attribute,
      * that value or attribute will be set from the recessive DOM node.
      */
-    String DEFAULT_SELF_COMBINATION_MODE = SELF_COMBINATION_MERGE;
+    public static final String DEFAULT_SELF_COMBINATION_MODE = 
SELF_COMBINATION_MERGE;
+
+    protected final String prefix;

Review Comment:
   these should all be private



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscr...@maven.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


Reply via email to