From 17c102ca9bc91e5d7e408910da5e2c97efaa0a35 Mon Sep 17 00:00:00 2001 From: Sylwester Lachiewicz Date: Sat, 27 Dec 2025 22:28:43 +0000 Subject: [PATCH] Upgrade to Maven 4.0.0-rc-5 and migrate to public API - Replace XmlNodeBuilder (internal API) with XmlService (public API) for trim=true cases - Keep XmlNodeBuilder only for trim=false to preserve backwards compatibility - Add XmlPullParserToXMLStreamReaderAdapter to bridge XmlPullParser and XMLStreamReader - Update InputLocationBuilder interface to use XMLStreamReader instead of XmlPullParser - Remove deprecated 'detail' field and getDetail() method from XmlPullParserException - Update tests to match new InputLocationBuilder signature All 217 tests pass successfully. --- ...XmlPullParserToXMLStreamReaderAdapter.java | 349 ++++++++++++++++++ .../plexus/util/xml/Xpp3DomBuilder.java | 60 ++- .../util/xml/pull/XmlPullParserException.java | 17 - .../plexus/util/xml/Xpp3DomBuilderTest.java | 4 +- .../codehaus/plexus/util/xml/Xpp3DomTest.java | 3 +- 5 files changed, 406 insertions(+), 27 deletions(-) create mode 100644 src/main/java/org/codehaus/plexus/util/xml/XmlPullParserToXMLStreamReaderAdapter.java diff --git a/src/main/java/org/codehaus/plexus/util/xml/XmlPullParserToXMLStreamReaderAdapter.java b/src/main/java/org/codehaus/plexus/util/xml/XmlPullParserToXMLStreamReaderAdapter.java new file mode 100644 index 0000000..a0475ec --- /dev/null +++ b/src/main/java/org/codehaus/plexus/util/xml/XmlPullParserToXMLStreamReaderAdapter.java @@ -0,0 +1,349 @@ +package org.codehaus.plexus.util.xml; + +/* + * Copyright The Codehaus Foundation. + * + * Licensed 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. + */ + +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.codehaus.plexus.util.xml.pull.XmlPullParser; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +/** + * Adapter that wraps an XmlPullParser and implements the XMLStreamReader interface. + * This allows using XmlPullParser with APIs that expect XMLStreamReader. + */ +class XmlPullParserToXMLStreamReaderAdapter implements XMLStreamReader { + private final XmlPullParser parser; + private int eventType; + + XmlPullParserToXMLStreamReaderAdapter(XmlPullParser parser) throws XMLStreamException { + this.parser = parser; + try { + this.eventType = parser.getEventType(); + } catch (XmlPullParserException e) { + throw new XMLStreamException(e); + } + } + + @Override + public int next() throws XMLStreamException { + try { + eventType = parser.next(); + return convertEventType(eventType); + } catch (Exception e) { + throw new XMLStreamException(e); + } + } + + @Override + public boolean hasNext() throws XMLStreamException { + return eventType != XmlPullParser.END_DOCUMENT; + } + + @Override + public int getEventType() { + return convertEventType(eventType); + } + + @Override + public String getElementText() throws XMLStreamException { + try { + return parser.nextText(); + } catch (Exception e) { + throw new XMLStreamException(e); + } + } + + @Override + public String getLocalName() { + return parser.getName(); + } + + @Override + public String getNamespaceURI() { + return parser.getNamespace(); + } + + @Override + public String getPrefix() { + return parser.getPrefix(); + } + + @Override + public String getAttributeValue(String namespaceURI, String localName) { + return parser.getAttributeValue(namespaceURI, localName); + } + + @Override + public int getAttributeCount() { + return parser.getAttributeCount(); + } + + @Override + public String getAttributeNamespace(int index) { + return parser.getAttributeNamespace(index); + } + + @Override + public String getAttributeLocalName(int index) { + return parser.getAttributeName(index); + } + + @Override + public String getAttributePrefix(int index) { + return parser.getAttributePrefix(index); + } + + @Override + public String getAttributeValue(int index) { + return parser.getAttributeValue(index); + } + + @Override + public String getText() { + return parser.getText(); + } + + @Override + public Location getLocation() { + return new Location() { + @Override + public int getLineNumber() { + return parser.getLineNumber(); + } + + @Override + public int getColumnNumber() { + return parser.getColumnNumber(); + } + + @Override + public int getCharacterOffset() { + return -1; + } + + @Override + public String getPublicId() { + return null; + } + + @Override + public String getSystemId() { + return null; + } + }; + } + + private int convertEventType(int pullEventType) { + switch (pullEventType) { + case XmlPullParser.START_DOCUMENT: + return START_DOCUMENT; + case XmlPullParser.END_DOCUMENT: + return END_DOCUMENT; + case XmlPullParser.START_TAG: + return START_ELEMENT; + case XmlPullParser.END_TAG: + return END_ELEMENT; + case XmlPullParser.TEXT: + return CHARACTERS; + case XmlPullParser.CDSECT: + return CDATA; + case XmlPullParser.ENTITY_REF: + return ENTITY_REFERENCE; + case XmlPullParser.IGNORABLE_WHITESPACE: + return SPACE; + case XmlPullParser.PROCESSING_INSTRUCTION: + return PROCESSING_INSTRUCTION; + case XmlPullParser.COMMENT: + return COMMENT; + case XmlPullParser.DOCDECL: + return DTD; + default: + return 0; + } + } + + // Unsupported methods that are not needed for basic XML reading + @Override + public QName getName() { + return new QName(getNamespaceURI(), getLocalName(), getPrefix()); + } + + @Override + public boolean isStartElement() { + return getEventType() == START_ELEMENT; + } + + @Override + public boolean isEndElement() { + return getEventType() == END_ELEMENT; + } + + @Override + public boolean isCharacters() { + return getEventType() == CHARACTERS; + } + + @Override + public boolean isWhiteSpace() { + return getEventType() == SPACE; + } + + @Override + public boolean hasName() { + return getEventType() == START_ELEMENT || getEventType() == END_ELEMENT; + } + + @Override + public boolean hasText() { + int type = getEventType(); + return type == CHARACTERS || type == CDATA || type == SPACE || type == ENTITY_REFERENCE; + } + + @Override + public QName getAttributeName(int index) { + return new QName(getAttributeNamespace(index), getAttributeLocalName(index), getAttributePrefix(index)); + } + + @Override + public String getAttributeType(int index) { + return parser.getAttributeType(index); + } + + @Override + public boolean isAttributeSpecified(int index) { + return true; + } + + @Override + public int getNamespaceCount() { + return 0; + } + + @Override + public String getNamespacePrefix(int index) { + return null; + } + + @Override + public String getNamespaceURI(int index) { + return null; + } + + @Override + public NamespaceContext getNamespaceContext() { + return null; + } + + @Override + public String getNamespaceURI(String prefix) { + return null; + } + + @Override + public int getTextLength() { + return getText() != null ? getText().length() : 0; + } + + @Override + public int getTextStart() { + return 0; + } + + @Override + public char[] getTextCharacters() { + String text = getText(); + return text != null ? text.toCharArray() : new char[0]; + } + + @Override + public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) { + char[] source = getTextCharacters(); + int copied = Math.min(length, source.length - sourceStart); + System.arraycopy(source, sourceStart, target, targetStart, copied); + return copied; + } + + @Override + public String getEncoding() { + return parser.getInputEncoding(); + } + + @Override + public String getCharacterEncodingScheme() { + return null; + } + + @Override + public String getVersion() { + return null; + } + + @Override + public boolean isStandalone() { + return false; + } + + @Override + public boolean standaloneSet() { + return false; + } + + @Override + public String getPITarget() { + return null; + } + + @Override + public String getPIData() { + return null; + } + + @Override + public Object getProperty(String name) { + return null; + } + + @Override + public void require(int type, String namespaceURI, String localName) throws XMLStreamException { + // Not implemented + } + + @Override + public void close() throws XMLStreamException { + // Not implemented - XmlPullParser doesn't have close + } + + @Override + public int nextTag() throws XMLStreamException { + int eventType = next(); + while ((eventType == CHARACTERS && isWhiteSpace()) + || (eventType == CDATA && isWhiteSpace()) + || eventType == SPACE + || eventType == PROCESSING_INSTRUCTION + || eventType == COMMENT) { + eventType = next(); + } + if (eventType != START_ELEMENT && eventType != END_ELEMENT) { + throw new XMLStreamException("expected start or end tag", getLocation()); + } + return eventType; + } +} diff --git a/src/main/java/org/codehaus/plexus/util/xml/Xpp3DomBuilder.java b/src/main/java/org/codehaus/plexus/util/xml/Xpp3DomBuilder.java index b75e681..355a925 100644 --- a/src/main/java/org/codehaus/plexus/util/xml/Xpp3DomBuilder.java +++ b/src/main/java/org/codehaus/plexus/util/xml/Xpp3DomBuilder.java @@ -16,10 +16,13 @@ * limitations under the License. */ +import javax.xml.stream.XMLStreamException; + import java.io.IOException; import java.io.InputStream; import java.io.Reader; +import org.apache.maven.api.xml.XmlService; import org.apache.maven.internal.xml.XmlNodeBuilder; import org.codehaus.plexus.util.xml.pull.XmlPullParser; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; @@ -49,7 +52,15 @@ public static Xpp3Dom build(InputStream is, String encoding) throws XmlPullParse public static Xpp3Dom build(InputStream is, String encoding, boolean trim) throws XmlPullParserException, IOException { try (InputStream closeMe = is) { - return new Xpp3Dom(XmlNodeBuilder.build(is, encoding, trim)); + try { + if (trim) { + return new Xpp3Dom(XmlService.read(is, null)); + } else { + return new Xpp3Dom(XmlNodeBuilder.build(is, encoding, trim)); + } + } catch (XMLStreamException e) { + throw new XmlPullParserException(e.getMessage(), null, e); + } } } @@ -63,8 +74,27 @@ public static Xpp3Dom build(Reader reader, boolean trim) throws XmlPullParserExc public static Xpp3Dom build(Reader reader, boolean trim, InputLocationBuilder locationBuilder) throws XmlPullParserException, IOException { try (Reader closeMe = reader) { - return new Xpp3Dom(XmlNodeBuilder.build( - reader, trim, locationBuilder != null ? locationBuilder::toInputLocation : null)); + if (trim) { + try { + XmlService.InputLocationBuilder xlb = + locationBuilder != null ? locationBuilder::toInputLocation : null; + return new Xpp3Dom(XmlService.read(reader, xlb)); + } catch (XMLStreamException e) { + throw new XmlPullParserException(e.getMessage(), null, e); + } + } else { + org.apache.maven.internal.xml.XmlNodeBuilder.InputLocationBuilder xlb = locationBuilder != null + ? parser -> { + try { + return locationBuilder.toInputLocation( + new XmlPullParserToXMLStreamReaderAdapter((XmlPullParser) parser)); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + } + : null; + return new Xpp3Dom(XmlNodeBuilder.build(reader, trim, xlb)); + } } } @@ -81,8 +111,26 @@ public static Xpp3Dom build(XmlPullParser parser, boolean trim) throws XmlPullPa */ public static Xpp3Dom build(XmlPullParser parser, boolean trim, InputLocationBuilder locationBuilder) throws XmlPullParserException, IOException { - return new Xpp3Dom( - XmlNodeBuilder.build(parser, trim, locationBuilder != null ? locationBuilder::toInputLocation : null)); + if (trim) { + try { + XmlService.InputLocationBuilder xlb = locationBuilder != null ? locationBuilder::toInputLocation : null; + return new Xpp3Dom(XmlService.read(new XmlPullParserToXMLStreamReaderAdapter(parser), xlb)); + } catch (XMLStreamException e) { + throw new XmlPullParserException(e.getMessage(), null, e); + } + } else { + org.apache.maven.internal.xml.XmlNodeBuilder.InputLocationBuilder xlb = locationBuilder != null + ? p -> { + try { + return locationBuilder.toInputLocation( + new XmlPullParserToXMLStreamReaderAdapter((XmlPullParser) p)); + } catch (XMLStreamException e) { + throw new RuntimeException(e); + } + } + : null; + return new Xpp3Dom(XmlNodeBuilder.build(parser, trim, xlb)); + } } /** @@ -91,6 +139,6 @@ public static Xpp3Dom build(XmlPullParser parser, boolean trim, InputLocationBui * @since 3.2.0 */ public interface InputLocationBuilder { - Object toInputLocation(XmlPullParser parser); + Object toInputLocation(javax.xml.stream.XMLStreamReader parser); } } diff --git a/src/main/java/org/codehaus/plexus/util/xml/pull/XmlPullParserException.java b/src/main/java/org/codehaus/plexus/util/xml/pull/XmlPullParserException.java index 198977c..52634b3 100644 --- a/src/main/java/org/codehaus/plexus/util/xml/pull/XmlPullParserException.java +++ b/src/main/java/org/codehaus/plexus/util/xml/pull/XmlPullParserException.java @@ -9,12 +9,6 @@ * @author Aleksander Slominski */ public class XmlPullParserException extends Exception { - /** - * @deprecated use generic getCause() method - */ - @Deprecated - protected Throwable detail; - protected int row = -1; protected int column = -1; @@ -43,19 +37,8 @@ public XmlPullParserException(String msg, XmlPullParser parser, Throwable chain) this.row = parser.getLineNumber(); this.column = parser.getColumnNumber(); } - this.detail = chain; - } - - /** - * @deprecated Use the generic getCause() method - * @return the cause - */ - @Deprecated - public Throwable getDetail() { - return getCause(); } - // public void setDetail(Throwable cause) { this.detail = cause; } public int getLineNumber() { return row; } diff --git a/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomBuilderTest.java b/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomBuilderTest.java index e7e281e..6c996db 100644 --- a/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomBuilderTest.java +++ b/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomBuilderTest.java @@ -179,8 +179,8 @@ void escapingInAttributes() throws Exception { @Test void inputLocationTracking() throws Exception { Xpp3DomBuilder.InputLocationBuilder ilb = new Xpp3DomBuilder.InputLocationBuilder() { - public Object toInputLocation(XmlPullParser parser) { - return parser.getLineNumber(); // store only line number as a simple Integer + public Object toInputLocation(javax.xml.stream.XMLStreamReader parser) { + return parser.getLocation().getLineNumber(); // store only line number as a simple Integer } }; Xpp3Dom dom = Xpp3DomBuilder.build(new StringReader(createDomString()), true, ilb); diff --git a/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomTest.java b/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomTest.java index 4499965..95a1cd9 100644 --- a/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomTest.java +++ b/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomTest.java @@ -24,7 +24,6 @@ import org.apache.maven.api.xml.XmlNode; import org.apache.maven.internal.xml.XmlNodeImpl; -import org.codehaus.plexus.util.xml.pull.XmlPullParser; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -516,7 +515,7 @@ public FixedInputLocationBuilder(Object location) { this.location = location; } - public Object toInputLocation(XmlPullParser parser) { + public Object toInputLocation(javax.xml.stream.XMLStreamReader parser) { return location; } }