You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2022/12/01 21:07:36 UTC
[maven] branch master updated: [MNG-7596] Upgrade to plexus 3.5.0 (#866)
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 615390f6f [MNG-7596] Upgrade to plexus 3.5.0 (#866)
615390f6f is described below
commit 615390f6fc166bf991bfa271b3b05f22abb6e029
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Thu Dec 1 22:07:30 2022 +0100
[MNG-7596] Upgrade to plexus 3.5.0 (#866)
---
.../main/java/org/apache/maven/api/xml/Dom.java | 11 ++
.../org/apache/maven/internal/xml/Xpp3Dom.java | 90 ++++++----
.../apache/maven/internal/xml/Xpp3DomBuilder.java | 9 +-
.../org/apache/maven/internal/xml/Xpp3DomTest.java | 188 +++++++++++++++++++++
pom.xml | 2 +-
5 files changed, 269 insertions(+), 31 deletions(-)
diff --git a/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/Dom.java b/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/Dom.java
index c796ff711..f72d05591 100644
--- a/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/Dom.java
+++ b/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/Dom.java
@@ -57,6 +57,17 @@ public interface Dom {
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";
+
+ /**
+ * 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";
+
/**
* 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
diff --git a/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/Xpp3Dom.java b/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/Xpp3Dom.java
index 933a67366..4373f3988 100644
--- a/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/Xpp3Dom.java
+++ b/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/Xpp3Dom.java
@@ -29,6 +29,7 @@ import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -180,8 +181,6 @@ public class Xpp3Dom implements Serializable, Dom {
* </ol></li>
* <li> If mergeSelf == true
* <ol type="A">
- * <li> if the dominant root node's value is empty, set it to the recessive root node's value</li>
- * <li> For each attribute in the recessive root node which is not set in the dominant root node, set it.</li>
* <li> Determine whether children from the recessive DOM will be merged or appended to the dominant DOM as
* siblings (flag=mergeChildren).
* <ol type="i">
@@ -222,16 +221,11 @@ public class Xpp3Dom implements Serializable, Dom {
if (mergeSelf) {
- String value = null;
- Object location = null;
+ String value = dominant.getValue();
+ Object location = dominant.getInputLocation();
Map<String, String> attrs = null;
List<Dom> children = null;
- if (isEmpty(dominant.getValue()) && !isEmpty(recessive.getValue())) {
- value = recessive.getValue();
- location = recessive.getInputLocation();
- }
-
for (Map.Entry<String, String> attr : recessive.getAttributes().entrySet()) {
String key = attr.getKey();
if (isEmpty(dominant.getAttribute(key)) && !SELF_COMBINATION_MODE_ATTRIBUTE.equals(key)) {
@@ -253,25 +247,55 @@ public class Xpp3Dom implements Serializable, Dom {
}
}
- if (!mergeChildren) {
- children = new ArrayList<>(recessive.getChildren().size()
- + dominant.getChildren().size());
- children.addAll(recessive.getChildren());
- children.addAll(dominant.getChildren());
- } else {
- Map<String, Iterator<Dom>> commonChildren = new HashMap<>();
- Set<String> names =
- recessive.getChildren().stream().map(Dom::getName).collect(Collectors.toSet());
- for (String name : names) {
- List<Dom> dominantChildren = dominant.getChildren().stream()
- .filter(n -> n.getName().equals(name))
- .collect(Collectors.toList());
- if (dominantChildren.size() > 0) {
- commonChildren.put(name, dominantChildren.iterator());
+ String keysValue = recessive.getAttribute(KEYS_COMBINATION_MODE_ATTRIBUTE);
+
+ for (Dom recessiveChild : recessive.getChildren()) {
+ String idValue = recessiveChild.getAttribute(ID_COMBINATION_MODE_ATTRIBUTE);
+
+ Dom childDom = null;
+ if (isNotEmpty(idValue)) {
+ for (Dom dominantChild : dominant.getChildren()) {
+ if (idValue.equals(dominantChild.getAttribute(ID_COMBINATION_MODE_ATTRIBUTE))) {
+ childDom = dominantChild;
+ // we have a match, so don't append but merge
+ mergeChildren = true;
+ }
}
+ } else if (isNotEmpty(keysValue)) {
+ String[] keys = keysValue.split(",");
+ Map<String, Optional<String>> recessiveKeyValues = Stream.of(keys)
+ .collect(Collectors.toMap(
+ k -> k, k -> Optional.ofNullable(recessiveChild.getAttribute(k))));
+
+ for (Dom dominantChild : dominant.getChildren()) {
+ Map<String, Optional<String>> dominantKeyValues = Stream.of(keys)
+ .collect(Collectors.toMap(
+ k -> k, k -> Optional.ofNullable(dominantChild.getAttribute(k))));
+
+ if (recessiveKeyValues.equals(dominantKeyValues)) {
+ childDom = dominantChild;
+ // we have a match, so don't append but merge
+ mergeChildren = true;
+ }
+ }
+ } else {
+ childDom = dominant.getChild(recessiveChild.getName());
}
- for (Dom recessiveChild : recessive.getChildren()) {
+ if (mergeChildren && childDom != null) {
+ Map<String, Iterator<Dom>> commonChildren = new HashMap<>();
+ Set<String> names = recessive.getChildren().stream()
+ .map(Dom::getName)
+ .collect(Collectors.toSet());
+ for (String name : names) {
+ List<Dom> dominantChildren = dominant.getChildren().stream()
+ .filter(n -> n.getName().equals(name))
+ .collect(Collectors.toList());
+ if (dominantChildren.size() > 0) {
+ commonChildren.put(name, dominantChildren.iterator());
+ }
+ }
+
String name = recessiveChild.getName();
Iterator<Dom> it =
commonChildren.computeIfAbsent(name, n1 -> Stream.of(dominant.getChildren().stream()
@@ -297,7 +321,7 @@ public class Xpp3Dom implements Serializable, Dom {
}
children.remove(dominantChild);
} else {
- int idx = (children != null ? children : dominant.getChildren()).indexOf(dominantChild);
+ int idx = dominant.getChildren().indexOf(dominantChild);
Dom merged = merge(dominantChild, recessiveChild, childMergeOverride);
if (merged != dominantChild) {
if (children == null) {
@@ -307,6 +331,14 @@ public class Xpp3Dom implements Serializable, Dom {
}
}
}
+ } else {
+ if (children == null) {
+ children = new ArrayList<>(dominant.getChildren());
+ }
+ int idx = mergeChildren
+ ? children.size()
+ : recessive.getChildren().indexOf(recessiveChild);
+ children.add(idx, recessiveChild);
}
}
}
@@ -381,11 +413,11 @@ public class Xpp3Dom implements Serializable, Dom {
return writer.toString();
}
- public static boolean isNotEmpty(String str) {
+ private static boolean isNotEmpty(String str) {
return ((str != null) && (str.length() > 0));
}
- public static boolean isEmpty(String str) {
- return ((str == null) || (str.trim().length() == 0));
+ private static boolean isEmpty(String str) {
+ return ((str == null) || (str.length() == 0));
}
}
diff --git a/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/Xpp3DomBuilder.java b/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/Xpp3DomBuilder.java
index 4b7917528..077efca5b 100644
--- a/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/Xpp3DomBuilder.java
+++ b/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/Xpp3DomBuilder.java
@@ -129,8 +129,10 @@ public class Xpp3DomBuilder {
Map<String, String> attrs = null;
List<Dom> children = null;
int eventType = parser.getEventType();
+ boolean emptyTag = false;
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
+ emptyTag = parser.isEmptyElementTag();
if (name == null) {
name = parser.getName();
location = locationBuilder != null ? locationBuilder.toInputLocation(parser) : null;
@@ -158,7 +160,12 @@ public class Xpp3DomBuilder {
}
value = value != null ? value + text : text;
} else if (eventType == XmlPullParser.END_TAG) {
- return new Xpp3Dom(name, children == null ? value : null, attrs, children, location);
+ return new Xpp3Dom(
+ name,
+ children == null ? (value != null ? value : emptyTag ? null : "") : null,
+ attrs,
+ children,
+ location);
}
eventType = parser.next();
}
diff --git a/maven-xml-impl/src/test/java/org/apache/maven/internal/xml/Xpp3DomTest.java b/maven-xml-impl/src/test/java/org/apache/maven/internal/xml/Xpp3DomTest.java
new file mode 100644
index 000000000..4abd156cc
--- /dev/null
+++ b/maven-xml-impl/src/test/java/org/apache/maven/internal/xml/Xpp3DomTest.java
@@ -0,0 +1,188 @@
+/*
+ * 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.internal.xml;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.apache.maven.api.xml.Dom;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.junit.jupiter.api.Test;
+
+public class Xpp3DomTest {
+
+ /**
+ * <p>testCombineId.</p>
+ *
+ * @throws java.lang.Exception if any.
+ */
+ @Test
+ public void testCombineId() throws Exception {
+ String lhs = "<props>" + "<property combine.id='LHS-ONLY'><name>LHS-ONLY</name><value>LHS</value></property>"
+ + "<property combine.id='TOOVERWRITE'><name>TOOVERWRITE</name><value>LHS</value></property>"
+ + "</props>";
+
+ String rhs = "<props>" + "<property combine.id='RHS-ONLY'><name>RHS-ONLY</name><value>RHS</value></property>"
+ + "<property combine.id='TOOVERWRITE'><name>TOOVERWRITE</name><value>RHS</value></property>"
+ + "</props>";
+
+ Xpp3Dom leftDom = Xpp3DomBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left"));
+ Xpp3Dom rightDom = Xpp3DomBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right"));
+
+ Dom mergeResult = Xpp3Dom.merge(leftDom, rightDom, true);
+ assertEquals(3, getChildren(mergeResult, "property").size());
+
+ Dom p0 = getNthChild(mergeResult, "property", 0);
+ assertEquals("LHS-ONLY", p0.getChild("name").getValue());
+ assertEquals("left", p0.getChild("name").getInputLocation());
+ assertEquals("LHS", p0.getChild("value").getValue());
+ assertEquals("left", p0.getChild("value").getInputLocation());
+
+ Dom p1 = getNthChild(mergeResult, "property", 1);
+ assertEquals(
+ "TOOVERWRITE",
+ getNthChild(mergeResult, "property", 1).getChild("name").getValue());
+ assertEquals("left", p1.getChild("name").getInputLocation());
+ assertEquals(
+ "LHS", getNthChild(mergeResult, "property", 1).getChild("value").getValue());
+ assertEquals("left", p1.getChild("value").getInputLocation());
+
+ Dom p2 = getNthChild(mergeResult, "property", 2);
+ assertEquals(
+ "RHS-ONLY",
+ getNthChild(mergeResult, "property", 2).getChild("name").getValue());
+ assertEquals("right", p2.getChild("name").getInputLocation());
+ assertEquals(
+ "RHS", getNthChild(mergeResult, "property", 2).getChild("value").getValue());
+ assertEquals("right", p2.getChild("value").getInputLocation());
+ }
+
+ /**
+ * <p>testCombineKeys.</p>
+ *
+ * @throws java.lang.Exception if any.
+ */
+ @Test
+ public void testCombineKeys() throws Exception {
+ String lhs = "<props combine.keys='key'>"
+ + "<property key=\"LHS-ONLY\"><name>LHS-ONLY</name><value>LHS</value></property>"
+ + "<property combine.keys='name'><name>TOOVERWRITE</name><value>LHS</value></property>" + "</props>";
+
+ String rhs = "<props combine.keys='key'>"
+ + "<property key=\"RHS-ONLY\"><name>RHS-ONLY</name><value>RHS</value></property>"
+ + "<property combine.keys='name'><name>TOOVERWRITE</name><value>RHS</value></property>" + "</props>";
+
+ Xpp3Dom leftDom = Xpp3DomBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left"));
+ Xpp3Dom rightDom = Xpp3DomBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right"));
+
+ Dom mergeResult = Xpp3Dom.merge(leftDom, rightDom, true);
+ assertEquals(3, getChildren(mergeResult, "property").size());
+
+ Dom p0 = getNthChild(mergeResult, "property", 0);
+ assertEquals("LHS-ONLY", p0.getChild("name").getValue());
+ assertEquals("left", p0.getChild("name").getInputLocation());
+ assertEquals("LHS", p0.getChild("value").getValue());
+ assertEquals("left", p0.getChild("value").getInputLocation());
+
+ Dom p1 = getNthChild(mergeResult, "property", 1);
+ assertEquals(
+ "TOOVERWRITE",
+ getNthChild(mergeResult, "property", 1).getChild("name").getValue());
+ assertEquals("left", p1.getChild("name").getInputLocation());
+ assertEquals(
+ "LHS", getNthChild(mergeResult, "property", 1).getChild("value").getValue());
+ assertEquals("left", p1.getChild("value").getInputLocation());
+
+ Dom p2 = getNthChild(mergeResult, "property", 2);
+ assertEquals(
+ "RHS-ONLY",
+ getNthChild(mergeResult, "property", 2).getChild("name").getValue());
+ assertEquals("right", p2.getChild("name").getInputLocation());
+ assertEquals(
+ "RHS", getNthChild(mergeResult, "property", 2).getChild("value").getValue());
+ assertEquals("right", p2.getChild("value").getInputLocation());
+ }
+
+ @Test
+ public void testPreserveDominantBlankValue() throws XmlPullParserException, IOException {
+ String lhs = "<parameter xml:space=\"preserve\"> </parameter>";
+
+ String rhs = "<parameter>recessive</parameter>";
+
+ Xpp3Dom leftDom = Xpp3DomBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left"));
+ Xpp3Dom rightDom = Xpp3DomBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right"));
+
+ Dom mergeResult = Xpp3Dom.merge(leftDom, rightDom, true);
+ assertEquals(" ", mergeResult.getValue());
+ }
+
+ @Test
+ public void testPreserveDominantEmptyNode() throws XmlPullParserException, IOException {
+ String lhs = "<parameter></parameter>";
+
+ String rhs = "<parameter>recessive</parameter>";
+
+ Xpp3Dom leftDom = Xpp3DomBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left"));
+ Xpp3Dom rightDom = Xpp3DomBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right"));
+
+ Dom mergeResult = Xpp3Dom.merge(leftDom, rightDom, true);
+ assertEquals("", mergeResult.getValue());
+ }
+
+ @Test
+ public void testPreserveDominantEmptyNode2() throws XmlPullParserException, IOException {
+ String lhs = "<parameter/>";
+
+ String rhs = "<parameter>recessive</parameter>";
+
+ Xpp3Dom leftDom = Xpp3DomBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left"));
+ Xpp3Dom rightDom = Xpp3DomBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right"));
+
+ Dom mergeResult = Xpp3Dom.merge(leftDom, rightDom, true);
+ assertEquals(null, mergeResult.getValue());
+ }
+
+ private static List<Dom> getChildren(Dom node, String name) {
+ return node.getChildren().stream().filter(n -> n.getName().equals(name)).collect(Collectors.toList());
+ }
+
+ private static Dom getNthChild(Dom node, String name, int nth) {
+ return node.getChildren().stream()
+ .filter(n -> n.getName().equals(name))
+ .skip(nth)
+ .findFirst()
+ .orElse(null);
+ }
+
+ private static class FixedInputLocationBuilder implements Xpp3DomBuilder.InputLocationBuilder {
+ private final Object location;
+
+ public FixedInputLocationBuilder(Object location) {
+ this.location = location;
+ }
+
+ public Object toInputLocation(XmlPullParser parser) {
+ return location;
+ }
+ }
+}
diff --git a/pom.xml b/pom.xml
index 3da131289..7ce89d792 100644
--- a/pom.xml
+++ b/pom.xml
@@ -157,7 +157,7 @@ under the License.
<plexusVersion>2.1.0</plexusVersion>
<plexusInterpolationVersion>1.26</plexusInterpolationVersion>
<plexusUtilsVersion>4.0.0-alpha-3-SNAPSHOT</plexusUtilsVersion>
- <plexusUtilsVersionEmbedded>3.4.2</plexusUtilsVersionEmbedded>
+ <plexusUtilsVersionEmbedded>3.5.0</plexusUtilsVersionEmbedded>
<guiceVersion>5.1.0</guiceVersion>
<guavaVersion>30.1-jre</guavaVersion>
<guavafailureaccessVersion>1.0.1</guavafailureaccessVersion>