cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From johndam...@apache.org
Subject [cxf] 19/21: MP Rest Client interface validation tests
Date Wed, 20 Dec 2017 19:18:56 GMT
This is an automated email from the ASF dual-hosted git repository.

johndament pushed a commit to branch mp-client
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit 13a483f176de72a3b0297a8d777c5f80393665a9
Author: Andy McCright <j.andrew.mccright@gmail.com>
AuthorDate: Tue Dec 19 15:26:45 2017 -0600

    MP Rest Client interface validation tests
    
    Checks:
    - that the passed-in type is an interface
    - that each method has, at most, one HTTP method annotation
    - that URI template variables in @Path annotations are resolved by
    @PathParam annotations
---
 .../client/CxfTypeSafeClientBuilder.java           |   1 +
 .../cxf/microprofile/client/Messages.properties    |  24 ++++
 .../client/MicroProfileClientConfigurableImpl.java |   8 +-
 .../apache/cxf/microprofile/client/Validator.java  | 124 +++++++++++++++++++
 .../cxf/microprofile/client/ValidatorTest.java     | 134 +++++++++++++++++++++
 5 files changed, 290 insertions(+), 1 deletion(-)

diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/CxfTypeSafeClientBuilder.java
b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/CxfTypeSafeClientBuilder.java
index d895586..2daf944 100644
--- a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/CxfTypeSafeClientBuilder.java
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/CxfTypeSafeClientBuilder.java
@@ -42,6 +42,7 @@ public class CxfTypeSafeClientBuilder implements RestClientBuilder, Configurable
         if (baseUri == null) {
             throw new IllegalStateException("baseUrl not set");
         }
