You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by jo...@apache.org on 2017/12/20 12:07:41 UTC
[cxf] 01/02: MP Rest Client interface validation tests
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 5855485896b77c4e929d0128485b113b9a0f0387
Author: Andy McCright <j....@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" <co...@cxf.apache.org>.