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

davsclaus pushed a commit to branch backport/CAMEL-24573-4.18.x
in repository https://gitbox.apache.org/repos/asf/camel.git

commit c625191fdbcd032c26a807a292c1a2e974139c25
Author: Marco Carletti <[email protected]>
AuthorDate: Mon Aug 31 18:27:52 2026 +0200

    CAMEL-24573: CXF REST: UnsupportedOperationException when copying factory 
bean with fixed-size features list
    
    When creating a CXF JAXRS client factory bean from a Spring bean with a
    fixed-size features list (e.g., from Arrays.asList()), the shallow field 
copy
    resulted in a reference to the immutable list. Subsequent attempts to append
    endpoint features via addAll() threw UnsupportedOperationException.
    
    Wrap the copied features list in a new ArrayList to ensure mutability while
    preserving the original values.
    
    Fixes CSB-10555
    
    (cherry picked from commit 98615a5d003e19186b593b5c386770d42a4a1592)
    
    Deviations from a straight cherry-pick, both mechanical:
    
    - Import conflict resolved for this branch: CxfRsSpringEndpointTest keeps 
this
      branch's org.apache.camel.test.spring.junit5.CamelSpringTestSupport import
      rather than main's junit6 one; camel-cxf-spring-rest here depends on
      camel-test-spring-junit5, not junit6.
    - CxfRsSpringEndpoint.setupJAXRSClientFactoryBean() on this branch does not 
call
      setupCommonFactoryProperties() (that call was added later by CAMEL-24183,
      which is not on this branch), so the endpoint's own features are never
      auto-appended to the copied list here. The ported test's
      assertEquals(2, cfb.getFeatures().size()) does not hold on this branch: it
      now asserts the copied feature is preserved (1) and that the list is
      mutable by appending a second feature directly and re-checking the size 
(2),
      which still exercises the fix without relying on behaviour this branch
      doesn't have.
    
    Co-Authored-By: Claude Haiku 4.5 <[email protected]>
    Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
---
 .../cxf/spring/jaxrs/CxfRsSpringEndpoint.java      |  3 +++
 .../cxf/jaxrs/CxfRsSpringEndpointTest.java         | 29 ++++++++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git 
a/components/camel-cxf/camel-cxf-spring-rest/src/main/java/org/apache/camel/component/cxf/spring/jaxrs/CxfRsSpringEndpoint.java
 
b/components/camel-cxf/camel-cxf-spring-rest/src/main/java/org/apache/camel/component/cxf/spring/jaxrs/CxfRsSpringEndpoint.java
index 3697f7816e05..d513f4dd22e5 100644
--- 
a/components/camel-cxf/camel-cxf-spring-rest/src/main/java/org/apache/camel/component/cxf/spring/jaxrs/CxfRsSpringEndpoint.java
+++ 
b/components/camel-cxf/camel-cxf-spring-rest/src/main/java/org/apache/camel/component/cxf/spring/jaxrs/CxfRsSpringEndpoint.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.component.cxf.spring.jaxrs;
 
+import java.util.ArrayList;
+
 import org.apache.camel.Component;
 import org.apache.camel.component.cxf.jaxrs.BeanIdAware;
 import org.apache.camel.component.cxf.jaxrs.CxfRsEndpoint;
