You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by re...@apache.org on 2021/09/17 01:11:24 UTC

[cxf] branch 3.4.x-fixes updated (888ae63 -> b0cdc26)

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

reta pushed a change to branch 3.4.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git.


    from 888ae63  Update Spring Framework to 5.2.17.RELEASE
     new 4f46a32  CXF-7543: JAX-RS Features not used in proxies or WebClients (#849)
     new b0cdc26  Recording .gitmergeinfo Changes

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .gitmergeinfo                                      |  3 +
 .../cxf/jaxrs/client/JAXRSClientFactoryBean.java   | 41 ++++++++++
 .../JAXRSClientFactoryBeanDefinitionParser.java    | 59 ++++++++++++++
 .../cxf/jaxrs/client/cache/ClientCacheTest.java    | 23 ++++++
 .../client/spring/JAXRSClientFactoryBeanTest.java  | 34 ++++++++
 .../client/spring/SpringParameterHandler.java}     | 17 ++--
 .../org/apache/cxf/jaxrs/client/spring/clients.xml |  6 ++
 .../client/MicroProfileClientFactoryBean.java      | 14 +++-
 .../client/CxfTypeSafeClientBuilderTest.java       | 42 ++++++++++
 .../client/MicroProfileClientFactoryBeanTest.java  | 94 ++++++++++++++++++++++
 10 files changed, 324 insertions(+), 9 deletions(-)
 copy rt/{frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/PriorityCustomerParameterHandler.java => rs/client/src/test/java/org/apache/cxf/jaxrs/client/spring/SpringParameterHandler.java} (76%)
 create mode 100644 rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/MicroProfileClientFactoryBeanTest.java

[cxf] 02/02: Recording .gitmergeinfo Changes

Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

reta pushed a commit to branch 3.4.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit b0cdc26653ed616519ff47735eb179c6b2779d9a
Author: Andriy Redko <dr...@gmail.com>
AuthorDate: Thu Sep 16 20:37:33 2021 -0400

    Recording .gitmergeinfo Changes
---
 .gitmergeinfo | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/.gitmergeinfo b/.gitmergeinfo
index 54a2d87..30c334c 100644
--- a/.gitmergeinfo
+++ b/.gitmergeinfo
@@ -97,6 +97,7 @@ M 15185954d24578b3a848afe5bf258d9774ff03b6
 M 16df606f5ea05ad8fe5c3ab54cc4e3684067d84d
 M 1820f1a94b08ba840c3868ac3e1f3b7751540a08
 M 1955e0d57557bd682d0e7fe6bd68d3fb973c4af0
+M 1b48b239be3807e843c56939f663ae935a53f6f5
 M 1c7c39771adb05f1fa8678e20b97f1c735f2601c
 M 2871e80043c2452cf9aca3925a07360b8775c508
 M 299d6a844b99a69555355b2f9baca3e6ec13a918
@@ -117,6 +118,7 @@ M 4576030871f0f52e7295ce7d41888d8b976c7c11
 M 4680528c0f9379ee51a0758ab52ad2e6de2cb0a6
 M 4852a50d335817c50882f641197fd189207571eb
 M 4b714edc4805395974da2ff9c683b61ec9b23db9
+M 4b76fac643915ec9e3409f00c1ce62ba83994265
 M 4c3c5196be3e9295c31b5bc592ebc8f911c93c6d
 M 4dc7c95796c89ec6d33d99b2df202cb71124a741
 M 504cb84e0bf6043d3b787def4070c0649dd51c32
@@ -187,6 +189,7 @@ M c29b1c23a7e09f9fe2c5412d0b9ece1bafb7c89c
 M c2e6f351383602c5c40405049fb83a52a0b3ccff
 M c7786d4e78999cb08fd668b24a7fac480bf7b5e0
 M ca5d02bf9581a28971c8b8d021732972dce5377e
