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 & 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