This is an automated email from the ASF dual-hosted git repository.
veithen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ws-axiom.git
The following commit(s) were added to refs/heads/master by this push:
new e05c8fd33 Introduce new CharacterData lifetime contract in
XmlHandler.processCharacterData
e05c8fd33 is described below
commit e05c8fd33a5ee5698bf04be8b026e4d8bc393fcb
Author: Copilot <[email protected]>
AuthorDate: Tue May 26 16:59:45 2026 +0100
Introduce new CharacterData lifetime contract in
XmlHandler.processCharacterData
This should enable the implementation of various optimizations.
Co-authored-by: Andreas Veithen-Knowles <[email protected]>
---
.../org/apache/axiom/core/stream/CharacterData.java | 17 +++++++++++++++++
.../java/org/apache/axiom/core/stream/XmlHandler.java | 4 ++++
.../axiom/core/stream/stax/pull/output/StAXPivot.java | 3 ++-
.../core/stream/util/CharacterDataAccumulator.java | 2 +-
.../axiom/core/impl/builder/BuildableContext.java | 5 +++--
.../java/org/apache/axiom/om/impl/intf/TextContent.java | 5 +++++
6 files changed, 32 insertions(+), 4 deletions(-)
diff --git
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/CharacterData.java
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/CharacterData.java
index 315fd024a..f66906b94 100644
---
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/CharacterData.java
+++
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/CharacterData.java
@@ -33,4 +33,21 @@ public interface CharacterData {
void writeTo(CharacterDataSink sink) throws IOException;
void appendTo(StringBuilder buffer);
+
+ /**
+ * Returns a {@link String} or a {@link CharacterData} instance that
remains valid beyond the
+ * current {@link XmlHandler#processCharacterData} invocation. If this
instance is already valid
+ * beyond that scope, implementations may return {@code this}.
+ *
+ * <p>The return type is {@link Object} because the value is either a
{@link String} or a
+ * {@link CharacterData}, consistent with the {@code data} parameter of
{@link
+ * XmlHandler#processCharacterData}.
+ *
+ * <p>Callers must invoke this method before storing a {@link
CharacterData} value beyond the
+ * duration of a {@link XmlHandler#processCharacterData} invocation.
+ *
+ * @return a {@link String} or {@link CharacterData} representation of
this instance that
+ * remains valid beyond the current invocation
+ */
+ Object retain();
}
diff --git
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/XmlHandler.java
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/XmlHandler.java
index ba17fa57d..3ce6f42d9 100644
---
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/XmlHandler.java
+++
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/XmlHandler.java
@@ -104,6 +104,10 @@ public interface XmlHandler {
* take advantage of its more efficient {@link
CharacterData#writeTo(CharacterDataSink)} and
* {@link CharacterData#appendTo(StringBuilder)} methods. The value is
never {@code null}.
*
+ * <p>When {@code data} is a {@link CharacterData} instance, the instance
is only valid for the
+ * duration of this invocation. Implementations that need to store the
value beyond the call
+ * must first invoke {@link CharacterData#retain()} to obtain a
permanently valid form.
+ *
* <p>The {@code ignorable} flag corresponds to the SAX distinction
between {@link
* org.xml.sax.ContentHandler#characters(char[], int, int)} and {@link
* org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)}: it
is {@code true} when
diff --git
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/stax/pull/output/StAXPivot.java
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/stax/pull/output/StAXPivot.java
index 4cd25b48a..d62483f9a 100644
---
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/stax/pull/output/StAXPivot.java
+++
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/stax/pull/output/StAXPivot.java
@@ -29,6 +29,7 @@ import javax.xml.namespace.QName;
import javax.xml.stream.Location;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
+import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.core.stream.StreamException;
import org.apache.axiom.core.stream.XmlHandler;
import org.apache.axiom.core.stream.XmlReader;
@@ -355,7 +356,7 @@ public final class StAXPivot implements
InternalXMLStreamReader, XmlHandler {
switch (state) {
case STATE_DEFAULT -> {
eventType = ignorable ? SPACE : CHARACTERS;
- characterData = data;
+ characterData = data instanceof CharacterData cd ? cd.retain()
: data;
state = STATE_EVENT_COMPLETE;
return;
}
diff --git
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/util/CharacterDataAccumulator.java
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/util/CharacterDataAccumulator.java
index d3a42b1cc..d9ca093f9 100644
---
a/components/core-streams/src/main/java/org/apache/axiom/core/stream/util/CharacterDataAccumulator.java
+++
b/components/core-streams/src/main/java/org/apache/axiom/core/stream/util/CharacterDataAccumulator.java
@@ -25,7 +25,7 @@ public class CharacterDataAccumulator {
public void append(Object data) {
if (content == null) {
- content = data;
+ content = data instanceof CharacterData cd ? cd.retain() : data;
} else {
StringBuilder buffer;
if (content instanceof StringBuilder stringBuilder) {
diff --git
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/BuildableContext.java
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/BuildableContext.java
index 63efcadac..8dc58a931 100644
---
a/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/BuildableContext.java
+++
b/mixins/core-mixins/src/main/java/org/apache/axiom/core/impl/builder/BuildableContext.java
@@ -36,6 +36,7 @@ import org.apache.axiom.core.CoreNamespaceDeclaration;
import org.apache.axiom.core.CoreParentNode;
import org.apache.axiom.core.CoreProcessingInstruction;
import org.apache.axiom.core.InputContext;
+import org.apache.axiom.core.stream.CharacterData;
import org.apache.axiom.core.stream.NullXmlHandler;
import org.apache.axiom.core.stream.StreamException;
import org.apache.axiom.core.stream.XmlHandler;
@@ -263,10 +264,10 @@ final class BuildableContext extends Context implements
InputContext {
if (passThroughHandler != null) {
passThroughHandler.processCharacterData(data, ignorable);
} else if (!ignorable && pendingCharacterData == null &&
target.coreGetFirstChildIfAvailable() == null) {
- pendingCharacterData = data;
+ pendingCharacterData = data instanceof CharacterData cd ?
cd.retain() : data;
} else {
CoreCharacterDataNode node =
builderHandler.nodeFactory.createCharacterDataNode();
- node.coreSetCharacterData(data);
+ node.coreSetCharacterData(data instanceof CharacterData cd ?
cd.retain() : data);
node.coreSetIgnorable(ignorable);
addChild(node);
}
diff --git
a/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/intf/TextContent.java
b/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/intf/TextContent.java
index 3012f872f..f4303f5ff 100644
---
a/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/intf/TextContent.java
+++
b/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/intf/TextContent.java
@@ -198,4 +198,9 @@ public final class TextContent implements
CloneableCharacterData {
buffer.append(value);
}
}
+
+ @Override
+ public Object retain() {
+ return this;
+ }
}