+M cc4f758e89da58b2f47c95fb68df186e0533ca74
 M ccb76b7c2c02b0f295405fd9bb0b585544c40869
 M cf2f79a5de150773b8dd1c4975de7e679a6d4d17
 M d2f8db651c418c82b08bc69900d9b90c5d9625bc

[cxf] 01/02: CXF-7543: JAX-RS Features not used in proxies or WebClients (#849)

Posted by re...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

reta pushed a commit to branch 3.4.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit 4f46a32f698d4089fb8b0c11ae095d53821d50f8
Author: Andriy Redko <dr...@gmail.com>
AuthorDate: Thu Sep 16 20:05:21 2021 -0400

    CXF-7543: JAX-RS Features not used in proxies or WebClients (#849)
    
    (cherry picked from commit bf25a931a96a6eb6cac47651bef1f2ff4fb442bc)
---
 .../cxf/jaxrs/client/JAXRSClientFactoryBean.java   | 41 ++++++++++
 .../JAXRSClientFactoryBeanDefinitionParser.java    | 59 ++++++++++++++
 .../cxf/jaxrs/client/cache/ClientCacheTest.java    | 23 ++++++
 .../client/spring/JAXRSClientFactoryBeanTest.java  | 34 ++++++++
 .../client/spring/SpringParameterHandler.java      | 58 +++++++++++++
 .../org/apache/cxf/jaxrs/client/spring/clients.xml |  6 ++
 .../client/MicroProfileClientFactoryBean.java      | 14 +++-
 .../client/CxfTypeSafeClientBuilderTest.java       | 42 ++++++++++
 .../client/MicroProfileClientFactoryBeanTest.java  | 94 ++++++++++++++++++++++
 9 files changed, 368 insertions(+), 3 deletions(-)

diff --git a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactoryBean.java b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactoryBean.java
index 13d3c28..ccf547c 100644
--- a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactoryBean.java
+++ b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactoryBean.java
@@ -24,12 +24,19 @@ import java.lang.reflect.Type;
 import java.net.URI;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.logging.Logger;
 
 import javax.ws.rs.CookieParam;
 import javax.ws.rs.HeaderParam;
+import javax.ws.rs.RuntimeType;
+import javax.ws.rs.core.Configurable;
+import javax.ws.rs.core.Configuration;
+import javax.ws.rs.core.Feature;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.ext.ParamConverter;
 import javax.ws.rs.ext.ParamConverterProvider;
@@ -45,6 +52,8 @@ import org.apache.cxf.endpoint.UpfrontConduitSelector;
 import org.apache.cxf.jaxrs.AbstractJAXRSFactoryBean;
 import org.apache.cxf.jaxrs.JAXRSServiceFactoryBean;
 import org.apache.cxf.jaxrs.JAXRSServiceImpl;
+import org.apache.cxf.jaxrs.impl.ConfigurableImpl;
+import org.apache.cxf.jaxrs.impl.FeatureContextImpl;
 import org.apache.cxf.jaxrs.impl.MetadataMap;
 import org.apache.cxf.jaxrs.model.ClassResourceInfo;
 import org.apache.cxf.jaxrs.utils.AnnotationUtils;
@@ -403,6 +412,10 @@ public class JAXRSClientFactoryBean extends AbstractJAXRSFactoryBean {
             });
         }
     }
+    
+    protected <C extends Configurable<C>> Configurable<?> getConfigurableFor(C context) {
+        return new ConfigurableImpl<>(context, RuntimeType.CLIENT);
+    }
 
     protected void applyFeatures(AbstractClient client) {
         if (getFeatures() != null) {
@@ -410,6 +423,34 @@ public class JAXRSClientFactoryBean extends AbstractJAXRSFactoryBean {
                 feature.initialize(client.getConfiguration(), getBus());
             });
         }
