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;
+    }
 }

Reply via email to