+        Validator.checkValid(aClass);
         RegisterProvider[] providers = aClass.getAnnotationsByType(RegisterProvider.class);
         Configuration config = configImpl.getConfiguration();
         if (providers != null) {
diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/Messages.properties
b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/Messages.properties
new file mode 100644
index 0000000..d2d5363
--- /dev/null
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/Messages.properties
@@ -0,0 +1,24 @@
+#
+#
+#    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.
+#
+#
+
+VALIDATION_NOT_AN_INTERFACE=The type, {0},  passed in to the build method is not an interface.
+VALIDATION_METHOD_WITH_MULTIPLE_VERBS=The client interface contains a method, {0} annotated
with more than one HTTP method: {1}
+VALIDATION_UNRESOLVED_PATH_PARAMS=The client interface, {0} has one or more methods with
unresolved path template variables: {1}
diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/MicroProfileClientConfigurableImpl.java
b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/MicroProfileClientConfigurableImpl.java
index 3df4246..b27c47e 100644
--- a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/MicroProfileClientConfigurableImpl.java
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/MicroProfileClientConfigurableImpl.java
@@ -56,7 +56,13 @@ public class MicroProfileClientConfigurableImpl<C extends Configurable<C>>
         if (prop instanceof Boolean) {
             return (Boolean)prop;
         } else {
-            Config config = ConfigProvider.getConfig();
+            Config config;
+            try {
+                config = ConfigProvider.getConfig();
+            } catch (ExceptionInInitializerError | NoClassDefFoundError | IllegalStateException
ex) {
+                // no config provider implementation
+                return false;
+            }
             return config.getOptionalValue(CONFIG_KEY_DISABLE_MAPPER,
                     Boolean.class).orElse(false);
         }
diff --git a/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/Validator.java
b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/Validator.java
new file mode 100644
index 0000000..8d77e02
--- /dev/null
+++ b/rt/rs/microprofile-client/src/main/java/org/apache/cxf/microprofile/client/Validator.java
@@ -0,0 +1,124 @@
+/**
+ * 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.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+
+import org.apache.cxf.common.i18n.BundleUtils;
+import org.apache.cxf.common.i18n.Message;
+import org.apache.cxf.jaxrs.model.URITemplate;
+import org.eclipse.microprofile.rest.client.RestClientDefinitionException;
+
+final class Validator {
+    private static final ResourceBundle BUNDLE = BundleUtils.getBundle(Validator.class);
+
+    private Validator() {
+    }
+
+
+    public static void checkValid(Class<?> userType) throws RestClientDefinitionException
{
+        if (!userType.isInterface()) {
+            throwException("VALIDATION_NOT_AN_INTERFACE", userType);
+        }
+        Method[] methods = userType.getMethods();
+        checkMethodsForMultipleHTTPMethodAnnotations(methods);
+        checkMethodsForInvalidURITemplates(userType, methods);
+    }
+
+    private static void checkMethodsForMultipleHTTPMethodAnnotations(Method[] clientMethods)
+        throws RestClientDefinitionException {
+
+        Map<String, Class<? extends Annotation>> httpMethods = new HashMap<>();
+        for (Method method : clientMethods) {
+
+            for (Annotation anno : method.getAnnotations()) {
+                Class<? extends Annotation> annoClass = anno.annotationType();
+                HttpMethod verb = annoClass.getAnnotation(HttpMethod.class);
+                if (verb != null) {
+                    httpMethods.put(verb.value(), annoClass);
+                }
+            }
+            if (httpMethods.size() > 1) {
+                throwException("VALIDATION_METHOD_WITH_MULTIPLE_VERBS", method, httpMethods.values());
+            }
+            httpMethods.clear();
+        }
+
+    }
+
+    private static void checkMethodsForInvalidURITemplates(Class<?> userType, Method[]
methods) 
+        throws RestClientDefinitionException {
+
+        Path classPathAnno = userType.getAnnotation(Path.class);
+        
+        final Set<String> classLevelVariables = new HashSet<>();
+        URITemplate classTemplate = null;
+        if (classPathAnno != null) {
+            classTemplate = new URITemplate(classPathAnno.value());
+            classLevelVariables.addAll(classTemplate.getVariables());
+        }
+        URITemplate template;
+        for (Method method : methods) {
+            
+            Path methodPathAnno = method.getAnnotation(Path.class);
+            if (methodPathAnno != null) {
+                template = classPathAnno == null ? new URITemplate(methodPathAnno.value())

+                    : new URITemplate(classPathAnno.value() + "/" + methodPathAnno.value());
+            } else {
+                template = classTemplate;
+            }
+            if (template == null) {
+                continue;
+            }
+            Set<String> allVariables = new HashSet<>(template.getVariables());
+            if (!allVariables.isEmpty()) {
+                Map<String, String> paramMap = new HashMap<>();
+                for (Parameter p : method.getParameters()) {
+                    PathParam pathParam = p.getAnnotation(PathParam.class);
+                    if (pathParam != null) {
+                        paramMap.put(pathParam.value(), "x");
+                    }
+                }
+                try {
+                    template.substitute(paramMap, Collections.<String>emptySet(), false);
+                } catch (IllegalArgumentException ex) {
+                    throwException("VALIDATION_UNRESOLVED_PATH_PARAMS", userType, method);
+                }
+            }
+        }
+    }
+
+    private static void throwException(String msgKey, Object...msgParams) throws RestClientDefinitionException
{
+        Message msg = new Message(msgKey, BUNDLE, msgParams);
+        throw new RestClientDefinitionException(msg.toString());
+    }
+
+}
diff --git a/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/ValidatorTest.java
b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/ValidatorTest.java
new file mode 100644
index 0000000..7877574
--- /dev/null
+++ b/rt/rs/microprofile-client/src/test/java/org/apache/cxf/microprofile/client/ValidatorTest.java
@@ -0,0 +1,134 @@
+/**
+ * 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.net.MalformedURLException;
+import java.net.URL;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.Response;
+
+import org.eclipse.microprofile.rest.client.RestClientBuilder;
+import org.eclipse.microprofile.rest.client.RestClientDefinitionException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ValidatorTest extends Assert {
+
+    public abstract static class NotAnInterface {
+        @GET
+        public abstract Response get();
+    }
+
+    public interface MultiVerbMethod {
+        @GET
+        Response get();
+        @PUT
+        Response put(String x);
+        @POST
+        @DELETE
+        Response postAndDelete();
+    }
+
+    @Path("/rest/{class}")
+    public interface UnresolvedClassUriTemplate {
+        @GET
+        Response myUnresolvedMethod();
+    }
+
+    @Path("/rest")
+    public interface UnresolvedMethodUriTemplate {
+        @Path("/{method}")
+        @GET
+        Response myOtherUnresolvedMethod();
+    }
+
+    @Path("/rest/{class}")
+    public interface PartiallyResolvedUriTemplate {
+        @GET
+        Response get(@PathParam("class")String className);
+
+        @PUT
+        @Path("/{method}")
+        Response put(@PathParam("method")String methodName);
+    }
+
+    @Path("/rest/{class}")
+    public interface PartiallyResolvedUriTemplate2 {
+        @DELETE
+        Response delete(@PathParam("class")String className);
+
+        @POST
+        @Path("/{method}")
+        Response post(@PathParam("class")String className);
+    }
+
+    private static RestClientBuilder newBuilder() {
+        RestClientBuilder builder = RestClientBuilder.newBuilder();
+        try {
+            builder = builder.baseUrl(new URL("http://localhost:8080/test"));
+        } catch (MalformedURLException e) {
+            fail("MalformedURL - bad testcase");
+        }
+        return builder;
+    }
+
+    @Test
+    public void testNotAnInterface() {
+        test(NotAnInterface.class, "is not an interface", "NotAnInterface");
+    }
+
+    @Test
+    public void testMethodWithMultipleVerbs() {
+        test(MultiVerbMethod.class, "more than one HTTP method", "postAndDelete", "javax.ws.rs.POST",
+            "javax.ws.rs.DELETE");
+    }
+
+    @Test
+    public void testUnresolvedUriTemplates() {
+        test(UnresolvedClassUriTemplate.class, "unresolved path template variables", "UnresolvedClassUriTemplate",
+            "myUnresolvedMethod");
+        test(UnresolvedMethodUriTemplate.class, "unresolved path template variables", "UnresolvedMethodUriTemplate",
+            "myOtherUnresolvedMethod");
+        test(PartiallyResolvedUriTemplate.class, "unresolved path template variables", "PartiallyResolvedUriTemplate",
+            "put");
+        test(PartiallyResolvedUriTemplate2.class, "unresolved path template variables", "PartiallyResolvedUriTemplate2",
+            "post");
+    }
+
+    private void test(Class<?> clientInterface, String...expectedMessageTexts) {
+        try {
+            newBuilder().build(clientInterface);
+            fail("Expected RestClientDefinitionException");
+        } catch (RestClientDefinitionException ex) {
+            String msgText = ex.getMessage();
+            assertNotNull("No message text in RestClientDefinitionException", msgText);
+            for (String expectedMessageText : expectedMessageTexts) {
+                assertTrue("Exception text does not contain expected message: " + expectedMessageText,

+                           msgText.contains(expectedMessageText));
+            }
+        }
+    }
+}

-- 
To stop receiving notification emails like this one, please contact
"commits@cxf.apache.org" <commits@cxf.apache.org>.

Mime
View raw message