@@ -88,6 +90,7 @@ public class CxfRsSpringEndpoint extends CxfRsEndpoint 
implements BeanIdAware {
 
         if (bean instanceof SpringJAXRSClientFactoryBean) {
             ReflectionUtils.shallowCopyFieldState(bean, cfb);
+            cfb.setFeatures(new ArrayList<>(cfb.getFeatures()));
         }
 
         return cfb;
diff --git 
a/components/camel-cxf/camel-cxf-spring-rest/src/test/java/org/apache/camel/component/cxf/jaxrs/CxfRsSpringEndpointTest.java
 
b/components/camel-cxf/camel-cxf-spring-rest/src/test/java/org/apache/camel/component/cxf/jaxrs/CxfRsSpringEndpointTest.java
index 077ed721036f..4275465597c6 100644
--- 
a/components/camel-cxf/camel-cxf-spring-rest/src/test/java/org/apache/camel/component/cxf/jaxrs/CxfRsSpringEndpointTest.java
+++ 
b/components/camel-cxf/camel-cxf-spring-rest/src/test/java/org/apache/camel/component/cxf/jaxrs/CxfRsSpringEndpointTest.java
@@ -16,18 +16,21 @@
  */
 package org.apache.camel.component.cxf.jaxrs;
 
+import java.util.Arrays;
 import java.util.Map;
 
 import org.apache.camel.component.cxf.jaxrs.testbean.CustomerService;
 import 
org.apache.camel.component.cxf.spring.jaxrs.SpringJAXRSClientFactoryBean;
 import 
org.apache.camel.component.cxf.spring.jaxrs.SpringJAXRSServerFactoryBean;
 import org.apache.camel.test.spring.junit5.CamelSpringTestSupport;
+import org.apache.cxf.feature.AbstractFeature;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
 import org.springframework.context.support.AbstractXmlApplicationContext;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
 
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNotSame;
@@ -36,6 +39,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 public class CxfRsSpringEndpointTest extends CamelSpringTestSupport {
 
     private static final String BEAN_SERVICE_ENDPOINT_NAME = "serviceEndpoint";
+    private static final String FIXED_SIZE_FEATURES_ENDPOINT_NAME = 
"fixedSizeFeaturesEndpoint";
     private static final String BEAN_SERVICE_ADDRESS = 
"http://localhost/programmatically";;
     private static final String BEAN_SERVICE_USERNAME = 
"BEAN_SERVICE_USERNAME";
     private static final String BEAN_SERVICE_PASSWORD = 
"BEAN_SERVICE_PASSWORD";
@@ -88,6 +92,19 @@ public class CxfRsSpringEndpointTest extends 
CamelSpringTestSupport {
         assertEquals(BEAN_SERVICE_PASSWORD, cfb.getPassword(), "Got the wrong 
password");
     }
 
+    @Test
+    public void testCreateCxfRsClientFactoryBeanWithFixedSizeFeatures() {
+        CxfRsEndpoint endpoint = resolveMandatoryEndpoint(
+                "cxfrs://bean://" + FIXED_SIZE_FEATURES_ENDPOINT_NAME, 
CxfRsEndpoint.class);
+
+        SpringJAXRSClientFactoryBean cfb = (SpringJAXRSClientFactoryBean) 
endpoint.createJAXRSClientFactoryBean();
+
+        assertEquals(1, cfb.getFeatures().size(), "The copied feature must be 
preserved");
+        assertDoesNotThrow(() -> cfb.getFeatures().add(new AbstractFeature() {
+        }), "The copied features list must be mutable");
+        assertEquals(2, cfb.getFeatures().size(), "The appended feature must 
be present");
+    }
+
     public static SpringJAXRSClientFactoryBean serviceEndpoint() {
 
         SpringJAXRSClientFactoryBean clientFactoryBean = new 
SpringJAXRSClientFactoryBean();
@@ -99,6 +116,13 @@ public class CxfRsSpringEndpointTest extends 
CamelSpringTestSupport {
         return clientFactoryBean;
     }
 
+    public static SpringJAXRSClientFactoryBean fixedSizeFeaturesEndpoint() {
+        SpringJAXRSClientFactoryBean clientFactoryBean = serviceEndpoint();
+        clientFactoryBean.setFeatures(Arrays.asList(new AbstractFeature() {
+        }));
+        return clientFactoryBean;
+    }
+
     @Override
     protected AbstractXmlApplicationContext createApplicationContext() {
 
@@ -115,5 +139,10 @@ public class CxfRsSpringEndpointTest extends 
CamelSpringTestSupport {
         BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder
                 
.rootBeanDefinition(CxfRsSpringEndpointTest.class.getName()).setFactoryMethod("serviceEndpoint");
         beanFactory.registerBeanDefinition(BEAN_SERVICE_ENDPOINT_NAME, 
definitionBuilder.getBeanDefinition());
+
+        BeanDefinitionBuilder fixedSizeFeaturesDefinitionBuilder = 
BeanDefinitionBuilder
+                
.rootBeanDefinition(CxfRsSpringEndpointTest.class.getName()).setFactoryMethod("fixedSizeFeaturesEndpoint");
+        beanFactory.registerBeanDefinition(FIXED_SIZE_FEATURES_ENDPOINT_NAME,
+                fixedSizeFeaturesDefinitionBuilder.getBeanDefinition());
     }
 }

Reply via email to