You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2016/11/28 15:00:26 UTC

cxf git commit: [CXF-7157] Support for the client side bean validation for JAX-RS and JAX-WS (further minor updates might be needed for JAX-WS)

Repository: cxf
Updated Branches:
  refs/heads/master 71376c2e3 -> 75093fe6a


[CXF-7157] Support for the client side bean validation for JAX-RS and JAX-WS (further minor updates might be needed for JAX-WS)


Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/75093fe6
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/75093fe6
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/75093fe6

Branch: refs/heads/master
Commit: 75093fe6a833af5c96b136005dc9d993123adc9e
Parents: 71376c2
Author: Sergey Beryozkin <sb...@gmail.com>
Authored: Mon Nov 28 15:00:12 2016 +0000
Committer: Sergey Beryozkin <sb...@gmail.com>
Committed: Mon Nov 28 15:00:12 2016 +0000

----------------------------------------------------------------------
 .../AbstractBeanValidationInterceptor.java      | 63 ++++++++++++++++++++
 .../AbstractValidationInterceptor.java          | 20 ++++---
 .../cxf/validation/BeanValidationFeature.java   |  5 +-
 .../validation/BeanValidationInInterceptor.java | 39 +-----------
 .../validation/ClientBeanValidationFeature.java | 50 ++++++++++++++++
 .../ClientBeanValidationOutInterceptor.java     | 30 ++++++++++
 .../cxf/jaxrs/client/ClientProxyImpl.java       | 21 ++++---
 .../jaxrs/client/JAXRSClientFactoryBean.java    |  1 +
 .../JAXRSClientBeanValidationFeature.java       | 40 +++++++++++++
 ...JAXRSClientBeanValidationOutInterceptor.java | 40 +++++++++++++
 .../JAXRSClientServerValidationSpringTest.java  | 24 ++++++++
 11 files changed, 279 insertions(+), 54 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf/blob/75093fe6/core/src/main/java/org/apache/cxf/validation/AbstractBeanValidationInterceptor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/cxf/validation/AbstractBeanValidationInterceptor.java b/core/src/main/java/org/apache/cxf/validation/AbstractBeanValidationInterceptor.java
