mirror of https://github.com/apache/jclouds.git
added means to supply default parameters to a MapBinder
This commit is contained in:
parent
f2b074e2a5
commit
e726d74a9d
|
@ -0,0 +1,46 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* Licensed 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.jclouds.rest.annotations;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.METHOD;
|
||||||
|
import static java.lang.annotation.ElementType.TYPE;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import javax.ws.rs.QueryParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Designates that default parameters will be added a map that builds the request entity.
|
||||||
|
*
|
||||||
|
* @see QueryParam
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Target( { TYPE, METHOD })
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public @interface MapPayloadParams {
|
||||||
|
|
||||||
|
public static final String NULL = "MAP_PAYLOAD_NULL";
|
||||||
|
|
||||||
|
String[] keys();
|
||||||
|
|
||||||
|
String[] values() default NULL;
|
||||||
|
}
|
|
@ -111,6 +111,7 @@ import org.jclouds.rest.annotations.FormParams;
|
||||||
import org.jclouds.rest.annotations.Headers;
|
import org.jclouds.rest.annotations.Headers;
|
||||||
import org.jclouds.rest.annotations.MapBinder;
|
import org.jclouds.rest.annotations.MapBinder;
|
||||||
import org.jclouds.rest.annotations.MapPayloadParam;
|
import org.jclouds.rest.annotations.MapPayloadParam;
|
||||||
|
import org.jclouds.rest.annotations.MapPayloadParams;
|
||||||
import org.jclouds.rest.annotations.MatrixParams;
|
import org.jclouds.rest.annotations.MatrixParams;
|
||||||
import org.jclouds.rest.annotations.OverrideRequestFilters;
|
import org.jclouds.rest.annotations.OverrideRequestFilters;
|
||||||
import org.jclouds.rest.annotations.ParamParser;
|
import org.jclouds.rest.annotations.ParamParser;
|
||||||
|
@ -164,7 +165,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
static final Map<MethodKey, Method> delegationMap = newHashMap();
|
static final Map<MethodKey, Method> delegationMap = newHashMap();
|
||||||
|
|
||||||
static Map<Method, Map<Integer, Set<Annotation>>> createMethodToIndexOfParamToAnnotation(
|
static Map<Method, Map<Integer, Set<Annotation>>> createMethodToIndexOfParamToAnnotation(
|
||||||
final Class<? extends Annotation> annotation) {
|
final Class<? extends Annotation> annotation) {
|
||||||
return new MapMaker().makeComputingMap(new Function<Method, Map<Integer, Set<Annotation>>>() {
|
return new MapMaker().makeComputingMap(new Function<Method, Map<Integer, Set<Annotation>>>() {
|
||||||
public Map<Integer, Set<Annotation>> apply(final Method method) {
|
public Map<Integer, Set<Annotation>> apply(final Method method) {
|
||||||
return new MapMaker().makeComputingMap(new GetAnnotationsForMethodParameterIndex(method, annotation));
|
return new MapMaker().makeComputingMap(new GetAnnotationsForMethodParameterIndex(method, annotation));
|
||||||
|
@ -198,7 +199,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Class<? extends HttpRequestOptions[]> optionsVarArgsClass = new HttpRequestOptions[] {}
|
private static final Class<? extends HttpRequestOptions[]> optionsVarArgsClass = new HttpRequestOptions[] {}
|
||||||
.getClass();
|
.getClass();
|
||||||
|
|
||||||
private static final Function<? super Entry<String, String>, ? extends Part> ENTRY_TO_PART = new Function<Entry<String, String>, Part>() {
|
private static final Function<? super Entry<String, String>, ? extends Part> ENTRY_TO_PART = new Function<Entry<String, String>, Part>() {
|
||||||
|
|
||||||
|
@ -210,17 +211,17 @@ public class RestAnnotationProcessor<T> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private final Map<Method, Set<Integer>> methodToIndexesOfOptions = new MapMaker()
|
private final Map<Method, Set<Integer>> methodToIndexesOfOptions = new MapMaker()
|
||||||
.makeComputingMap(new Function<Method, Set<Integer>>() {
|
.makeComputingMap(new Function<Method, Set<Integer>>() {
|
||||||
public Set<Integer> apply(final Method method) {
|
public Set<Integer> apply(final Method method) {
|
||||||
Set<Integer> toReturn = newHashSet();
|
Set<Integer> toReturn = newHashSet();
|
||||||
for (int index = 0; index < method.getParameterTypes().length; index++) {
|
for (int index = 0; index < method.getParameterTypes().length; index++) {
|
||||||
Class<?> type = method.getParameterTypes()[index];
|
Class<?> type = method.getParameterTypes()[index];
|
||||||
if (HttpRequestOptions.class.isAssignableFrom(type) || optionsVarArgsClass.isAssignableFrom(type))
|
if (HttpRequestOptions.class.isAssignableFrom(type) || optionsVarArgsClass.isAssignableFrom(type))
|
||||||
toReturn.add(index);
|
toReturn.add(index);
|
||||||
|
}
|
||||||
|
return toReturn;
|
||||||
}
|
}
|
||||||
return toReturn;
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
private final ParseSax.Factory parserFactory;
|
private final ParseSax.Factory parserFactory;
|
||||||
private final HttpUtils utils;
|
private final HttpUtils utils;
|
||||||
|
@ -238,7 +239,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public static Function<HttpResponse, ?> createResponseParser(ParseSax.Factory parserFactory, Injector injector,
|
public static Function<HttpResponse, ?> createResponseParser(ParseSax.Factory parserFactory, Injector injector,
|
||||||
Method method, HttpRequest request) {
|
Method method, HttpRequest request) {
|
||||||
Function<HttpResponse, ?> transformer;
|
Function<HttpResponse, ?> transformer;
|
||||||
Class<? extends HandlerWithResult<?>> handler = getSaxResponseParserClassOrNull(method);
|
Class<? extends HandlerWithResult<?>> handler = getSaxResponseParserClassOrNull(method);
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
|
@ -259,7 +260,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public static Function<Exception, ?> createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(
|
public static Function<Exception, ?> createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(
|
||||||
Injector injector, Method method) {
|
Injector injector, Method method) {
|
||||||
ExceptionParser annotation = method.getAnnotation(ExceptionParser.class);
|
ExceptionParser annotation = method.getAnnotation(ExceptionParser.class);
|
||||||
if (annotation != null) {
|
if (annotation != null) {
|
||||||
return injector.getInstance(annotation.value());
|
return injector.getInstance(annotation.value());
|
||||||
|
@ -270,7 +271,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Inject
|
@Inject
|
||||||
public RestAnnotationProcessor(Injector injector, ParseSax.Factory parserFactory, HttpUtils utils,
|
public RestAnnotationProcessor(Injector injector, ParseSax.Factory parserFactory, HttpUtils utils,
|
||||||
TypeLiteral<T> typeLiteral) {
|
TypeLiteral<T> typeLiteral) {
|
||||||
this.declaring = (Class<T>) typeLiteral.getRawType();
|
this.declaring = (Class<T>) typeLiteral.getRawType();
|
||||||
this.injector = injector;
|
this.injector = injector;
|
||||||
this.parserFactory = parserFactory;
|
this.parserFactory = parserFactory;
|
||||||
|
@ -385,7 +386,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
public GeneratedHttpRequest<T> createRequest(Method method, Object... args) {
|
public GeneratedHttpRequest<T> createRequest(Method method, Object... args) {
|
||||||
inputParamValidator.validateMethodParametersOrThrow(method, args);
|
inputParamValidator.validateMethodParametersOrThrow(method, args);
|
||||||
ClassMethodArgs cma = logger.isTraceEnabled() ? new ClassMethodArgs(method.getDeclaringClass(), method, args)
|
ClassMethodArgs cma = logger.isTraceEnabled() ? new ClassMethodArgs(method.getDeclaringClass(), method, args)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
URI endpoint = callerEndpoint;
|
URI endpoint = callerEndpoint;
|
||||||
try {
|
try {
|
||||||
|
@ -458,7 +459,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
GeneratedHttpRequest<T> request = new GeneratedHttpRequest<T>(httpMethod, endpoint, skips, declaring, method,
|
GeneratedHttpRequest<T> request = new GeneratedHttpRequest<T>(httpMethod, endpoint, skips, declaring, method,
|
||||||
args);
|
args);
|
||||||
addHostHeaderIfAnnotatedWithVirtualHost(headers, request.getEndpoint().getHost(), method);
|
addHostHeaderIfAnnotatedWithVirtualHost(headers, request.getEndpoint().getHost(), method);
|
||||||
addFiltersIfAnnotated(method, request);
|
addFiltersIfAnnotated(method, request);
|
||||||
|
|
||||||
|
@ -488,7 +489,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
builder.path(clazz);
|
builder.path(clazz);
|
||||||
builder.path(method);
|
builder.path(method);
|
||||||
return builder.buildFromEncodedMap(convertUnsafe(encodeValues(getPathParamKeyValues(method, args), skips)))
|
return builder.buildFromEncodedMap(convertUnsafe(encodeValues(getPathParamKeyValues(method, args), skips)))
|
||||||
.getPath();
|
.getPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Multimap<String, String> addPathAndGetTokens(Class<?> clazz, Method method, Object[] args, UriBuilder builder) {
|
private Multimap<String, String> addPathAndGetTokens(Class<?> clazz, Method method, Object[] args, UriBuilder builder) {
|
||||||
|
@ -503,14 +504,14 @@ public class RestAnnotationProcessor<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static URI replaceQuery(Provider<UriBuilder> uriBuilderProvider, URI in, String newQuery,
|
public static URI replaceQuery(Provider<UriBuilder> uriBuilderProvider, URI in, String newQuery,
|
||||||
@Nullable Comparator<Entry<String, String>> sorter, char... skips) {
|
@Nullable Comparator<Entry<String, String>> sorter, char... skips) {
|
||||||
UriBuilder builder = uriBuilderProvider.get().uri(in);
|
UriBuilder builder = uriBuilderProvider.get().uri(in);
|
||||||
builder.replaceQuery(makeQueryLine(parseQueryToMap(newQuery), sorter, skips));
|
builder.replaceQuery(makeQueryLine(parseQueryToMap(newQuery), sorter, skips));
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addMatrixParams(UriBuilder builder, Collection<Entry<String, String>> tokenValues, Method method,
|
private void addMatrixParams(UriBuilder builder, Collection<Entry<String, String>> tokenValues, Method method,
|
||||||
Object... args) {
|
Object... args) {
|
||||||
if (declaring.isAnnotationPresent(MatrixParams.class)) {
|
if (declaring.isAnnotationPresent(MatrixParams.class)) {
|
||||||
MatrixParams matrix = declaring.getAnnotation(MatrixParams.class);
|
MatrixParams matrix = declaring.getAnnotation(MatrixParams.class);
|
||||||
addMatrix(builder, matrix, tokenValues);
|
addMatrix(builder, matrix, tokenValues);
|
||||||
|
@ -527,7 +528,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Multimap<String, String> addFormParams(Collection<Entry<String, String>> tokenValues, Method method,
|
private Multimap<String, String> addFormParams(Collection<Entry<String, String>> tokenValues, Method method,
|
||||||
Object... args) {
|
Object... args) {
|
||||||
Multimap<String, String> formMap = LinkedListMultimap.create();
|
Multimap<String, String> formMap = LinkedListMultimap.create();
|
||||||
if (declaring.isAnnotationPresent(FormParams.class)) {
|
if (declaring.isAnnotationPresent(FormParams.class)) {
|
||||||
FormParams form = declaring.getAnnotation(FormParams.class);
|
FormParams form = declaring.getAnnotation(FormParams.class);
|
||||||
|
@ -546,7 +547,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Multimap<String, String> addQueryParams(Collection<Entry<String, String>> tokenValues, Method method,
|
private Multimap<String, String> addQueryParams(Collection<Entry<String, String>> tokenValues, Method method,
|
||||||
Object... args) {
|
Object... args) {
|
||||||
Multimap<String, String> queryMap = LinkedListMultimap.create();
|
Multimap<String, String> queryMap = LinkedListMultimap.create();
|
||||||
if (declaring.isAnnotationPresent(QueryParams.class)) {
|
if (declaring.isAnnotationPresent(QueryParams.class)) {
|
||||||
QueryParams query = declaring.getAnnotation(QueryParams.class);
|
QueryParams query = declaring.getAnnotation(QueryParams.class);
|
||||||
|
@ -565,7 +566,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addForm(Multimap<String, String> formParams, FormParams form,
|
private void addForm(Multimap<String, String> formParams, FormParams form,
|
||||||
Collection<Entry<String, String>> tokenValues) {
|
Collection<Entry<String, String>> tokenValues) {
|
||||||
for (int i = 0; i < form.keys().length; i++) {
|
for (int i = 0; i < form.keys().length; i++) {
|
||||||
if (form.values()[i].equals(FormParams.NULL)) {
|
if (form.values()[i].equals(FormParams.NULL)) {
|
||||||
formParams.removeAll(form.keys()[i]);
|
formParams.removeAll(form.keys()[i]);
|
||||||
|
@ -576,8 +577,19 @@ public class RestAnnotationProcessor<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addMapPayload(Map<String, String> postParams, MapPayloadParams mapDefaults,
|
||||||
|
Collection<Entry<String, String>> tokenValues) {
|
||||||
|
for (int i = 0; i < mapDefaults.keys().length; i++) {
|
||||||
|
if (mapDefaults.values()[i].equals(MapPayloadParams.NULL)) {
|
||||||
|
postParams.put(mapDefaults.keys()[i], null);
|
||||||
|
} else {
|
||||||
|
postParams.put(mapDefaults.keys()[i], replaceTokens(mapDefaults.values()[i], tokenValues));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void addQuery(Multimap<String, String> queryParams, QueryParams query,
|
private void addQuery(Multimap<String, String> queryParams, QueryParams query,
|
||||||
Collection<Entry<String, String>> tokenValues) {
|
Collection<Entry<String, String>> tokenValues) {
|
||||||
for (int i = 0; i < query.keys().length; i++) {
|
for (int i = 0; i < query.keys().length; i++) {
|
||||||
if (query.values()[i].equals(QueryParams.NULL)) {
|
if (query.values()[i].equals(QueryParams.NULL)) {
|
||||||
queryParams.removeAll(query.keys()[i]);
|
queryParams.removeAll(query.keys()[i]);
|
||||||
|
@ -620,7 +632,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public static URI getEndpointInParametersOrNull(Method method, final Object[] args, Injector injector) {
|
public static URI getEndpointInParametersOrNull(Method method, final Object[] args, Injector injector) {
|
||||||
Map<Integer, Set<Annotation>> map = indexWithAtLeastOneAnnotation(method,
|
Map<Integer, Set<Annotation>> map = indexWithAtLeastOneAnnotation(method,
|
||||||
methodToIndexOfParamToEndpointParamAnnotations);
|
methodToIndexOfParamToEndpointParamAnnotations);
|
||||||
if (map.size() >= 1 && args.length > 0) {
|
if (map.size() >= 1 && args.length > 0) {
|
||||||
EndpointParam firstAnnotation = (EndpointParam) get(get(map.values(), 0), 0);
|
EndpointParam firstAnnotation = (EndpointParam) get(get(map.values(), 0), 0);
|
||||||
Function<Object, URI> parser = injector.getInstance(firstAnnotation.parser());
|
Function<Object, URI> parser = injector.getInstance(firstAnnotation.parser());
|
||||||
|
@ -630,7 +642,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
try {
|
try {
|
||||||
URI returnVal = parser.apply(args[index]);
|
URI returnVal = parser.apply(args[index]);
|
||||||
checkArgument(returnVal != null, String.format("endpoint for [%s] not configured for %s", args[index],
|
checkArgument(returnVal != null, String.format("endpoint for [%s] not configured for %s", args[index],
|
||||||
method));
|
method));
|
||||||
return returnVal;
|
return returnVal;
|
||||||
} catch (NullPointerException e) {
|
} catch (NullPointerException e) {
|
||||||
throw new IllegalArgumentException(String.format("argument at index %d on method %s", index, method), e);
|
throw new IllegalArgumentException(String.format("argument at index %d on method %s", index, method), e);
|
||||||
|
@ -648,11 +660,11 @@ public class RestAnnotationProcessor<T> {
|
||||||
try {
|
try {
|
||||||
URI returnVal = parser.apply(argsToParse);
|
URI returnVal = parser.apply(argsToParse);
|
||||||
checkArgument(returnVal != null, String.format("endpoint for [%s] not configured for %s", argsToParse,
|
checkArgument(returnVal != null, String.format("endpoint for [%s] not configured for %s", argsToParse,
|
||||||
method));
|
method));
|
||||||
return returnVal;
|
return returnVal;
|
||||||
} catch (NullPointerException e) {
|
} catch (NullPointerException e) {
|
||||||
throw new IllegalArgumentException(String.format("argument at indexes %s on method %s", map.keySet(),
|
throw new IllegalArgumentException(String.format("argument at indexes %s on method %s", map.keySet(),
|
||||||
method), e);
|
method), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -693,13 +705,13 @@ public class RestAnnotationProcessor<T> {
|
||||||
ResponseParser annotation = method.getAnnotation(ResponseParser.class);
|
ResponseParser annotation = method.getAnnotation(ResponseParser.class);
|
||||||
if (annotation == null) {
|
if (annotation == null) {
|
||||||
if (method.getReturnType().equals(void.class)
|
if (method.getReturnType().equals(void.class)
|
||||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureVoidLiteral)) {
|
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureVoidLiteral)) {
|
||||||
return Key.get(ReleasePayloadAndReturn.class);
|
return Key.get(ReleasePayloadAndReturn.class);
|
||||||
} else if (method.getReturnType().equals(boolean.class) || method.getReturnType().equals(Boolean.class)
|
} else if (method.getReturnType().equals(boolean.class) || method.getReturnType().equals(Boolean.class)
|
||||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureBooleanLiteral)) {
|
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureBooleanLiteral)) {
|
||||||
return Key.get(ReturnTrueIf2xx.class);
|
return Key.get(ReturnTrueIf2xx.class);
|
||||||
} else if (method.getReturnType().equals(InputStream.class)
|
} else if (method.getReturnType().equals(InputStream.class)
|
||||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureInputStreamLiteral)) {
|
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureInputStreamLiteral)) {
|
||||||
return Key.get(ReturnInputStream.class);
|
return Key.get(ReturnInputStream.class);
|
||||||
} else if (getAcceptHeadersOrNull(method).contains(MediaType.APPLICATION_JSON)) {
|
} else if (getAcceptHeadersOrNull(method).contains(MediaType.APPLICATION_JSON)) {
|
||||||
Type returnVal;
|
Type returnVal;
|
||||||
|
@ -720,10 +732,10 @@ public class RestAnnotationProcessor<T> {
|
||||||
parserType = Types.newParameterizedType(ParseJson.class, returnVal);
|
parserType = Types.newParameterizedType(ParseJson.class, returnVal);
|
||||||
return (Key<? extends Function<HttpResponse, ?>>) Key.get(parserType);
|
return (Key<? extends Function<HttpResponse, ?>>) Key.get(parserType);
|
||||||
} else if (method.getReturnType().equals(String.class)
|
} else if (method.getReturnType().equals(String.class)
|
||||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureStringLiteral)) {
|
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureStringLiteral)) {
|
||||||
return Key.get(ReturnStringIf2xx.class);
|
return Key.get(ReturnStringIf2xx.class);
|
||||||
} else if (method.getReturnType().equals(URI.class)
|
} else if (method.getReturnType().equals(URI.class)
|
||||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureURILiteral)) {
|
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureURILiteral)) {
|
||||||
return Key.get(ParseURIFromListOrLocationHeaderIf20x.class);
|
return Key.get(ParseURIFromListOrLocationHeaderIf20x.class);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("You must specify a ResponseParser annotation on: " + method.toString());
|
throw new IllegalStateException("You must specify a ResponseParser annotation on: " + method.toString());
|
||||||
|
@ -755,7 +767,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
} else {
|
} else {
|
||||||
if (postBinders[0] instanceof org.jclouds.rest.MapBinder) {
|
if (postBinders[0] instanceof org.jclouds.rest.MapBinder) {
|
||||||
throw new IllegalArgumentException("we currently do not support multiple varargs postBinders in: "
|
throw new IllegalArgumentException("we currently do not support multiple varargs postBinders in: "
|
||||||
+ method.getName());
|
+ method.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (arg instanceof org.jclouds.rest.MapBinder) {
|
} else if (arg instanceof org.jclouds.rest.MapBinder) {
|
||||||
|
@ -792,8 +804,8 @@ public class RestAnnotationProcessor<T> {
|
||||||
Set<String> requests = IsHttpMethod.getHttpMethods(method);
|
Set<String> requests = IsHttpMethod.getHttpMethods(method);
|
||||||
if (requests == null || requests.size() != 1) {
|
if (requests == null || requests.size() != 1) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"You must use at least one, but no more than one http method or pathparam annotation on: "
|
"You must use at least one, but no more than one http method or pathparam annotation on: "
|
||||||
+ method.toString());
|
+ method.toString());
|
||||||
}
|
}
|
||||||
return requests.iterator().next();
|
return requests.iterator().next();
|
||||||
}
|
}
|
||||||
|
@ -806,22 +818,21 @@ public class RestAnnotationProcessor<T> {
|
||||||
|
|
||||||
public void decorateRequest(GeneratedHttpRequest<T> request, Multimap<String, String> headers) {
|
public void decorateRequest(GeneratedHttpRequest<T> request, Multimap<String, String> headers) {
|
||||||
org.jclouds.rest.MapBinder mapBinder = getMapPayloadBinderOrNull(request.getJavaMethod(), request.getArgs());
|
org.jclouds.rest.MapBinder mapBinder = getMapPayloadBinderOrNull(request.getJavaMethod(), request.getArgs());
|
||||||
Map<String, String> mapParams = buildPostParams(request.getJavaMethod(), request.getArgs());
|
|
||||||
// MapPayloadBinder is only useful if there are parameters. We guard here
|
|
||||||
// in case the
|
|
||||||
// MapPayloadBinder is also an PayloadBinder. If so, it can be used with
|
|
||||||
// or without
|
|
||||||
// parameters.
|
|
||||||
if (mapBinder != null) {
|
if (mapBinder != null) {
|
||||||
|
Map<String, String> mapParams = buildPostParams(request.getJavaMethod(), request.getArgs());
|
||||||
|
if (request.getJavaMethod().isAnnotationPresent(MapPayloadParams.class)) {
|
||||||
|
MapPayloadParams params = request.getJavaMethod().getAnnotation(MapPayloadParams.class);
|
||||||
|
addMapPayload(mapParams, params, headers.entries());
|
||||||
|
}
|
||||||
mapBinder.bindToRequest(request, mapParams);
|
mapBinder.bindToRequest(request, mapParams);
|
||||||
} else {
|
} else {
|
||||||
OUTER: for (Entry<Integer, Set<Annotation>> entry : filterValues(
|
OUTER: for (Entry<Integer, Set<Annotation>> entry : filterValues(
|
||||||
methodToIndexOfParamToDecoratorParamAnnotation.get(request.getJavaMethod()),
|
methodToIndexOfParamToDecoratorParamAnnotation.get(request.getJavaMethod()),
|
||||||
new Predicate<Set<Annotation>>() {
|
new Predicate<Set<Annotation>>() {
|
||||||
public boolean apply(Set<Annotation> input) {
|
public boolean apply(Set<Annotation> input) {
|
||||||
return input.size() >= 1;
|
return input.size() >= 1;
|
||||||
}
|
}
|
||||||
}).entrySet()) {
|
}).entrySet()) {
|
||||||
boolean shouldBreak = false;
|
boolean shouldBreak = false;
|
||||||
BinderParam payloadAnnotation = (BinderParam) entry.getValue().iterator().next();
|
BinderParam payloadAnnotation = (BinderParam) entry.getValue().iterator().next();
|
||||||
Binder binder = injector.getInstance(payloadAnnotation.value());
|
Binder binder = injector.getInstance(payloadAnnotation.value());
|
||||||
|
@ -857,24 +868,24 @@ public class RestAnnotationProcessor<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<Integer, Set<Annotation>> indexWithOnlyOneAnnotation(Method method, String description,
|
public static Map<Integer, Set<Annotation>> indexWithOnlyOneAnnotation(Method method, String description,
|
||||||
Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
|
Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
|
||||||
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = indexWithAtLeastOneAnnotation(method, toRefine);
|
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = indexWithAtLeastOneAnnotation(method, toRefine);
|
||||||
if (indexToPayloadAnnotation.size() > 1) {
|
if (indexToPayloadAnnotation.size() > 1) {
|
||||||
throw new IllegalStateException(String.format(
|
throw new IllegalStateException(String.format(
|
||||||
"You must not specify more than one %s annotation on: %s; found %s", description, method.toString(),
|
"You must not specify more than one %s annotation on: %s; found %s", description, method.toString(),
|
||||||
indexToPayloadAnnotation));
|
indexToPayloadAnnotation));
|
||||||
}
|
}
|
||||||
return indexToPayloadAnnotation;
|
return indexToPayloadAnnotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<Integer, Set<Annotation>> indexWithAtLeastOneAnnotation(Method method,
|
private static Map<Integer, Set<Annotation>> indexWithAtLeastOneAnnotation(Method method,
|
||||||
Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
|
Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
|
||||||
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = filterValues(toRefine.get(method),
|
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = filterValues(toRefine.get(method),
|
||||||
new Predicate<Set<Annotation>>() {
|
new Predicate<Set<Annotation>>() {
|
||||||
public boolean apply(Set<Annotation> input) {
|
public boolean apply(Set<Annotation> input) {
|
||||||
return input.size() == 1;
|
return input.size() == 1;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return indexToPayloadAnnotation;
|
return indexToPayloadAnnotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -893,7 +904,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
} else {
|
} else {
|
||||||
if (options[0] instanceof HttpRequestOptions) {
|
if (options[0] instanceof HttpRequestOptions) {
|
||||||
throw new IllegalArgumentException("we currently do not support multiple varargs options in: "
|
throw new IllegalArgumentException("we currently do not support multiple varargs options in: "
|
||||||
+ method.getName());
|
+ method.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -905,7 +916,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Multimap<String, String> buildHeaders(Collection<Entry<String, String>> tokenValues, Method method,
|
public Multimap<String, String> buildHeaders(Collection<Entry<String, String>> tokenValues, Method method,
|
||||||
final Object... args) {
|
final Object... args) {
|
||||||
Multimap<String, String> headers = LinkedHashMultimap.create();
|
Multimap<String, String> headers = LinkedHashMultimap.create();
|
||||||
addHeaderIfAnnotationPresentOnMethod(headers, method, tokenValues);
|
addHeaderIfAnnotationPresentOnMethod(headers, method, tokenValues);
|
||||||
Map<Integer, Set<Annotation>> indexToHeaderParam = methodToIndexOfParamToHeaderParamAnnotations.get(method);
|
Map<Integer, Set<Annotation>> indexToHeaderParam = methodToIndexOfParamToHeaderParamAnnotations.get(method);
|
||||||
|
@ -952,7 +963,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addHeaderIfAnnotationPresentOnMethod(Multimap<String, String> headers, Method method,
|
public void addHeaderIfAnnotationPresentOnMethod(Multimap<String, String> headers, Method method,
|
||||||
Collection<Entry<String, String>> tokenValues) {
|
Collection<Entry<String, String>> tokenValues) {
|
||||||
if (declaring.isAnnotationPresent(Headers.class)) {
|
if (declaring.isAnnotationPresent(Headers.class)) {
|
||||||
Headers header = declaring.getAnnotation(Headers.class);
|
Headers header = declaring.getAnnotation(Headers.class);
|
||||||
addHeader(headers, header, tokenValues);
|
addHeader(headers, header, tokenValues);
|
||||||
|
@ -964,7 +975,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addHeader(Multimap<String, String> headers, Headers header,
|
private void addHeader(Multimap<String, String> headers, Headers header,
|
||||||
Collection<Entry<String, String>> tokenValues) {
|
Collection<Entry<String, String>> tokenValues) {
|
||||||
for (int i = 0; i < header.keys().length; i++) {
|
for (int i = 0; i < header.keys().length; i++) {
|
||||||
String value = header.values()[i];
|
String value = header.values()[i];
|
||||||
value = replaceTokens(value, tokenValues);
|
value = replaceTokens(value, tokenValues);
|
||||||
|
|
|
@ -119,6 +119,7 @@ import org.jclouds.rest.annotations.FormParams;
|
||||||
import org.jclouds.rest.annotations.Headers;
|
import org.jclouds.rest.annotations.Headers;
|
||||||
import org.jclouds.rest.annotations.MapBinder;
|
import org.jclouds.rest.annotations.MapBinder;
|
||||||
import org.jclouds.rest.annotations.MapPayloadParam;
|
import org.jclouds.rest.annotations.MapPayloadParam;
|
||||||
|
import org.jclouds.rest.annotations.MapPayloadParams;
|
||||||
import org.jclouds.rest.annotations.MatrixParams;
|
import org.jclouds.rest.annotations.MatrixParams;
|
||||||
import org.jclouds.rest.annotations.OverrideRequestFilters;
|
import org.jclouds.rest.annotations.OverrideRequestFilters;
|
||||||
import org.jclouds.rest.annotations.ParamParser;
|
import org.jclouds.rest.annotations.ParamParser;
|
||||||
|
@ -534,25 +535,27 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
|
||||||
assertEquals(request.getMethod(), "POST");
|
assertEquals(request.getMethod(), "POST");
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TestPost {
|
public interface TestPost {
|
||||||
@POST
|
@POST
|
||||||
public void post(@Nullable @BinderParam(BindToStringPayload.class) String content) {
|
void post(@Nullable @BinderParam(BindToStringPayload.class) String content);
|
||||||
}
|
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
public void postAsJson(@BinderParam(BindToJsonPayload.class) String content) {
|
public void postAsJson(@BinderParam(BindToJsonPayload.class) String content);
|
||||||
}
|
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Path("{foo}")
|
@Path("{foo}")
|
||||||
public void postWithPath(@PathParam("foo") @MapPayloadParam("fooble") String path, MapBinder content) {
|
public void postWithPath(@PathParam("foo") @MapPayloadParam("fooble") String path, MapBinder content);
|
||||||
}
|
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Path("{foo}")
|
@Path("{foo}")
|
||||||
@MapBinder(BindToJsonPayload.class)
|
@MapBinder(BindToJsonPayload.class)
|
||||||
public void postWithMethodBinder(@PathParam("foo") @MapPayloadParam("fooble") String path) {
|
public void postWithMethodBinder(@PathParam("foo") @MapPayloadParam("fooble") String path);
|
||||||
}
|
|
||||||
|
@POST
|
||||||
|
@Path("{foo}")
|
||||||
|
@MapPayloadParams(keys = "rat", values = "atat")
|
||||||
|
@MapBinder(BindToJsonPayload.class)
|
||||||
|
public void postWithMethodBinderAndDefaults(@PathParam("foo") @MapPayloadParam("fooble") String path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCreatePostRequest() throws SecurityException, NoSuchMethodException, IOException {
|
public void testCreatePostRequest() throws SecurityException, NoSuchMethodException, IOException {
|
||||||
|
@ -606,6 +609,15 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
|
||||||
assertPayloadEquals(request, "{\"fooble\":\"data\"}", "application/json", false);
|
assertPayloadEquals(request, "{\"fooble\":\"data\"}", "application/json", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testCreatePostWithMethodBinderAndDefaults() throws SecurityException, NoSuchMethodException, IOException {
|
||||||
|
Method method = TestPost.class.getMethod("postWithMethodBinderAndDefaults", String.class);
|
||||||
|
HttpRequest request = factory(TestPost.class).createRequest(method, "data");
|
||||||
|
|
||||||
|
assertRequestLineEquals(request, "POST http://localhost:9999/data HTTP/1.1");
|
||||||
|
assertNonPayloadHeadersEqual(request, "");
|
||||||
|
assertPayloadEquals(request, "{\"fooble\":\"data\",\"rat\":\"atat\"}", "application/json", false);
|
||||||
|
}
|
||||||
|
|
||||||
static interface TestMultipartForm {
|
static interface TestMultipartForm {
|
||||||
@POST
|
@POST
|
||||||
void withStringPart(@PartParam(name = "fooble") String path);
|
void withStringPart(@PartParam(name = "fooble") String path);
|
||||||
|
|
Loading…
Reference in New Issue