+        
+        // Process JAX-RS features which are passed through as providers 
+        final Set<Object> providers = new HashSet<>();
+        for (final Object provider: getProviders()) {
+            if (provider instanceof Feature) {
+                final Feature feature = (Feature)provider;
+                final FeatureContextImpl context = new FeatureContextImpl();
+                final Configurable<?> configurable = getConfigurableFor(context);
+                final Configuration configuration = configurable.getConfiguration();
+                final Set<Object> registered = configuration.getInstances();
+                
+                if (!configuration.isRegistered(feature)) {
+                    configurable.register(feature);
+                    
+                    // Disregarding if the feature is enabled or disabled, register only newly added providers,
+                    // excluding pre-existing ones and the feature instance itself.
+                    final Set<Object> added = new HashSet<Object>(configuration.getInstances());
+                    added.remove(feature);
+                    added.removeAll(registered);
+                    
+                    providers.addAll(added);
+                }
+            }
+        }
+        
+        if (!providers.isEmpty()) {
+            setProviders(Arrays.asList(providers));
+        }
     }
 
     /**
diff --git a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spring/JAXRSClientFactoryBeanDefinitionParser.java b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spring/JAXRSClientFactoryBeanDefinitionParser.java
index 4f93423..1fb0912 100644
--- a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spring/JAXRSClientFactoryBeanDefinitionParser.java
+++ b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spring/JAXRSClientFactoryBeanDefinitionParser.java
@@ -20,12 +20,14 @@ package org.apache.cxf.jaxrs.client.spring;
 
 import java.io.IOException;
 import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
 import java.util.Collection;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
 import javax.ws.rs.Path;
+import javax.ws.rs.core.Configurable;
 import javax.ws.rs.ext.Provider;
 import javax.xml.namespace.QName;
 
@@ -35,6 +37,7 @@ import org.apache.cxf.bus.spring.BusWiringBeanFactoryPostProcessor;
 import org.apache.cxf.common.util.ClasspathScanner;
 import org.apache.cxf.configuration.spring.AbstractFactoryBeanDefinitionParser;
 import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean;
+import org.apache.cxf.jaxrs.impl.ConfigurableImpl;
 import org.apache.cxf.jaxrs.model.UserResource;
 import org.apache.cxf.jaxrs.utils.ResourceUtils;
 import org.springframework.beans.BeansException;
@@ -109,11 +112,50 @@ public class JAXRSClientFactoryBeanDefinitionParser extends AbstractFactoryBeanD
             setFirstChildAsProperty(el, ctx, bean, name);
         }
     }
+    
+    /**
+     * Instantiate newly registered provider instances using {@link AutowireCapableBeanFactory} 
+     */
+    private static class SpringInstantiator implements ConfigurableImpl.Instantiator {
+        private final AutowireCapableBeanFactory beanFactory;
+        
+        SpringInstantiator(final AutowireCapableBeanFactory beanFactory) {
+            this.beanFactory = beanFactory;
+        }
+
+        @Override
+        public <T> Object create(Class<T> cls) {
+            return beanFactory.createBean(cls, resolveAutowireMode(cls), true);
+        }
+        
+        @Override
+        public void release(Object instance) {
+            beanFactory.destroyBean(instance);
+        }
+        
+        /**
+         * Return the resolved autowire mode (AUTOWIRE_CONSTRUCTOR or AUTOWIRE_BY_TYPE).
+         */
+        private <T> int resolveAutowireMode(Class<T> cls) {
+            final Constructor<?>[] constructors = cls.getConstructors();
+            
+            for (Constructor<?> constructor: constructors) {
+                // If there is a default constructor, we are good to go with
+                // autowiring by type, otherwise we need construction injection.
+                if (constructor.getParameterCount() == 0) {
+                    return AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
+                }
+            }
+
+            return AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
+        }
+    }
 
     public static class JAXRSSpringClientFactoryBean extends JAXRSClientFactoryBean
         implements ApplicationContextAware {
 
         private List<String> basePackages;
+        private SpringInstantiator instantiator;
 
         public JAXRSSpringClientFactoryBean() {
             super();
@@ -125,6 +167,10 @@ public class JAXRSClientFactoryBeanDefinitionParser extends AbstractFactoryBeanD
 
         public void setApplicationContext(ApplicationContext ctx) throws BeansException {
             try {
+                if (instantiator == null) {
+                    instantiator = new SpringInstantiator(ctx.getAutowireCapableBeanFactory());
+                }
+                
                 if (basePackages != null) {
                     final Map< Class< ? extends Annotation >, Collection< Class< ? > > > classes =
                         ClasspathScanner.findClasses(basePackages, Path.class, Provider.class);
@@ -159,6 +205,17 @@ public class JAXRSClientFactoryBeanDefinitionParser extends AbstractFactoryBeanD
                 setBus(BusWiringBeanFactoryPostProcessor.addDefaultBus(ctx));
             }
         }
+        
+        @Override
+        protected <C extends Configurable<C>> Configurable<?> getConfigurableFor(C context) {
+            final Configurable<?> configurable = super.getConfigurableFor(context);
+            
+            if (instantiator != null) {
+                configurable.register(instantiator);
+            }
+            
+            return configurable;
+        }
     }
 
     static Class<?> getServiceClass(Collection<Class<?>> rootClasses) {
@@ -184,4 +241,6 @@ public class JAXRSClientFactoryBeanDefinitionParser extends AbstractFactoryBeanD
         }
         return providers;
     }
+    
+    
 }