new file mode 100644
index 0000000..a7b25e0
--- /dev/null
+++ b/core/src/main/java/org/apache/cxf/validation/AbstractBeanValidationInterceptor.java
@@ -0,0 +1,63 @@
+/**
+ * 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.validation;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import javax.validation.ValidationException;
+
+import org.apache.cxf.message.Message;
+
+public abstract class AbstractBeanValidationInterceptor extends AbstractValidationInterceptor {
+    protected AbstractBeanValidationInterceptor(String phase) {
+        super(phase);
+    }
+
+    protected Object getServiceObject(Message message) {
+        return checkNotNull(super.getServiceObject(message), "SERVICE_OBJECT_NULL");
+    }
+    
+    protected Method getServiceMethod(Message message) {
+        return (Method)checkNotNull(super.getServiceMethod(message), "SERVICE_METHOD_NULL");
+    }
+    
+    private Object checkNotNull(Object object, String name) {
+        if (object == null) {
+            String message = new org.apache.cxf.common.i18n.Message(name, BUNDLE).toString();
+            LOG.severe(message);
+            throw new ValidationException(message.toString());
+        }
+        return object;
+    }
+    
+    @Override
+    protected void handleValidation(final Message message, final Object resourceInstance,
+                                    final Method method, final List<Object> arguments) {
+        if (arguments.size() > 0) {
+            BeanValidationProvider provider = getProvider(message);
+            provider.validateParameters(resourceInstance, method, unwrapArgs(arguments).toArray());
+            message.getExchange().put(BeanValidationProvider.class, provider);
+        }
+    }
+    
+    protected List<Object> unwrapArgs(List<Object> arguments) {
+        return arguments;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/75093fe6/core/src/main/java/org/apache/cxf/validation/AbstractValidationInterceptor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/cxf/validation/AbstractValidationInterceptor.java b/core/src/main/java/org/apache/cxf/validation/AbstractValidationInterceptor.java
index 266d2c9..821d7d1 100644
--- a/core/src/main/java/org/apache/cxf/validation/AbstractValidationInterceptor.java
+++ b/core/src/main/java/org/apache/cxf/validation/AbstractValidationInterceptor.java
@@ -96,15 +96,21 @@ public abstract class AbstractValidationInterceptor extends AbstractPhaseInterce
     
     protected Method getServiceMethod(Message message) {
         Message inMessage = message.getExchange().getInMessage();
-        Method method = (Method)inMessage.get("org.apache.cxf.resource.method");
-        if (method == null) {
-            BindingOperationInfo bop = inMessage.getExchange().getBindingOperationInfo();
-            if (bop != null) {
-                MethodDispatcher md = (MethodDispatcher) 
-                    inMessage.getExchange().getService().get(MethodDispatcher.class.getName());
-                method = md.getMethod(bop);
+        Method method = null;
+        if (inMessage != null) {
+            method = (Method)inMessage.get("org.apache.cxf.resource.method");
+            if (method == null) {
+                BindingOperationInfo bop = inMessage.getExchange().getBindingOperationInfo();
+                if (bop != null) {
+                    MethodDispatcher md = (MethodDispatcher) 
+                        inMessage.getExchange().getService().get(MethodDispatcher.class.getName());
+                    method = md.getMethod(bop);
+                }
             }
         }
+        if (method == null) {
+            method = message.getExchange().get(Method.class);
+        }
         return method;
     }
     

http://git-wip-us.apache.org/repos/asf/cxf/blob/75093fe6/core/src/main/java/org/apache/cxf/validation/BeanValidationFeature.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/cxf/validation/BeanValidationFeature.java b/core/src/main/java/org/apache/cxf/validation/BeanValidationFeature.java
index e5516fc..f4f1ef1 100644
--- a/core/src/main/java/org/apache/cxf/validation/BeanValidationFeature.java
+++ b/core/src/main/java/org/apache/cxf/validation/BeanValidationFeature.java
@@ -19,10 +19,13 @@
 package org.apache.cxf.validation;
 
 import org.apache.cxf.Bus;
+import org.apache.cxf.annotations.Provider;
+import org.apache.cxf.annotations.Provider.Scope;
+import org.apache.cxf.annotations.Provider.Type;
 import org.apache.cxf.feature.AbstractFeature;
 import org.apache.cxf.interceptor.InterceptorProvider;
 
-
+@Provider(value = Type.Feature, scope = Scope.Server)
 public class BeanValidationFeature extends AbstractFeature {
 
     private BeanValidationProvider validationProvider;

http://git-wip-us.apache.org/repos/asf/cxf/blob/75093fe6/core/src/main/java/org/apache/cxf/validation/BeanValidationInInterceptor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/cxf/validation/BeanValidationInInterceptor.java b/core/src/main/java/org/apache/cxf/validation/BeanValidationInInterceptor.java
index 15d1b67..2e87f96 100644
--- a/core/src/main/java/org/apache/cxf/validation/BeanValidationInInterceptor.java
+++ b/core/src/main/java/org/apache/cxf/validation/BeanValidationInInterceptor.java
@@ -18,50 +18,13 @@
  */
 package org.apache.cxf.validation;
 
-import java.lang.reflect.Method;
-import java.util.List;
-
-import javax.validation.ValidationException;
-
-import org.apache.cxf.message.Message;
 import org.apache.cxf.phase.Phase;
 
