From 2b0eb5025a06d5cb89ed1a87d2b59be89c2a8e2b Mon Sep 17 00:00:00 2001 From: "adrian.f.cole" Date: Sun, 19 Jul 2009 17:33:17 +0000 Subject: [PATCH] Issue 76: New interface annotation parsing: 1. HttpRequestOptions can now be a vararg option. While we only support one element at the moment, it can cut down on repetition. ex. public List listStuff(); public List listStuff(ListOptions options); becomes public List listStuff(ListOptions ... options); This is especially important when attempting to limit the copy-pasting of annotations which are the same between slight deviations 2. HttpRequestOptions can now create a path suffix. Again, this is to cut down on redundancy in the api: ex. public List listStuff(); public List listStuff(ListOptions options); @Path(/details) public List listStuffDetails(); @Path(/details) public List listStuffDetails(ListOptions options); becomes public List listStuff(ListOptions ... options); where ListOptions contains withDetails option. example usage: List servers = connection.listServers(withDetails()); git-svn-id: http://jclouds.googlecode.com/svn/trunk@1652 3d8758e0-26b5-11de-8745-db77d3ebf521 --- .../http/options/BaseHttpRequestOptions.java | 5 +++ .../http/options/HttpRequestOptions.java | 4 ++- .../rest/JaxrsAnnotationProcessor.java | 34 ++++++++++++++++--- .../rest/JaxrsAnnotationProcessorTest.java | 26 ++++++++++++++ 4 files changed, 64 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/jclouds/http/options/BaseHttpRequestOptions.java b/core/src/main/java/org/jclouds/http/options/BaseHttpRequestOptions.java index a28c3f694f..cae9926654 100644 --- a/core/src/main/java/org/jclouds/http/options/BaseHttpRequestOptions.java +++ b/core/src/main/java/org/jclouds/http/options/BaseHttpRequestOptions.java @@ -40,6 +40,7 @@ public class BaseHttpRequestOptions implements HttpRequestOptions { protected Multimap queryParameters = HashMultimap.create(); protected Multimap headers = HashMultimap.create(); protected String entity; + protected String pathSuffix; public String buildStringEntity() { return entity; @@ -76,4 +77,8 @@ public class BaseHttpRequestOptions implements HttpRequestOptions { return matrixParameters; } + public String buildPathSuffix() { + return pathSuffix; + } + } \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/http/options/HttpRequestOptions.java b/core/src/main/java/org/jclouds/http/options/HttpRequestOptions.java index b88065e493..b8b97ed802 100644 --- a/core/src/main/java/org/jclouds/http/options/HttpRequestOptions.java +++ b/core/src/main/java/org/jclouds/http/options/HttpRequestOptions.java @@ -53,7 +53,9 @@ public interface HttpRequestOptions { * @return multimap that may contain matrix parameters. */ Multimap buildMatrixParameters(); - + String buildStringEntity(); + String buildPathSuffix(); + } \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/rest/JaxrsAnnotationProcessor.java b/core/src/main/java/org/jclouds/rest/JaxrsAnnotationProcessor.java index 482f30b8c8..ce433f7880 100644 --- a/core/src/main/java/org/jclouds/rest/JaxrsAnnotationProcessor.java +++ b/core/src/main/java/org/jclouds/rest/JaxrsAnnotationProcessor.java @@ -54,6 +54,7 @@ import org.jclouds.http.functions.ParseSax.HandlerWithResult; import org.jclouds.http.options.HttpRequestOptions; import org.jclouds.logging.Logger; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; @@ -128,13 +129,17 @@ public class JaxrsAnnotationProcessor { } + private static final Class optionsVarArgsClass = new HttpRequestOptions[] {} + .getClass(); + private final Map> methodToIndexesOfOptions = new MapMaker() .makeComputingMap(new Function>() { public Set apply(final Method method) { Set toReturn = Sets.newHashSet(); for (int index = 0; index < method.getParameterTypes().length; index++) { Class type = method.getParameterTypes()[index]; - if (HttpRequestOptions.class.isAssignableFrom(type)) + if (HttpRequestOptions.class.isAssignableFrom(type) + || optionsVarArgsClass.isAssignableFrom(type)) toReturn.add(index); } return toReturn; @@ -147,7 +152,8 @@ public class JaxrsAnnotationProcessor { private final ParseSax.Factory parserFactory; - Function createResponseParser(Method method) { + @VisibleForTesting + public Function createResponseParser(Method method) { Function transformer; Class> handler = getXMLTransformerOrNull(method); if (handler != null) { @@ -158,7 +164,8 @@ public class JaxrsAnnotationProcessor { return transformer; } - Function createExceptionParserOrNullIfNotFound(Method method) { + @VisibleForTesting + public Function createExceptionParserOrNullIfNotFound(Method method) { ExceptionParser annotation = method.getAnnotation(ExceptionParser.class); if (annotation != null) { return injector.getInstance(annotation.value()); @@ -227,6 +234,10 @@ public class JaxrsAnnotationProcessor { for (Entry matrix : options.buildMatrixParameters().entries()) { builder.matrixParam(matrix.getKey(), matrix.getValue()); } + String pathSuffix = options.buildPathSuffix(); + if (pathSuffix != null) { + builder.path(pathSuffix); + } } URI endPoint; @@ -444,7 +455,22 @@ public class JaxrsAnnotationProcessor { private HttpRequestOptions findOptionsIn(Method method, Object[] args) { for (int index : methodToIndexesOfOptions.get(method)) { - return (HttpRequestOptions) args[index]; + if (args.length >= index + 1) {// accomodate varargs + if (optionsVarArgsClass.isAssignableFrom(args[index].getClass())) { + HttpRequestOptions[] options = (HttpRequestOptions[]) args[index]; + if (options.length == 0) { + return null; + } else if (options.length == 1) { + return options[0]; + } else { + throw new IllegalArgumentException( + "we currently do not support multiple varargs options in: " + + method.getName()); + } + } else { + return (HttpRequestOptions) args[index]; + } + } } return null; } diff --git a/core/src/test/java/org/jclouds/rest/JaxrsAnnotationProcessorTest.java b/core/src/test/java/org/jclouds/rest/JaxrsAnnotationProcessorTest.java index dd577c3e82..c3b1d7b25f 100644 --- a/core/src/test/java/org/jclouds/rest/JaxrsAnnotationProcessorTest.java +++ b/core/src/test/java/org/jclouds/rest/JaxrsAnnotationProcessorTest.java @@ -390,6 +390,13 @@ public class JaxrsAnnotationProcessorTest { return null; } + @GET + @VirtualHost + @Path("/{id}") + public Future get(@PathParam("id") String id, HttpRequestOptions... options) { + return null; + } + @GET @Path("/{id}") @ResponseParser(ReturnStringIf200.class) @@ -435,6 +442,25 @@ public class JaxrsAnnotationProcessorTest { } } + public void testCreateGetVarArgOptionsThatProducesHeaders() throws SecurityException, + NoSuchMethodException { + DateTime date = new DateTime(); + GetOptions options = GetOptions.Builder.ifModifiedSince(date); + HttpRequestOptions[] optionsHolder = new HttpRequestOptions[]{}; + Method method = TestRequest.class.getMethod("get", String.class, optionsHolder.getClass()); + URI endpoint = URI.create("http://localhost"); + HttpRequest httpMethod = factory.create(TestRequest.class).createRequest(endpoint, method, + new Object[] { "1", options }); + assertEquals(httpMethod.getEndpoint().getHost(), "localhost"); + assertEquals(httpMethod.getEndpoint().getPath(), "/1"); + assertEquals(httpMethod.getMethod(), HttpMethod.GET); + assertEquals(httpMethod.getHeaders().size(), 2); + assertEquals(httpMethod.getHeaders().get(HttpHeaders.HOST), Collections + .singletonList("localhost")); + assertEquals(httpMethod.getHeaders().get(HttpHeaders.IF_MODIFIED_SINCE), Collections + .singletonList(dateService.rfc822DateFormat(date))); + } + public void testCreateGetOptionsThatProducesHeaders() throws SecurityException, NoSuchMethodException { DateTime date = new DateTime();