diff --git a/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/cache/ClientCacheTest.java b/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/cache/ClientCacheTest.java
index f784f5d..5fc4be6 100644
--- a/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/cache/ClientCacheTest.java
+++ b/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/cache/ClientCacheTest.java
@@ -89,6 +89,29 @@ public class ClientCacheTest {
     }
 
     @Test
+    public void testGetTimeStringUsingClientFactory() {
+        CacheControlFeature feature = new CacheControlFeature();
+        try {
+            JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
+            bean.setAddress(ADDRESS);
+            bean.setProviders(Collections.singletonList(feature));
+            bean.setTransportId(LocalTransportFactory.TRANSPORT_ID);
+            
+            final WebClient cached = bean.createWebClient()
+                .accept("text/plain")
+                .header(HttpHeaders.CACHE_CONTROL, "public");
+            
+            final Response r = cached.get();
+            assertEquals(Response.Status.OK.getStatusCode(), r.getStatus());
+            final String r1 = r.readEntity(String.class);
+            waitABit();
+            assertEquals(r1, cached.get().readEntity(String.class));
+        } finally {
+            feature.close();
+        }
+    }
+
+    @Test
     public void testGetTimeStringAsInputStream() throws Exception {
         CacheControlFeature feature = new CacheControlFeature();
         try {
diff --git a/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/spring/JAXRSClientFactoryBeanTest.java b/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/spring/JAXRSClientFactoryBeanTest.java
index ecfff4c..f34d037 100644
--- a/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/spring/JAXRSClientFactoryBeanTest.java
+++ b/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/spring/JAXRSClientFactoryBeanTest.java
@@ -18,22 +18,30 @@
  */
 package org.apache.cxf.jaxrs.client.spring;
 
+import java.util.List;
+
+import javax.ws.rs.core.Feature;
+import javax.ws.rs.core.FeatureContext;
 import javax.xml.namespace.QName;
 
 import org.apache.cxf.BusFactory;
 import org.apache.cxf.jaxrs.client.Client;
 import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean;
+import org.apache.cxf.jaxrs.client.cache.CacheControlClientReaderInterceptor;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
 
 import org.junit.After;
 import org.junit.Test;
 
 import static org.hamcrest.CoreMatchers.endsWith;
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 
 
+
 public class JAXRSClientFactoryBeanTest {
 
     @After
@@ -110,4 +118,30 @@ public class JAXRSClientFactoryBeanTest {
                 endsWith("?list=1&list=2"));
         }
     }
+    
+    @Test
+    public void testClientWithFeatures() throws Exception {
+        try (ClassPathXmlApplicationContext ctx =
+                new ClassPathXmlApplicationContext(new String[] {"/org/apache/cxf/jaxrs/client/spring/clients.xml"})) {
+            final Client bean = (Client) ctx.getBean("client4");
+            assertNotNull(bean);
+            
+            final JAXRSClientFactoryBean cfb = (JAXRSClientFactoryBean)ctx.getBean("client4.proxyFactory");
+            assertNotNull(bean);
+            
+            assertThat((List<Object>)cfb.getProviders(), 
+                hasItem(instanceOf(CacheControlClientReaderInterceptor.class)));
+            
+            assertThat((List<Object>)cfb.getProviders(), 
+                hasItem(instanceOf(SpringParameterHandler.class)));
+        }
+    }
+    
+    public static class SomeFeature implements Feature {
+        @Override
+        public boolean configure(FeatureContext context) {
+            context.register(SpringParameterHandler.class);
+            return true;
+        }
+    }
 }
