This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 650e182efde3 CAMEL-25231: camel-cxf - Type converter: regression tests 
for the source type chosen for a CachedCxfPayload (#28652)
650e182efde3 is described below

commit 650e182efde3a3b3fd929efe49c7bee38334a567
Author: Adriano Machado <[email protected]>
AuthorDate: Sun Nov 1 08:08:04 2026 -0500

    CAMEL-25231: camel-cxf - Type converter: regression tests for the source 
type chosen for a CachedCxfPayload (#28652)
    
    Co-authored-by: Claude Opus 5.5 <[email protected]>
---
 .../cxf/converter/CachedCxfPayloadTest.java        | 65 ++++++++++++++++++++++
 .../converter/TypeConverterLookupCacheTest.java    | 58 +++++++++++++++++++
 2 files changed, 123 insertions(+)

diff --git 
a/components/camel-cxf/camel-cxf-soap/src/test/java/org/apache/camel/component/cxf/converter/CachedCxfPayloadTest.java
 
b/components/camel-cxf/camel-cxf-soap/src/test/java/org/apache/camel/component/cxf/converter/CachedCxfPayloadTest.java
index b04f9891fa0a..344954fdedf8 100644
--- 
a/components/camel-cxf/camel-cxf-soap/src/test/java/org/apache/camel/component/cxf/converter/CachedCxfPayloadTest.java
+++ 
b/components/camel-cxf/camel-cxf-soap/src/test/java/org/apache/camel/component/cxf/converter/CachedCxfPayloadTest.java
@@ -19,27 +19,42 @@ package org.apache.camel.component.cxf.converter;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
 
 import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.Source;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.sax.SAXSource;
 import javax.xml.transform.stax.StAXSource;
 import javax.xml.transform.stream.StreamSource;
 
+import org.w3c.dom.Document;
+
 import org.apache.camel.NoTypeConversionAvailableException;
+import org.apache.camel.StreamCache;
 import org.apache.camel.TypeConversionException;
+import org.apache.camel.TypeConverter;
 import org.apache.camel.component.cxf.common.CxfPayload;
+import org.apache.camel.language.xpath.XPathBuilder;
+import org.apache.camel.spi.TypeConverterRegistry;
 import org.apache.camel.test.junit6.ExchangeTestSupport;
 import org.apache.cxf.staxutils.StaxSource;
 import org.apache.cxf.staxutils.StaxUtils;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 public class CachedCxfPayloadTest extends ExchangeTestSupport {
     private static final String PAYLOAD = "<foo>bar<![CDATA[ & a cdata section 
]]></foo>";
     private static final String PAYLOAD_AMPED = "<foo>bar &amp; a cdata 
section </foo>";
+    private static final String NS_PAYLOAD_NAMESPACE = "urn:camel:test";
+    private static final String NS_PAYLOAD = "<foo xmlns=\"" + 
NS_PAYLOAD_NAMESPACE + "\"><bar>baz</bar></foo>";
 
     @Test
     public void testCachedCxfPayloadSAXSource()
@@ -79,6 +94,56 @@ public class CachedCxfPayloadTest extends 
ExchangeTestSupport {
         doTest(source, PAYLOAD);
     }
 
+    @Test
+    public void testCachedCxfPayloadUsesTheStreamCacheConverters() {
+        TypeConverterRegistry registry = context.getTypeConverterRegistry();
+        // CAMEL-25231: a CachedCxfPayload is both a StreamCache and a 
CxfPayload, and both have converters to the XML
+        // sources. The interface is tried before the super class, so the 
StreamCache converters must always be chosen,
+        // whatever the order of the converters in the registry, which can 
change between JVM runs
+        for (Class<?> type : List.of(Source.class, SAXSource.class, 
DOMSource.class, StAXSource.class,
+                StreamSource.class, Document.class)) {
+            TypeConverter fromStreamCache = registry.lookup(type, 
StreamCache.class);
+            assertNotNull(fromStreamCache, "no converter from StreamCache to " 
+ type.getName());
+            assertNotSame(registry.lookup(type, CxfPayload.class), 
fromStreamCache);
+            assertSame(fromStreamCache, registry.lookup(type, 
CachedCxfPayload.class), type.getName());
+        }
+    }
+
+    @Test
+    public void testCachedCxfPayloadToDOMSourceHoldsTheDocument() throws 
Exception {
+        // CAMEL-25231: the DOMSource must hold the document, not its document 
element, as the xslt, xquery and
+        // validator components then evaluate from another context node (see 
CAMEL-25224)
+        for (CachedCxfPayload<?> cache : List.of(cachedDomPayload(), 
cachedStaxPayload())) {
+            DOMSource source = 
context.getTypeConverter().mandatoryConvertTo(DOMSource.class, exchange, cache);
+            Document document = assertInstanceOf(Document.class, 
source.getNode());
+            assertEquals("foo", document.getDocumentElement().getLocalName());
+        }
+    }
+
+    @Test
+    public void testXPathOnCachedCxfPayload() throws Exception {
+        for (CachedCxfPayload<?> cache : List.of(cachedDomPayload(), 
cachedStaxPayload())) {
+            exchange.getIn().setBody(cache);
+            String value = XPathBuilder.xpath("/x:foo/x:bar").namespace("x", 
NS_PAYLOAD_NAMESPACE).stringResult()
+                    .evaluate(exchange, String.class);
+            assertEquals("baz", value);
+        }
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private CachedCxfPayload<?> cachedDomPayload() throws Exception {
+        List<Source> body = new ArrayList<>();
+        body.add(new DOMSource(StaxUtils.read(new 
StringReader(NS_PAYLOAD)).getDocumentElement()));
+        return new CachedCxfPayload(new CxfPayload(null, body, null), 
exchange);
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private CachedCxfPayload<?> cachedStaxPayload() {
+        List<Source> body = new ArrayList<>();
+        body.add(new StaxSource(StaxUtils.createXMLStreamReader(new 
StreamSource(new StringReader(NS_PAYLOAD)))));
+        return new CachedCxfPayload(new CxfPayload(null, body, null), 
exchange);
+    }
+
     @SuppressWarnings({ "unchecked", "rawtypes" })
     private void doTest(Object source, String payload) throws IOException {
         CxfPayload<?> originalPayload = 
context.getTypeConverter().convertTo(CxfPayload.class, source);
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/converter/TypeConverterLookupCacheTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/converter/TypeConverterLookupCacheTest.java
index 053a43230a58..86a6d6afe3c8 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/converter/TypeConverterLookupCacheTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/converter/TypeConverterLookupCacheTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.converter;
 
+import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.camel.Exchange;
@@ -125,6 +126,63 @@ public class TypeConverterLookupCacheTest {
                 cause.getMessage());
     }
 
+    @Test
+    public void testCachedLookupFromInterfaceAndSuperClassIsDeterministic() {
+        // CAMEL-25231: like CachedCxfPayload (a CxfPayload that implements 
StreamCache), both the interface and the super
+        // class have a type converter. The interface is nearer, so lookup and 
convertTo must both choose its converter,
+        // whatever the order the type converters were added in, and the 
cached lookup must keep that choice
+        for (boolean interfaceFirst : List.of(true, false)) {
+            AtomicInteger fromCacheCalls = new AtomicInteger();
+            AtomicInteger fromPayloadCalls = new AtomicInteger();
+            TypeConverter fromCache = new CountingFooConverter(fromCacheCalls);
+            TypeConverter fromPayload = new 
CountingFooConverter(fromPayloadCalls);
+
+            DefaultTypeConverter fresh = new DefaultTypeConverter(
+                    new DefaultPackageScanClassResolver(), new 
DefaultInjector(new DefaultCamelContext()), true, false);
+            ServiceHelper.startService(fresh);
+            try {
+                if (interfaceFirst) {
+                    fresh.addTypeConverter(Foo.class, Cache.class, fromCache);
+                    fresh.addTypeConverter(Foo.class, Payload.class, 
fromPayload);
+                } else {
+                    fresh.addTypeConverter(Foo.class, Payload.class, 
fromPayload);
+                    fresh.addTypeConverter(Foo.class, Cache.class, fromCache);
+                }
+
+                assertSame(fromCache, fresh.lookup(Foo.class, 
CachedPayload.class));
+                assertNotNull(fresh.convertTo(Foo.class, new CachedPayload()));
+                assertEquals(1, fromCacheCalls.get());
+                assertEquals(0, fromPayloadCalls.get());
+                assertSame(fromCache, fresh.lookup(Foo.class, 
CachedPayload.class));
+            } finally {
+                ServiceHelper.stopService(fresh);
+            }
+        }
+    }
+
+    private interface Cache {
+    }
+
+    private static class Payload {
+    }
+
+    private static final class CachedPayload extends Payload implements Cache {
+    }
+
+    private static final class CountingFooConverter extends 
TypeConverterSupport {
+        private final AtomicInteger calls;
+
+        private CountingFooConverter(AtomicInteger calls) {
+            this.calls = calls;
+        }
+
+        @Override
+        public <T> T convertTo(Class<T> type, Exchange exchange, Object value) 
{
+            calls.incrementAndGet();
+            return type == Foo.class ? type.cast(new Foo()) : null;
+        }
+    }
+
     @Test
     public void testTryConvertToEnumTriesTheDirectTypeConverter() throws 
Exception {
         // trying to convert to an enum must not let a direct type converter 
throw an exception that is only ignored

Reply via email to