-public class BeanValidationInInterceptor extends AbstractValidationInterceptor {
+public class BeanValidationInInterceptor extends AbstractBeanValidationInterceptor {
     public BeanValidationInInterceptor() {
         super(Phase.PRE_INVOKE);
     }
     public BeanValidationInInterceptor(String phase) {
         super(phase);
     }
-
-    protected Object getServiceObject(Message message) {
-        return checkNotNull(super.getServiceObject(message), "SERVICE_OBJECT_NULL");
-    }
-    
-    protected Method getServiceMethod(Message message) {
-        return (Method)checkNotNull(super.getServiceMethod(message), "SERVICE_METHOD_NULL");
-    }
-    
-    private Object checkNotNull(Object object, String name) {
-        if (object == null) {
-            String message = new org.apache.cxf.common.i18n.Message(name, BUNDLE).toString();
-            LOG.severe(message);
-            throw new ValidationException(message.toString());
-        }
-        return object;
-    }
-    
-    @Override
-    protected void handleValidation(final Message message, final Object resourceInstance,
-                                    final Method method, final List<Object> arguments) {
-        if (arguments.size() > 0) {
-            BeanValidationProvider provider = getProvider(message);
-            provider.validateParameters(resourceInstance, method, unwrapArgs(arguments).toArray());
-            message.getExchange().put(BeanValidationProvider.class, provider);
-        }
-    }
-    
-    protected List<Object> unwrapArgs(List<Object> arguments) {
-        return arguments;
-    }
 }

http://git-wip-us.apache.org/repos/asf/cxf/blob/75093fe6/core/src/main/java/org/apache/cxf/validation/ClientBeanValidationFeature.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/cxf/validation/ClientBeanValidationFeature.java b/core/src/main/java/org/apache/cxf/validation/ClientBeanValidationFeature.java
new file mode 100644
index 0000000..67caff2
--- /dev/null
+++ b/core/src/main/java/org/apache/cxf/validation/ClientBeanValidationFeature.java
@@ -0,0 +1,50 @@
+/**
+ * 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.validation;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.annotations.Provider;
+import org.apache.cxf.annotations.Provider.Scope;
+import org.apache.cxf.annotations.Provider.Type;
+import org.apache.cxf.feature.AbstractFeature;
+import org.apache.cxf.interceptor.InterceptorProvider;
+
+@Provider(value = Type.Feature, scope = Scope.Client)
+public class ClientBeanValidationFeature extends AbstractFeature {
+
+    private BeanValidationProvider validationProvider;
+    
+    @Override
+    protected void initializeProvider(InterceptorProvider interceptorProvider, Bus bus) {
+        ClientBeanValidationOutInterceptor out = new ClientBeanValidationOutInterceptor();
+        addInterceptor(interceptorProvider, out);
+    }
+    
+    protected void addInterceptor(InterceptorProvider interceptorProvider, ClientBeanValidationOutInterceptor out) {
+        if (validationProvider != null) {
+            out.setProvider(validationProvider);
+        }
+        interceptorProvider.getOutInterceptors().add(out);
+        
+    }
+
+    public void setProvider(BeanValidationProvider provider) {
+        this.validationProvider = provider;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/75093fe6/core/src/main/java/org/apache/cxf/validation/ClientBeanValidationOutInterceptor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/cxf/validation/ClientBeanValidationOutInterceptor.java b/core/src/main/java/org/apache/cxf/validation/ClientBeanValidationOutInterceptor.java
new file mode 100644
index 0000000..c8e0401
--- /dev/null
+++ b/core/src/main/java/org/apache/cxf/validation/ClientBeanValidationOutInterceptor.java
@@ -0,0 +1,30 @@
+/**
+ * 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.validation;
+
+import org.apache.cxf.phase.Phase;
+
+public class ClientBeanValidationOutInterceptor extends AbstractBeanValidationInterceptor {
+    public ClientBeanValidationOutInterceptor() {
+        super(Phase.PRE_LOGICAL);
+    }
+    public ClientBeanValidationOutInterceptor(String phase) {
+        super(phase);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/75093fe6/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java
----------------------------------------------------------------------
diff --git a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java
index af3c015..221cbd4 100644
--- a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java
+++ b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java
@@ -96,8 +96,7 @@ public class ClientProxyImpl extends AbstractClient implements
     private static final ResourceBundle BUNDLE = BundleUtils.getBundle(ClientProxyImpl.class);
     private static final String SLASH = "/";
     private static final String BUFFER_PROXY_RESPONSE = "buffer.proxy.response";
-    private static final String METHOD_PARAM_BODY_INDEX = "method.parameter.body.index";
-    private static final String METHOD_PARAMS = "method.parameters";
+    private static final String PROXY_METHOD_PARAM_BODY_INDEX = "proxy.method.parameter.body.index";
     
     private ClassResourceInfo cri;
     private ClassLoader proxyLoader;
@@ -105,6 +104,7 @@ public class ClientProxyImpl extends AbstractClient implements
     private boolean isRoot;
     private Map<String, Object> valuesMap = Collections.emptyMap();
     private BodyWriter bodyWriter = new BodyWriter();
+    private Client proxy; 
     public ClientProxyImpl(URI baseURI,
                            ClassLoader loader,
                            ClassResourceInfo cri, 
@@ -128,7 +128,9 @@ public class ClientProxyImpl extends AbstractClient implements
         initValuesMap(varValues);
         cfg.getInInterceptors().add(new ClientAsyncResponseInterceptor());
     }
-    
+    void setProxyClient(Client client) {
+        this.proxy = client;
+    }
     private void initValuesMap(Object... varValues) {
         if (isRoot) {
             List<String> vars = cri.getURITemplate().getVariables();
@@ -732,15 +734,18 @@ public class ClientProxyImpl extends AbstractClient implements
             outMessage.put(Annotation.class.getName(), 
                            getMethodAnnotations(ori.getAnnotatedMethod(), bodyIndex));
             
-            outMessage.put(METHOD_PARAMS, methodParams);
+            outMessage.getExchange().put(Message.SERVICE_OBJECT, proxy);
+            if (methodParams != null) {
+                outMessage.put(List.class, Arrays.asList(methodParams));
+            }
             if (body != null) {
-                outMessage.put(METHOD_PARAM_BODY_INDEX, bodyIndex);
+                outMessage.put(PROXY_METHOD_PARAM_BODY_INDEX, bodyIndex);
             }
             outMessage.getInterceptorChain().add(bodyWriter);
             
             Map<String, Object> reqContext = getRequestContext(outMessage);
             reqContext.put(OperationResourceInfo.class.getName(), ori);
-            reqContext.put(METHOD_PARAM_BODY_INDEX, bodyIndex);
+            reqContext.put(PROXY_METHOD_PARAM_BODY_INDEX, bodyIndex);
             
             // execute chain
             InvocationCallback<Object> asyncCallback = checkAsyncCallback(ori, reqContext);
@@ -828,7 +833,7 @@ public class ClientProxyImpl extends AbstractClient implements
                                  Map<String, Object> invContext) throws Throwable {
         
         Map<String, Object> reqContext = CastUtils.cast((Map<?, ?>)invContext.get(REQUEST_CONTEXT));
-        int bodyIndex = body != null ? (Integer)reqContext.get(METHOD_PARAM_BODY_INDEX) : -1;
+        int bodyIndex = body != null ? (Integer)reqContext.get(PROXY_METHOD_PARAM_BODY_INDEX) : -1;
         OperationResourceInfo ori = 
             (OperationResourceInfo)reqContext.get(OperationResourceInfo.class.getName());
         return doChainedInvocation(newRequestURI, headers, ori, null,
@@ -906,7 +911,7 @@ public class ClientProxyImpl extends AbstractClient implements
             }
             
             Method method = ori.getMethodToInvoke();
-            int bodyIndex = (Integer)outMessage.get(METHOD_PARAM_BODY_INDEX);
+            int bodyIndex = (Integer)outMessage.get(PROXY_METHOD_PARAM_BODY_INDEX);
             
             Annotation[] anns = customAnns != null ? customAnns
                 : getMethodAnnotations(ori.getAnnotatedMethod(), bodyIndex);

http://git-wip-us.apache.org/repos/asf/cxf/blob/75093fe6/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/JAXRSClientFactoryBean.java
----------------------------------------------------------------------
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 936c43d..79d8b04 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
@@ -323,6 +323,7 @@ public class JAXRSClientFactoryBean extends AbstractJAXRSFactoryBean {
             ClassLoader theLoader = proxyLoader == null ? cri.getServiceClass().getClassLoader() : proxyLoader;
             Class<?>[] ifaces = new Class[]{Client.class, InvocationHandlerAware.class, cri.getServiceClass()};
             Client actualClient = (Client)ProxyHelper.getProxy(theLoader, ifaces, proxyImpl);
+            proxyImpl.setProxyClient(actualClient);
             notifyLifecycleManager(actualClient);
             this.getServiceFactory().sendEvent(FactoryBeanListener.Event.CLIENT_CREATED, actualClient, ep);
             return actualClient;

http://git-wip-us.apache.org/repos/asf/cxf/blob/75093fe6/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/validation/JAXRSClientBeanValidationFeature.java
----------------------------------------------------------------------
diff --git a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/validation/JAXRSClientBeanValidationFeature.java b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/validation/JAXRSClientBeanValidationFeature.java
new file mode 100644
index 0000000..9e45eab
--- /dev/null
+++ b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/validation/JAXRSClientBeanValidationFeature.java
@@ -0,0 +1,40 @@
+/**
+ * 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.validation;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.annotations.Provider;
+import org.apache.cxf.annotations.Provider.Scope;
+import org.apache.cxf.annotations.Provider.Type;
+import org.apache.cxf.interceptor.InterceptorProvider;
+import org.apache.cxf.validation.ClientBeanValidationFeature;
+
+@Provider(value = Type.Feature, scope = Scope.Client)
+public class JAXRSClientBeanValidationFeature extends ClientBeanValidationFeature {
+    private boolean wrapInProcessingException;
+    @Override
+    protected void initializeProvider(InterceptorProvider interceptorProvider, Bus bus) {
+        JAXRSClientBeanValidationOutInterceptor out = new JAXRSClientBeanValidationOutInterceptor();
+        out.setWrapInProcessingException(wrapInProcessingException);
+        super.addInterceptor(interceptorProvider, out);
+    }
+    public void setWrapInProcessingException(boolean wrapInProcessingException) {
+        this.wrapInProcessingException = wrapInProcessingException;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/75093fe6/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/validation/JAXRSClientBeanValidationOutInterceptor.java
----------------------------------------------------------------------
diff --git a/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/validation/JAXRSClientBeanValidationOutInterceptor.java b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/validation/JAXRSClientBeanValidationOutInterceptor.java
new file mode 100644
index 0000000..c2c155b
--- /dev/null
+++ b/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/validation/JAXRSClientBeanValidationOutInterceptor.java
@@ -0,0 +1,40 @@
+/**
+ * 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.validation;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.apache.cxf.message.Message;
+import org.apache.cxf.validation.ClientBeanValidationOutInterceptor;
+
+public class JAXRSClientBeanValidationOutInterceptor extends ClientBeanValidationOutInterceptor {
+    private boolean wrapInProcessingException;
+
+    @Override
+    protected void handleValidation(Message message, Object resourceInstance,
+                                    Method method, List<Object> arguments) {
+        message.getExchange().put("wrap.in.processing.exception", wrapInProcessingException);
+        super.handleValidation(message, resourceInstance, method, arguments);
+    }
+    
+    public void setWrapInProcessingException(boolean wrapInProcessingException) {
+        this.wrapInProcessingException = wrapInProcessingException;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/75093fe6/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/validation/spring/JAXRSClientServerValidationSpringTest.java
----------------------------------------------------------------------
diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/validation/spring/JAXRSClientServerValidationSpringTest.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/validation/spring/JAXRSClientServerValidationSpringTest.java
index b067b39..73cb899 100644
--- a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/validation/spring/JAXRSClientServerValidationSpringTest.java
+++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/validation/spring/JAXRSClientServerValidationSpringTest.java
@@ -18,6 +18,9 @@
  */
 package org.apache.cxf.systest.jaxrs.validation.spring;
 
+import java.util.Arrays;
+
+import javax.validation.ConstraintViolationException;
 import javax.ws.rs.BadRequestException;
 import javax.ws.rs.core.Form;
 import javax.ws.rs.core.Response;
@@ -28,6 +31,8 @@ import javax.xml.ws.soap.SOAPBinding;
 import javax.xml.ws.soap.SOAPFaultException;
 
 import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
+import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean;
+import org.apache.cxf.jaxrs.client.validation.JAXRSClientBeanValidationFeature;
 import org.apache.cxf.jaxrs.model.AbstractResourceInfo;
 import org.apache.cxf.systest.jaxrs.AbstractSpringServer;
 import org.apache.cxf.systest.jaxrs.validation.AbstractJAXRSValidationTest;
@@ -95,6 +100,25 @@ public class JAXRSClientServerValidationSpringTest extends AbstractJAXRSValidati
         }
         
     }
+    
+    @Test
+    public void testHelloRestValidationFailsIfNameIsNullClient() throws Exception {
+        JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean();
+        bean.setAddress("http://localhost:" + PORT + "/bwrest");
+        bean.setServiceClass(BookWorld.class);
+        bean.setFeatures(Arrays.asList(new JAXRSClientBeanValidationFeature()));
+        BookWorld service = bean.create(BookWorld.class);
+        BookWithValidation bw = service.echoBook(new BookWithValidation("RS", "123"));
+        assertEquals("123", bw.getId());
+        
+        try {
+            service.echoBook(new BookWithValidation(null, "123"));
+            fail("Validation failure expected");
+        } catch (ConstraintViolationException ex) {
+            // complete
+        }
+        
+    }
     @Test
     public void testHelloSoapValidationFailsIfNameIsNull() throws Exception {
         final QName serviceName = new QName("http://bookworld.com", "BookWorld");