\ No newline at end of file
diff --git a/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/spring/SpringParameterHandler.java b/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/spring/SpringParameterHandler.java
new file mode 100644
index 0000000..10745a5
--- /dev/null
+++ b/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/spring/SpringParameterHandler.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.jaxrs.client.spring;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Objects;
+
+import javax.ws.rs.ext.ParamConverter;
+import javax.ws.rs.ext.ParamConverterProvider;
+
+import org.apache.cxf.jaxrs.client.Customer;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+
+public class SpringParameterHandler implements ParamConverterProvider, ParamConverter<Customer> {
+    @Autowired
+    public SpringParameterHandler(ApplicationContext context) {
+        Objects.requireNonNull(context);
+    }
+    
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> ParamConverter<T> getConverter(Class<T> cls, Type arg1, Annotation[] arg2) {
+        if (Customer.class == cls) {
+            return (ParamConverter<T>)this;
+        }
+        return null;
+    }
+
+    public Customer fromString(String s) throws IllegalArgumentException {
+        Customer c = new Customer();
+        c.setName(s);
+        return c;
+    }
+
+    @Override
+    public String toString(Customer arg0) throws IllegalArgumentException {
+        return null;
+    }
+}
diff --git a/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/spring/clients.xml b/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/spring/clients.xml
index 320de2e..7f33450 100644
--- a/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/spring/clients.xml
+++ b/rt/rs/client/src/test/java/org/apache/cxf/jaxrs/client/spring/clients.xml
@@ -59,4 +59,10 @@
             <entry key="expand.query.value.as.collection" value="true" />
         </jaxrs:properties>
     </jaxrs:client>
+    <jaxrs:client id="client4" serviceClass="org.apache.cxf.jaxrs.resources.BookStore" address="http://localhost:9000/foo" threadSafe="true">
+        <jaxrs:providers>
+            <bean class="org.apache.cxf.jaxrs.client.cache.CacheControlFeature"/>
+            <bean class="org.apache.cxf.jaxrs.client.spring.JAXRSClientFactoryBeanTest.SomeFeature"/>
+        </jaxrs:providers>
+    </jaxrs:client>
 </beans>
\ No newline at end of file
diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/MicroProfileClientFactoryBean.java b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/MicroProfileClientFactoryBean.java
index 389c4fa..0f10811 100644
--- a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/MicroProfileClientFactoryBean.java
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/MicroProfileClientFactoryBean.java
@@ -28,6 +28,7 @@ import java.util.concurrent.ExecutorService;
 
 import javax.ws.rs.client.ClientRequestFilter;
 import javax.ws.rs.client.ClientResponseFilter;
+import javax.ws.rs.core.Configurable;
 import javax.ws.rs.core.Configuration;
 
 import org.apache.cxf.common.util.ClassHelper;
@@ -51,17 +52,19 @@ import org.eclipse.microprofile.rest.client.RestClientBuilder;
 public class MicroProfileClientFactoryBean extends JAXRSClientFactoryBean {
     private final Comparator<ProviderInfo<?>> comparator;
     private final List<Object> registeredProviders;
+    private final Configurable<RestClientBuilder> configurable;
     private final Configuration configuration;
     private ClassLoader proxyLoader;
     private boolean inheritHeaders;
     private ExecutorService executorService;
     private TLSConfiguration secConfig;
 
-    public MicroProfileClientFactoryBean(MicroProfileClientConfigurableImpl<RestClientBuilder> configuration,
+    public MicroProfileClientFactoryBean(MicroProfileClientConfigurableImpl<RestClientBuilder> configurable,
                                          String baseUri, Class<?> aClass, ExecutorService executorService,
                                          TLSConfiguration secConfig) {
         super(new MicroProfileServiceFactoryBean());
-        this.configuration = configuration.getConfiguration();
+        this.configurable = configurable;
+        this.configuration = configurable.getConfiguration();
         this.comparator = MicroProfileClientProviderFactory.createComparator(this);
         this.executorService = (executorService == null) ? Utils.defaultExecutorService() : executorService; 
         this.secConfig = secConfig;
@@ -71,7 +74,7 @@ public class MicroProfileClientFactoryBean extends JAXRSClientFactoryBean {
         super.setProperties(this.configuration.getProperties());
         registeredProviders = new ArrayList<>();
         registeredProviders.addAll(processProviders());
-        if (!configuration.isDefaultExceptionMapperDisabled()) {
+        if (!configurable.isDefaultExceptionMapperDisabled()) {
             registeredProviders.add(new ProviderInfo<>(new DefaultResponseExceptionMapper(), getBus(), false));
         }
         registeredProviders.add(new ProviderInfo<>(new JsrJsonpProvider(), getBus(), false));
@@ -134,6 +137,11 @@ public class MicroProfileClientFactoryBean extends JAXRSClientFactoryBean {
                     inheritHeaders, executorService, configuration, interceptorWrapper, secConfig, varValues);
         }
     }
+    
+    @Override
+    protected <C extends Configurable<C>> Configurable<?> getConfigurableFor(C context) {
+        return configurable;
+    }
 
     Configuration getConfiguration() {
         return configuration;
diff --git a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/CxfTypeSafeClientBuilderTest.java b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/CxfTypeSafeClientBuilderTest.java
index c9d09a6..8ca5f4b 100644
--- a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/CxfTypeSafeClientBuilderTest.java
+++ b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/CxfTypeSafeClientBuilderTest.java
@@ -24,6 +24,8 @@ import java.net.URL;
 
 import javax.ws.rs.PathParam;
 import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Feature;
+import javax.ws.rs.core.FeatureContext;
 import javax.ws.rs.core.Response;
 
 import org.apache.cxf.jaxrs.client.WebClientUtil;
@@ -116,6 +118,30 @@ public class CxfTypeSafeClientBuilderTest {
         // TODO: add a test for writer interceptors - possibly in systests
         //assertEquals(TestWriterInterceptor.getAndResetValue(), 1);
     }
+    
+    @Test
+    public void testInvokesPostOperationWithRegisteredFeature() throws Exception {
+        String inputBody = "input body will be removed";
+        String expectedResponseBody = TestMessageBodyReader.REPLACED_BODY;
+
+        InterfaceWithoutProvidersDefined api = new CxfTypeSafeClientBuilder()
+                .register(SomeFeature.class)
+                .property("microprofile.rest.client.disable.default.mapper", true)
+                .baseUrl(new URL("http://localhost/null"))
+                .build(InterfaceWithoutProvidersDefined.class);
+
+        Response response = api.executePost(inputBody);
+
+        String body = response.readEntity(String.class);
+
+        response.close();
+
+        assertEquals(expectedResponseBody, body);
+
+        assertEquals(TestClientResponseFilter.getAndResetValue(), 1);
+        assertEquals(TestClientRequestFilter.getAndResetValue(), 1);
+        assertEquals(TestReaderInterceptor.getAndResetValue(), 1);
+    }
 
     @Test(expected = NoSuchEntityException.class)
     public void testResponseExceptionMapper() throws Exception {
@@ -223,4 +249,20 @@ public class CxfTypeSafeClientBuilderTest {
     public void testProxyAddressNullHost() {
         RestClientBuilder.newBuilder().proxyAddress(null, 8080);
     }
+    
+    public static class SomeFeature implements Feature {
+        @Override
+        public boolean configure(FeatureContext context) {
+            context
+                .register(TestClientRequestFilter.class)
+                .register(TestClientResponseFilter.class)
+                .register(TestMessageBodyReader.class, 4999)
+                .register(TestMessageBodyWriter.class)
+                .register(TestParamConverterProvider.class)
+                .register(TestReaderInterceptor.class)
+                .register(TestWriterInterceptor.class)
+                .register(EchoClientReqFilter.class);
+            return true;
+        }
+    }
 }
diff --git a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/MicroProfileClientFactoryBeanTest.java b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/MicroProfileClientFactoryBeanTest.java
new file mode 100644
index 0000000..9951f82
--- /dev/null
+++ b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/MicroProfileClientFactoryBeanTest.java
@@ -0,0 +1,94 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.microprofile.client;
+
+import java.util.List;
+
+import javax.ws.rs.core.Feature;
+import javax.ws.rs.core.FeatureContext;
+
+import org.apache.cxf.jaxrs.client.spec.TLSConfiguration;
+import org.apache.cxf.microprofile.client.mock.MyClient;
+import org.eclipse.microprofile.rest.client.RestClientBuilder;
+import org.eclipse.microprofile.rest.client.tck.providers.TestClientRequestFilter;
+
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+public class MicroProfileClientFactoryBeanTest {
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testCreateClientEnabledFeature() throws Exception {
+        final MicroProfileClientConfigurableImpl<RestClientBuilder> configurable = 
+                new MicroProfileClientConfigurableImpl<>(RestClientBuilder.newBuilder());
+
+        final MicroProfileClientFactoryBean bean = new MicroProfileClientFactoryBean(configurable, 
+                "http://bar", MyClient.class, null, new TLSConfiguration());
+        
+        final SomeFeature feature = new SomeFeature(true);
+        bean.setProvider(feature);
+
+        assertTrue(bean.create() instanceof MyClient);
+        assertTrue(configurable.getConfiguration().isRegistered(SomeFeature.class));
+        assertTrue(configurable.getConfiguration().isRegistered(TestClientRequestFilter.class));
+        assertTrue(configurable.getConfiguration().isEnabled(SomeFeature.class));
+        
+        assertThat((List<Object>)bean.getProviders(), hasItem(instanceOf(TestClientRequestFilter.class)));
+    }
+    
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testCreateClientDisabledFeature() throws Exception {
+        final MicroProfileClientConfigurableImpl<RestClientBuilder> configurable = 
+                new MicroProfileClientConfigurableImpl<>(RestClientBuilder.newBuilder());
+
+        final MicroProfileClientFactoryBean bean = new MicroProfileClientFactoryBean(configurable, 
+                "http://bar", MyClient.class, null, new TLSConfiguration());
+        
+        final SomeFeature feature = new SomeFeature(false);
+        bean.setProvider(feature);
+
+        assertTrue(bean.create() instanceof MyClient);
+        assertTrue(configurable.getConfiguration().isRegistered(SomeFeature.class));
+        assertTrue(configurable.getConfiguration().isRegistered(TestClientRequestFilter.class));
+        assertFalse(configurable.getConfiguration().isEnabled(SomeFeature.class));
+        
+        assertThat((List<Object>)bean.getProviders(), hasItem(instanceOf(TestClientRequestFilter.class)));
+    }
+    
+    public static class SomeFeature implements Feature {
+        private final boolean enabled;
+        
+        public SomeFeature(boolean enabled) {
+            this.enabled = enabled;
+        }
+        
+        @Override
+        public boolean configure(FeatureContext context) {
+            context.register(TestClientRequestFilter.class);
+            return enabled;
+        }
+    }
+}