mirror of https://github.com/apache/jclouds.git
Cleaned up scoping of delegated methods
This commit is contained in:
parent
436037c7be
commit
891484a2aa
|
@ -0,0 +1,38 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 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 java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import javax.inject.Qualifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply this to implementation classes when you want Access to items from the
|
||||||
|
* scope of a delegate.
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Target( { ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER , ElementType.FIELD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Qualifier
|
||||||
|
public @interface Caller {
|
||||||
|
}
|
|
@ -58,8 +58,8 @@ public class RestClientModule<S, A> extends AbstractModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
public RestClientModule(Class<S> syncClientType, Class<A> asyncClientType) {
|
public RestClientModule(Class<S> syncClientType, Class<A> asyncClientType) {
|
||||||
this(syncClientType, asyncClientType, ImmutableMap.<Class<?>, Class<?>> of(syncClientType,
|
this(syncClientType, asyncClientType, ImmutableMap
|
||||||
asyncClientType));
|
.<Class<?>, Class<?>> of(syncClientType, asyncClientType));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -68,8 +68,9 @@ public class RestClientModule<S, A> extends AbstractModule {
|
||||||
// Ensures the restcontext can be looked up without generic types.
|
// Ensures the restcontext can be looked up without generic types.
|
||||||
bind(new TypeLiteral<RestContext>() {
|
bind(new TypeLiteral<RestContext>() {
|
||||||
}).to(
|
}).to(
|
||||||
(TypeLiteral) TypeLiteral.get(Types.newParameterizedType(RestContextImpl.class,
|
(TypeLiteral) TypeLiteral.get(Types.newParameterizedType(
|
||||||
syncClientType, asyncClientType))).in(Scopes.SINGLETON);
|
RestContextImpl.class, syncClientType, asyncClientType))).in(
|
||||||
|
Scopes.SINGLETON);
|
||||||
bindAsyncClient();
|
bindAsyncClient();
|
||||||
bindClient();
|
bindClient();
|
||||||
bindErrorHandlers();
|
bindErrorHandlers();
|
||||||
|
@ -82,8 +83,10 @@ public class RestClientModule<S, A> extends AbstractModule {
|
||||||
* ex.
|
* ex.
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* bind(HttpRetryHandler.class).annotatedWith(Redirection.class).to(AWSRedirectionRetryHandler.class);
|
* bind(HttpRetryHandler.class).annotatedWith(Redirection.class).to(
|
||||||
* bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(AWSClientErrorRetryHandler.class);
|
* AWSRedirectionRetryHandler.class);
|
||||||
|
* bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(
|
||||||
|
* AWSClientErrorRetryHandler.class);
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -96,9 +99,12 @@ public class RestClientModule<S, A> extends AbstractModule {
|
||||||
* ex.
|
* ex.
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ParseAWSErrorFromXmlContent.class);
|
* bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(
|
||||||
* bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(ParseAWSErrorFromXmlContent.class);
|
* ParseAWSErrorFromXmlContent.class);
|
||||||
* bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseAWSErrorFromXmlContent.class);
|
* bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(
|
||||||
|
* ParseAWSErrorFromXmlContent.class);
|
||||||
|
* bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(
|
||||||
|
* ParseAWSErrorFromXmlContent.class);
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
@ -111,9 +117,11 @@ public class RestClientModule<S, A> extends AbstractModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void bindClient() {
|
protected void bindClient() {
|
||||||
BinderUtils.bindClient(binder(), syncClientType, asyncClientType, delegates);
|
BinderUtils.bindClient(binder(), syncClientType, asyncClientType,
|
||||||
|
delegates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
@Named("sync")
|
@Named("sync")
|
||||||
|
|
|
@ -18,9 +18,9 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.rest.config;
|
package org.jclouds.rest.config;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
|
@ -36,6 +36,7 @@ import org.jclouds.internal.ClassMethodArgs;
|
||||||
import org.jclouds.rest.AsyncClientFactory;
|
import org.jclouds.rest.AsyncClientFactory;
|
||||||
import org.jclouds.rest.HttpAsyncClient;
|
import org.jclouds.rest.HttpAsyncClient;
|
||||||
import org.jclouds.rest.HttpClient;
|
import org.jclouds.rest.HttpClient;
|
||||||
|
import org.jclouds.rest.annotations.Caller;
|
||||||
import org.jclouds.rest.internal.AsyncRestClientProxy;
|
import org.jclouds.rest.internal.AsyncRestClientProxy;
|
||||||
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
import org.jclouds.rest.internal.RestAnnotationProcessor;
|
||||||
|
|
||||||
|
@ -43,8 +44,10 @@ import com.google.common.base.Function;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.MapMaker;
|
import com.google.common.collect.MapMaker;
|
||||||
import com.google.inject.AbstractModule;
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
import com.google.inject.Key;
|
import com.google.inject.Key;
|
||||||
|
import com.google.inject.Module;
|
||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
import com.google.inject.Scopes;
|
import com.google.inject.Scopes;
|
||||||
import com.google.inject.TypeLiteral;
|
import com.google.inject.TypeLiteral;
|
||||||
|
@ -61,10 +64,12 @@ public class RestModule extends AbstractModule {
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
install(new ParserModule());
|
install(new ParserModule());
|
||||||
bind(UriBuilder.class).to(UriBuilderImpl.class);
|
bind(UriBuilder.class).to(UriBuilderImpl.class);
|
||||||
bind(AsyncRestClientProxy.Factory.class).to(Factory.class).in(Scopes.SINGLETON);
|
bind(AsyncRestClientProxy.Factory.class).to(Factory.class).in(
|
||||||
|
Scopes.SINGLETON);
|
||||||
BinderUtils.bindAsyncClient(binder(), HttpAsyncClient.class);
|
BinderUtils.bindAsyncClient(binder(), HttpAsyncClient.class);
|
||||||
BinderUtils.bindClient(binder(), HttpClient.class, HttpAsyncClient.class, ImmutableMap
|
BinderUtils.bindClient(binder(), HttpClient.class, HttpAsyncClient.class,
|
||||||
.<Class<?>, Class<?>> of(HttpClient.class, HttpAsyncClient.class));
|
ImmutableMap.<Class<?>, Class<?>> of(HttpClient.class,
|
||||||
|
HttpAsyncClient.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
@ -75,36 +80,74 @@ public class RestModule extends AbstractModule {
|
||||||
return new MapMaker().makeComputingMap(createAsyncClientForCaller);
|
return new MapMaker().makeComputingMap(createAsyncClientForCaller);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class CreateAsyncClientForCaller implements Function<ClassMethodArgs, Object> {
|
static class CreateAsyncClientForCaller implements
|
||||||
|
Function<ClassMethodArgs, Object> {
|
||||||
private final Injector injector;
|
private final Injector injector;
|
||||||
private final AsyncRestClientProxy.Factory factory;
|
private final AsyncRestClientProxy.Factory factory;
|
||||||
|
|
||||||
|
@Caller
|
||||||
|
@Inject(optional = true)
|
||||||
|
Module callerModule = new CallerScopedBindingModule();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
CreateAsyncClientForCaller(Injector injector, AsyncRestClientProxy.Factory factory) {
|
CreateAsyncClientForCaller(Injector injector,
|
||||||
|
AsyncRestClientProxy.Factory factory) {
|
||||||
this.injector = injector;
|
this.injector = injector;
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public Object apply(ClassMethodArgs from) {
|
public Object apply(final ClassMethodArgs from) {
|
||||||
Class clazz = from.getAsyncClass();
|
Class clazz = from.getAsyncClass();
|
||||||
TypeLiteral typeLiteral = TypeLiteral.get(clazz);
|
TypeLiteral typeLiteral = TypeLiteral.get(clazz);
|
||||||
RestAnnotationProcessor util = (RestAnnotationProcessor) injector.getInstance(Key
|
Injector injector = this.injector.createChildInjector(callerModule,
|
||||||
.get(TypeLiteral.get(Types.newParameterizedType(RestAnnotationProcessor.class,
|
new AbstractModule() {
|
||||||
clazz))));
|
|
||||||
util.setCaller(from);
|
|
||||||
|
|
||||||
ConcurrentMap<ClassMethodArgs, Object> delegateMap = injector.getInstance(Key.get(
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bind(ClassMethodArgs.class).annotatedWith(Caller.class)
|
||||||
|
.toInstance(from);
|
||||||
|
install(callerModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
RestAnnotationProcessor util = (RestAnnotationProcessor) injector
|
||||||
|
.getInstance(Key.get(TypeLiteral.get(Types.newParameterizedType(
|
||||||
|
RestAnnotationProcessor.class, clazz))));
|
||||||
|
// not sure why we have to go back and re-inject this...
|
||||||
|
injector.injectMembers(util);
|
||||||
|
ConcurrentMap<ClassMethodArgs, Object> delegateMap = injector
|
||||||
|
.getInstance(Key.get(
|
||||||
new TypeLiteral<ConcurrentMap<ClassMethodArgs, Object>>() {
|
new TypeLiteral<ConcurrentMap<ClassMethodArgs, Object>>() {
|
||||||
}, Names.named("async")));
|
}, Names.named("async")));
|
||||||
AsyncRestClientProxy proxy = new AsyncRestClientProxy(injector, factory, util,
|
AsyncRestClientProxy proxy = new AsyncRestClientProxy(injector,
|
||||||
typeLiteral, delegateMap);
|
factory, util, typeLiteral, delegateMap);
|
||||||
injector.injectMembers(proxy);
|
injector.injectMembers(proxy);
|
||||||
return AsyncClientFactory.create(clazz, proxy);
|
return AsyncClientFactory.create(clazz, proxy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public static class CallerScopedBindingModule extends AbstractModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Caller
|
||||||
|
URI provideCallerScopedURI(Injector injector, @Caller ClassMethodArgs args) {
|
||||||
|
try {
|
||||||
|
return RestAnnotationProcessor.getEndpointFor(args.getMethod(),
|
||||||
|
args.getArgs(), injector);
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class Factory implements AsyncRestClientProxy.Factory {
|
private static class Factory implements AsyncRestClientProxy.Factory {
|
||||||
@Inject
|
@Inject
|
||||||
private TransformingHttpCommandExecutorService executorService;
|
private TransformingHttpCommandExecutorService executorService;
|
||||||
|
@ -112,7 +155,8 @@ public class RestModule extends AbstractModule {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public TransformingHttpCommand<?> create(HttpRequest request,
|
public TransformingHttpCommand<?> create(HttpRequest request,
|
||||||
Function<HttpResponse, ?> transformer) {
|
Function<HttpResponse, ?> transformer) {
|
||||||
return new TransformingHttpCommandImpl(executorService, request, transformer);
|
return new TransformingHttpCommandImpl(executorService, request,
|
||||||
|
transformer);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,6 @@ package org.jclouds.rest.internal;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static com.google.common.collect.Collections2.filter;
|
import static com.google.common.collect.Collections2.filter;
|
||||||
import static com.google.common.collect.Collections2.transform;
|
|
||||||
import static com.google.common.collect.Iterables.concat;
|
|
||||||
import static com.google.common.collect.Lists.newArrayList;
|
import static com.google.common.collect.Lists.newArrayList;
|
||||||
import static com.google.common.collect.Lists.newLinkedList;
|
import static com.google.common.collect.Lists.newLinkedList;
|
||||||
import static com.google.common.collect.Maps.filterValues;
|
import static com.google.common.collect.Maps.filterValues;
|
||||||
|
@ -37,8 +35,6 @@ import static org.jclouds.http.HttpUtils.makeQueryLine;
|
||||||
import static org.jclouds.http.HttpUtils.parseQueryToMap;
|
import static org.jclouds.http.HttpUtils.parseQueryToMap;
|
||||||
import static org.jclouds.http.HttpUtils.urlEncode;
|
import static org.jclouds.http.HttpUtils.urlEncode;
|
||||||
import static org.jclouds.http.Payloads.newPayload;
|
import static org.jclouds.http.Payloads.newPayload;
|
||||||
import static org.jclouds.http.Payloads.newStringPayload;
|
|
||||||
import static org.jclouds.http.Payloads.newUrlEncodedFormPayload;
|
|
||||||
import static org.jclouds.util.Utils.replaceTokens;
|
import static org.jclouds.util.Utils.replaceTokens;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -76,6 +72,7 @@ import org.jclouds.http.HttpResponse;
|
||||||
import org.jclouds.http.HttpUtils;
|
import org.jclouds.http.HttpUtils;
|
||||||
import org.jclouds.http.Payload;
|
import org.jclouds.http.Payload;
|
||||||
import org.jclouds.http.PayloadEnclosing;
|
import org.jclouds.http.PayloadEnclosing;
|
||||||
|
import org.jclouds.http.Payloads;
|
||||||
import org.jclouds.http.functions.ParseSax;
|
import org.jclouds.http.functions.ParseSax;
|
||||||
import org.jclouds.http.functions.ParseURIFromListOrLocationHeaderIf20x;
|
import org.jclouds.http.functions.ParseURIFromListOrLocationHeaderIf20x;
|
||||||
import org.jclouds.http.functions.ReleasePayloadAndReturn;
|
import org.jclouds.http.functions.ReleasePayloadAndReturn;
|
||||||
|
@ -93,6 +90,7 @@ import org.jclouds.rest.Binder;
|
||||||
import org.jclouds.rest.InputParamValidator;
|
import org.jclouds.rest.InputParamValidator;
|
||||||
import org.jclouds.rest.InvocationContext;
|
import org.jclouds.rest.InvocationContext;
|
||||||
import org.jclouds.rest.annotations.BinderParam;
|
import org.jclouds.rest.annotations.BinderParam;
|
||||||
|
import org.jclouds.rest.annotations.Caller;
|
||||||
import org.jclouds.rest.annotations.Delegate;
|
import org.jclouds.rest.annotations.Delegate;
|
||||||
import org.jclouds.rest.annotations.Endpoint;
|
import org.jclouds.rest.annotations.Endpoint;
|
||||||
import org.jclouds.rest.annotations.EndpointParam;
|
import org.jclouds.rest.annotations.EndpointParam;
|
||||||
|
@ -116,6 +114,7 @@ import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.LinkedHashMultimap;
|
import com.google.common.collect.LinkedHashMultimap;
|
||||||
import com.google.common.collect.LinkedListMultimap;
|
import com.google.common.collect.LinkedListMultimap;
|
||||||
import com.google.common.collect.MapMaker;
|
import com.google.common.collect.MapMaker;
|
||||||
|
@ -136,51 +135,48 @@ public class RestAnnotationProcessor<T> {
|
||||||
@Resource
|
@Resource
|
||||||
protected Logger logger = Logger.NULL;
|
protected Logger logger = Logger.NULL;
|
||||||
|
|
||||||
ClassMethodArgs caller;
|
|
||||||
|
|
||||||
@Inject(optional = true)
|
|
||||||
public void setCaller(@Named("caller") ClassMethodArgs caller) {
|
|
||||||
seedCache(caller.getMethod().getDeclaringClass());
|
|
||||||
this.caller = caller;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Class<T> declaring;
|
private final Class<T> declaring;
|
||||||
|
|
||||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToDecoratorParamAnnotation = createMethodToIndexOfParamToAnnotation(BinderParam.class);
|
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToDecoratorParamAnnotation = createMethodToIndexOfParamToAnnotation(BinderParam.class);
|
||||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToHeaderParamAnnotations = createMethodToIndexOfParamToAnnotation(HeaderParam.class);
|
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToHeaderParamAnnotations = createMethodToIndexOfParamToAnnotation(HeaderParam.class);
|
||||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointAnnotations = createMethodToIndexOfParamToAnnotation(Endpoint.class);
|
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointAnnotations = createMethodToIndexOfParamToAnnotation(Endpoint.class);
|
||||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointParamAnnotations = createMethodToIndexOfParamToAnnotation(EndpointParam.class);
|
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointParamAnnotations = createMethodToIndexOfParamToAnnotation(EndpointParam.class);
|
||||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToMatrixParamAnnotations = createMethodToIndexOfParamToAnnotation(MatrixParam.class);
|
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToMatrixParamAnnotations = createMethodToIndexOfParamToAnnotation(MatrixParam.class);
|
||||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToFormParamAnnotations = createMethodToIndexOfParamToAnnotation(FormParam.class);
|
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToFormParamAnnotations = createMethodToIndexOfParamToAnnotation(FormParam.class);
|
||||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToQueryParamAnnotations = createMethodToIndexOfParamToAnnotation(QueryParam.class);
|
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToQueryParamAnnotations = createMethodToIndexOfParamToAnnotation(QueryParam.class);
|
||||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPathParamAnnotations = createMethodToIndexOfParamToAnnotation(PathParam.class);
|
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPathParamAnnotations = createMethodToIndexOfParamToAnnotation(PathParam.class);
|
||||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPostParamAnnotations = createMethodToIndexOfParamToAnnotation(MapPayloadParam.class);
|
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPostParamAnnotations = createMethodToIndexOfParamToAnnotation(MapPayloadParam.class);
|
||||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPartParamAnnotations = createMethodToIndexOfParamToAnnotation(PartParam.class);
|
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToPartParamAnnotations = createMethodToIndexOfParamToAnnotation(PartParam.class);
|
||||||
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToParamParserAnnotations = createMethodToIndexOfParamToAnnotation(ParamParser.class);
|
static final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToParamParserAnnotations = createMethodToIndexOfParamToAnnotation(ParamParser.class);
|
||||||
private 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(
|
return new MapMaker()
|
||||||
|
.makeComputingMap(new GetAnnotationsForMethodParameterIndex(
|
||||||
method, annotation));
|
method, annotation));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static class GetAnnotationsForMethodParameterIndex implements Function<Integer, Set<Annotation>> {
|
static class GetAnnotationsForMethodParameterIndex implements
|
||||||
|
Function<Integer, Set<Annotation>> {
|
||||||
private final Method method;
|
private final Method method;
|
||||||
private final Class<?> clazz;
|
private final Class<?> clazz;
|
||||||
|
|
||||||
protected GetAnnotationsForMethodParameterIndex(Method method, Class<?> clazz) {
|
protected GetAnnotationsForMethodParameterIndex(Method method,
|
||||||
|
Class<?> clazz) {
|
||||||
this.method = method;
|
this.method = method;
|
||||||
this.clazz = clazz;
|
this.clazz = clazz;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<Annotation> apply(final Integer index) {
|
public Set<Annotation> apply(final Integer index) {
|
||||||
Set<Annotation> keys = new HashSet<Annotation>();
|
Set<Annotation> keys = new HashSet<Annotation>();
|
||||||
List<Annotation> parameterAnnotations = newArrayList(method.getParameterAnnotations()[index]);
|
List<Annotation> parameterAnnotations = newArrayList(method
|
||||||
|
.getParameterAnnotations()[index]);
|
||||||
Collection<Annotation> filtered = filter(parameterAnnotations,
|
Collection<Annotation> filtered = filter(parameterAnnotations,
|
||||||
new Predicate<Annotation>() {
|
new Predicate<Annotation>() {
|
||||||
public boolean apply(Annotation input) {
|
public boolean apply(Annotation input) {
|
||||||
|
@ -231,13 +227,15 @@ public class RestAnnotationProcessor<T> {
|
||||||
private InputParamValidator inputParamValidator;
|
private InputParamValidator inputParamValidator;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
Function<HttpResponse, ?> createResponseParser(Method method, HttpRequest request) {
|
Function<HttpResponse, ?> createResponseParser(Method method,
|
||||||
|
HttpRequest request) {
|
||||||
return createResponseParser(parserFactory, injector, method, request);
|
return createResponseParser(parserFactory, injector, method, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public static Function<HttpResponse, ?> createResponseParser(ParseSax.Factory parserFactory,
|
public static Function<HttpResponse, ?> createResponseParser(
|
||||||
Injector injector, Method method, HttpRequest request) {
|
ParseSax.Factory parserFactory, Injector injector, 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) {
|
||||||
|
@ -246,7 +244,8 @@ public class RestAnnotationProcessor<T> {
|
||||||
transformer = injector.getInstance(getParserOrThrowException(method));
|
transformer = injector.getInstance(getParserOrThrowException(method));
|
||||||
}
|
}
|
||||||
if (transformer instanceof InvocationContext) {
|
if (transformer instanceof InvocationContext) {
|
||||||
((InvocationContext) transformer).setContext((GeneratedHttpRequest<?>) request);
|
((InvocationContext) transformer)
|
||||||
|
.setContext((GeneratedHttpRequest<?>) request);
|
||||||
}
|
}
|
||||||
return transformer;
|
return transformer;
|
||||||
}
|
}
|
||||||
|
@ -254,7 +253,8 @@ public class RestAnnotationProcessor<T> {
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
Function<Exception, ?> createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(
|
Function<Exception, ?> createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(
|
||||||
Method method) {
|
Method method) {
|
||||||
return createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(injector, method);
|
return createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(
|
||||||
|
injector, method);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
@ -269,8 +269,9 @@ public class RestAnnotationProcessor<T> {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Inject
|
@Inject
|
||||||
public RestAnnotationProcessor(Injector injector, ParseSax.Factory parserFactory,
|
public RestAnnotationProcessor(Injector injector,
|
||||||
HttpUtils utils, TypeLiteral<T> typeLiteral) {
|
ParseSax.Factory parserFactory, HttpUtils utils,
|
||||||
|
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;
|
||||||
|
@ -294,17 +295,27 @@ public class RestAnnotationProcessor<T> {
|
||||||
for (Method method : methods) {
|
for (Method method : methods) {
|
||||||
if (isHttpMethod(method)) {
|
if (isHttpMethod(method)) {
|
||||||
for (int index = 0; index < method.getParameterTypes().length; index++) {
|
for (int index = 0; index < method.getParameterTypes().length; index++) {
|
||||||
methodToIndexOfParamToDecoratorParamAnnotation.get(method).get(index);
|
methodToIndexOfParamToDecoratorParamAnnotation.get(method).get(
|
||||||
methodToIndexOfParamToHeaderParamAnnotations.get(method).get(index);
|
index);
|
||||||
methodToIndexOfParamToMatrixParamAnnotations.get(method).get(index);
|
methodToIndexOfParamToHeaderParamAnnotations.get(method).get(
|
||||||
methodToIndexOfParamToFormParamAnnotations.get(method).get(index);
|
index);
|
||||||
methodToIndexOfParamToQueryParamAnnotations.get(method).get(index);
|
methodToIndexOfParamToMatrixParamAnnotations.get(method).get(
|
||||||
|
index);
|
||||||
|
methodToIndexOfParamToFormParamAnnotations.get(method)
|
||||||
|
.get(index);
|
||||||
|
methodToIndexOfParamToQueryParamAnnotations.get(method).get(
|
||||||
|
index);
|
||||||
methodToIndexOfParamToEndpointAnnotations.get(method).get(index);
|
methodToIndexOfParamToEndpointAnnotations.get(method).get(index);
|
||||||
methodToIndexOfParamToEndpointParamAnnotations.get(method).get(index);
|
methodToIndexOfParamToEndpointParamAnnotations.get(method).get(
|
||||||
methodToIndexOfParamToPathParamAnnotations.get(method).get(index);
|
index);
|
||||||
methodToIndexOfParamToPostParamAnnotations.get(method).get(index);
|
methodToIndexOfParamToPathParamAnnotations.get(method)
|
||||||
methodToIndexOfParamToParamParserAnnotations.get(method).get(index);
|
.get(index);
|
||||||
methodToIndexOfParamToPartParamAnnotations.get(method).get(index);
|
methodToIndexOfParamToPostParamAnnotations.get(method)
|
||||||
|
.get(index);
|
||||||
|
methodToIndexOfParamToParamParserAnnotations.get(method).get(
|
||||||
|
index);
|
||||||
|
methodToIndexOfParamToPartParamAnnotations.get(method)
|
||||||
|
.get(index);
|
||||||
methodToIndexesOfOptions.get(method);
|
methodToIndexesOfOptions.get(method);
|
||||||
}
|
}
|
||||||
delegationMap.put(new MethodKey(method), method);
|
delegationMap.put(new MethodKey(method), method);
|
||||||
|
@ -315,7 +326,9 @@ public class RestAnnotationProcessor<T> {
|
||||||
} else if (method.isAnnotationPresent(Delegate.class)) {
|
} else if (method.isAnnotationPresent(Delegate.class)) {
|
||||||
logger.debug("skipping delegate method %s", method);
|
logger.debug("skipping delegate method %s", method);
|
||||||
} else if (!method.getName().startsWith("new")) {
|
} else if (!method.getName().startsWith("new")) {
|
||||||
logger.trace("Method is not annotated as either http or constant: %s", method);
|
logger.trace(
|
||||||
|
"Method is not annotated as either http or constant: %s",
|
||||||
|
method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -362,19 +375,26 @@ public class RestAnnotationProcessor<T> {
|
||||||
|
|
||||||
final Injector injector;
|
final Injector injector;
|
||||||
|
|
||||||
|
ClassMethodArgs caller;
|
||||||
|
|
||||||
|
@Inject(optional = true)
|
||||||
|
public void setCaller(@Caller ClassMethodArgs caller) {
|
||||||
|
seedCache(caller.getMethod().getDeclaringClass());
|
||||||
|
this.caller = caller;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(optional = true)
|
||||||
|
@Caller
|
||||||
|
@Nullable
|
||||||
|
URI callerEndpoint;
|
||||||
|
|
||||||
public GeneratedHttpRequest<T> createRequest(Method method, Object... args) {
|
public GeneratedHttpRequest<T> createRequest(Method method, Object... args) {
|
||||||
inputParamValidator.validateMethodParametersOrThrow(method, args);
|
inputParamValidator.validateMethodParametersOrThrow(method, args);
|
||||||
URI endpoint;
|
URI endpoint = callerEndpoint;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (caller != null) {
|
if (endpoint == null)
|
||||||
try {
|
endpoint = getEndpointFor(method, args, injector);
|
||||||
endpoint = getEndpointFor(caller.getMethod(), caller.getArgs());
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
endpoint = getEndpointFor(method, args);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
endpoint = getEndpointFor(method, args);
|
|
||||||
}
|
|
||||||
} catch (IllegalStateException e) {
|
} catch (IllegalStateException e) {
|
||||||
endpoint = injector.getInstance(Key.get(URI.class,
|
endpoint = injector.getInstance(Key.get(URI.class,
|
||||||
org.jclouds.rest.annotations.Provider.class));
|
org.jclouds.rest.annotations.Provider.class));
|
||||||
|
@ -386,34 +406,44 @@ public class RestAnnotationProcessor<T> {
|
||||||
Multimap<String, String> tokenValues = LinkedHashMultimap.create();
|
Multimap<String, String> tokenValues = LinkedHashMultimap.create();
|
||||||
|
|
||||||
if (caller != null) {
|
if (caller != null) {
|
||||||
builder.path(getPath(caller.getMethod().getDeclaringClass(), caller.getMethod(), caller
|
builder.path(getPath(caller.getMethod().getDeclaringClass(), caller
|
||||||
.getArgs()));
|
.getMethod(), caller.getArgs()));
|
||||||
}
|
}
|
||||||
tokenValues.putAll(addPathAndGetTokens(declaring, method, args, builder));
|
tokenValues.putAll(addPathAndGetTokens(declaring, method, args, builder));
|
||||||
|
|
||||||
Multimap<String, String> formParams = addFormParams(tokenValues.entries(), method, args);
|
Multimap<String, String> formParams = addFormParams(
|
||||||
Multimap<String, String> queryParams = addQueryParams(tokenValues.entries(), method, args);
|
tokenValues.entries(), method, args);
|
||||||
|
Multimap<String, String> queryParams = addQueryParams(tokenValues
|
||||||
|
.entries(), method, args);
|
||||||
|
|
||||||
addMatrixParams(builder, tokenValues.entries(), method, args);
|
addMatrixParams(builder, tokenValues.entries(), method, args);
|
||||||
|
|
||||||
Multimap<String, String> headers = buildHeaders(tokenValues.entries(), method, args);
|
Multimap<String, String> headers = buildHeaders(tokenValues.entries(),
|
||||||
|
method, args);
|
||||||
|
|
||||||
Payload payload = null;
|
Payload payload = null;
|
||||||
HttpRequestOptions options = findOptionsIn(method, args);
|
HttpRequestOptions options = findOptionsIn(method, args);
|
||||||
if (options != null) {
|
if (options != null) {
|
||||||
injector.injectMembers(options);// TODO test case
|
injector.injectMembers(options);// TODO test case
|
||||||
for (Entry<String, String> header : options.buildRequestHeaders().entries()) {
|
for (Entry<String, String> header : options.buildRequestHeaders()
|
||||||
headers.put(header.getKey(), replaceTokens(header.getValue(), tokenValues.entries()));
|
.entries()) {
|
||||||
|
headers.put(header.getKey(), replaceTokens(header.getValue(),
|
||||||
|
tokenValues.entries()));
|
||||||
}
|
}
|
||||||
for (Entry<String, String> matrix : options.buildMatrixParameters().entries()) {
|
for (Entry<String, String> matrix : options.buildMatrixParameters()
|
||||||
builder.matrixParam(matrix.getKey(), replaceTokens(matrix.getValue(), tokenValues
|
.entries()) {
|
||||||
.entries()));
|
builder.matrixParam(matrix.getKey(), replaceTokens(matrix
|
||||||
|
.getValue(), tokenValues.entries()));
|
||||||
}
|
}
|
||||||
for (Entry<String, String> query : options.buildQueryParameters().entries()) {
|
for (Entry<String, String> query : options.buildQueryParameters()
|
||||||
queryParams.put(query.getKey(), replaceTokens(query.getValue(), tokenValues.entries()));
|
.entries()) {
|
||||||
|
queryParams.put(query.getKey(), replaceTokens(query.getValue(),
|
||||||
|
tokenValues.entries()));
|
||||||
}
|
}
|
||||||
for (Entry<String, String> form : options.buildFormParameters().entries()) {
|
for (Entry<String, String> form : options.buildFormParameters()
|
||||||
formParams.put(form.getKey(), replaceTokens(form.getValue(), tokenValues.entries()));
|
.entries()) {
|
||||||
|
formParams.put(form.getKey(), replaceTokens(form.getValue(),
|
||||||
|
tokenValues.entries()));
|
||||||
}
|
}
|
||||||
|
|
||||||
String pathSuffix = options.buildPathSuffix();
|
String pathSuffix = options.buildPathSuffix();
|
||||||
|
@ -422,7 +452,7 @@ public class RestAnnotationProcessor<T> {
|
||||||
}
|
}
|
||||||
String stringPayload = options.buildStringPayload();
|
String stringPayload = options.buildStringPayload();
|
||||||
if (stringPayload != null)
|
if (stringPayload != null)
|
||||||
payload = newStringPayload(stringPayload);
|
payload = Payloads.newStringPayload(stringPayload);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queryParams.size() > 0) {
|
if (queryParams.size() > 0) {
|
||||||
|
@ -437,22 +467,24 @@ public class RestAnnotationProcessor<T> {
|
||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
GeneratedHttpRequest<T> request = new GeneratedHttpRequest<T>(httpMethod, endpoint, skips,
|
GeneratedHttpRequest<T> request = new GeneratedHttpRequest<T>(httpMethod,
|
||||||
declaring, method, args);
|
endpoint, skips, declaring, method, args);
|
||||||
addHostHeaderIfAnnotatedWithVirtualHost(headers, request.getEndpoint().getHost(), method);
|
addHostHeaderIfAnnotatedWithVirtualHost(headers, request.getEndpoint()
|
||||||
|
.getHost(), method);
|
||||||
addFiltersIfAnnotated(method, request);
|
addFiltersIfAnnotated(method, request);
|
||||||
|
|
||||||
if (payload == null)
|
if (payload == null)
|
||||||
payload = findPayloadInArgs(args);
|
payload = findPayloadInArgs(args);
|
||||||
List<? extends Part> parts = getParts(method, args, concat(tokenValues.entries(), formParams
|
List<? extends Part> parts = getParts(method, args, Iterables.concat(
|
||||||
.entries()));
|
tokenValues.entries(), formParams.entries()));
|
||||||
if (parts.size() > 0) {
|
if (parts.size() > 0) {
|
||||||
if (formParams.size() > 0) {
|
if (formParams.size() > 0) {
|
||||||
parts = newLinkedList(concat(transform(formParams.entries(), ENTRY_TO_PART), parts));
|
parts = newLinkedList(Iterables.concat(Iterables.transform(
|
||||||
|
formParams.entries(), ENTRY_TO_PART), parts));
|
||||||
}
|
}
|
||||||
payload = new MultipartForm(BOUNDARY, parts);
|
payload = new MultipartForm(BOUNDARY, parts);
|
||||||
} else if (formParams.size() > 0) {
|
} else if (formParams.size() > 0) {
|
||||||
payload = newUrlEncodedFormPayload(formParams, skips);
|
payload = Payloads.newUrlEncodedFormPayload(formParams, skips);
|
||||||
}
|
}
|
||||||
if (payload != null) {
|
if (payload != null) {
|
||||||
request.setPayload(payload);
|
request.setPayload(payload);
|
||||||
|
@ -469,11 +501,12 @@ public class RestAnnotationProcessor<T> {
|
||||||
builder.path(clazz);
|
builder.path(clazz);
|
||||||
builder.path(method);
|
builder.path(method);
|
||||||
return builder.buildFromEncodedMap(
|
return builder.buildFromEncodedMap(
|
||||||
convertUnsafe(encodeValues(getPathParamKeyValues(method, args), skips))).getPath();
|
convertUnsafe(encodeValues(getPathParamKeyValues(method, args),
|
||||||
|
skips))).getPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Multimap<String, String> addPathAndGetTokens(Class<?> clazz, Method method,
|
private Multimap<String, String> addPathAndGetTokens(Class<?> clazz,
|
||||||
Object[] args, UriBuilder builder) {
|
Method method, Object[] args, UriBuilder builder) {
|
||||||
if (clazz.isAnnotationPresent(Path.class))
|
if (clazz.isAnnotationPresent(Path.class))
|
||||||
builder.path(clazz);
|
builder.path(clazz);
|
||||||
builder.path(method);
|
builder.path(method);
|
||||||
|
@ -485,15 +518,18 @@ public class RestAnnotationProcessor<T> {
|
||||||
return replaceQuery(uriBuilderProvider, in, newQuery, sorter, skips);
|
return replaceQuery(uriBuilderProvider, in, newQuery, sorter, skips);
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
private void addMatrixParams(UriBuilder builder,
|
||||||
Method method, Object... args) {
|
Collection<Entry<String, String>> tokenValues, Method method,
|
||||||
|
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);
|
||||||
|
@ -504,13 +540,16 @@ public class RestAnnotationProcessor<T> {
|
||||||
addMatrix(builder, matrix, tokenValues);
|
addMatrix(builder, matrix, tokenValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Entry<String, String> matrix : getMatrixParamKeyValues(method, args).entries()) {
|
for (Entry<String, String> matrix : getMatrixParamKeyValues(method, args)
|
||||||
builder.matrixParam(matrix.getKey(), replaceTokens(matrix.getValue(), tokenValues));
|
.entries()) {
|
||||||
|
builder.matrixParam(matrix.getKey(), replaceTokens(matrix.getValue(),
|
||||||
|
tokenValues));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Multimap<String, String> addFormParams(Collection<Entry<String, String>> tokenValues,
|
private Multimap<String, String> addFormParams(
|
||||||
Method method, Object... args) {
|
Collection<Entry<String, String>> tokenValues, Method method,
|
||||||
|
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);
|
||||||
|
@ -522,14 +561,17 @@ public class RestAnnotationProcessor<T> {
|
||||||
addForm(formMap, form, tokenValues);
|
addForm(formMap, form, tokenValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Entry<String, String> form : getFormParamKeyValues(method, args).entries()) {
|
for (Entry<String, String> form : getFormParamKeyValues(method, args)
|
||||||
formMap.put(form.getKey(), replaceTokens(form.getValue(), tokenValues));
|
.entries()) {
|
||||||
|
formMap
|
||||||
|
.put(form.getKey(), replaceTokens(form.getValue(), tokenValues));
|
||||||
}
|
}
|
||||||
return formMap;
|
return formMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Multimap<String, String> addQueryParams(Collection<Entry<String, String>> tokenValues,
|
private Multimap<String, String> addQueryParams(
|
||||||
Method method, Object... args) {
|
Collection<Entry<String, String>> tokenValues, Method method,
|
||||||
|
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);
|
||||||
|
@ -541,8 +583,10 @@ public class RestAnnotationProcessor<T> {
|
||||||
addQuery(queryMap, query, tokenValues);
|
addQuery(queryMap, query, tokenValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Entry<String, String> query : getQueryParamKeyValues(method, args).entries()) {
|
for (Entry<String, String> query : getQueryParamKeyValues(method, args)
|
||||||
queryMap.put(query.getKey(), replaceTokens(query.getValue(), tokenValues));
|
.entries()) {
|
||||||
|
queryMap.put(query.getKey(), replaceTokens(query.getValue(),
|
||||||
|
tokenValues));
|
||||||
}
|
}
|
||||||
return queryMap;
|
return queryMap;
|
||||||
}
|
}
|
||||||
|
@ -554,19 +598,21 @@ public class RestAnnotationProcessor<T> {
|
||||||
formParams.removeAll(form.keys()[i]);
|
formParams.removeAll(form.keys()[i]);
|
||||||
formParams.put(form.keys()[i], null);
|
formParams.put(form.keys()[i], null);
|
||||||
} else {
|
} else {
|
||||||
formParams.put(form.keys()[i], replaceTokens(form.values()[i], tokenValues));
|
formParams.put(form.keys()[i], replaceTokens(form.values()[i],
|
||||||
|
tokenValues));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addQuery(Multimap<String, String> queryParams, QueryParams query,
|
private void addQuery(Multimap<String, String> queryParams,
|
||||||
Collection<Entry<String, String>> tokenValues) {
|
QueryParams query, 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]);
|
||||||
queryParams.put(query.keys()[i], null);
|
queryParams.put(query.keys()[i], null);
|
||||||
} else {
|
} else {
|
||||||
queryParams.put(query.keys()[i], replaceTokens(query.values()[i], tokenValues));
|
queryParams.put(query.keys()[i], replaceTokens(query.values()[i],
|
||||||
|
tokenValues));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -577,56 +623,82 @@ public class RestAnnotationProcessor<T> {
|
||||||
if (matrix.values()[i].equals(MatrixParams.NULL)) {
|
if (matrix.values()[i].equals(MatrixParams.NULL)) {
|
||||||
builder.replaceMatrix(matrix.keys()[i]);
|
builder.replaceMatrix(matrix.keys()[i]);
|
||||||
} else {
|
} else {
|
||||||
builder.matrixParam(matrix.keys()[i], replaceTokens(matrix.values()[i], tokenValues));
|
builder.matrixParam(matrix.keys()[i], replaceTokens(
|
||||||
|
matrix.values()[i], tokenValues));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addFiltersIfAnnotated(Method method, HttpRequest request) {
|
private void addFiltersIfAnnotated(Method method, HttpRequest request) {
|
||||||
if (declaring.isAnnotationPresent(RequestFilters.class)) {
|
if (declaring.isAnnotationPresent(RequestFilters.class)) {
|
||||||
for (Class<? extends HttpRequestFilter> clazz : declaring.getAnnotation(
|
for (Class<? extends HttpRequestFilter> clazz : declaring
|
||||||
RequestFilters.class).value()) {
|
.getAnnotation(RequestFilters.class).value()) {
|
||||||
HttpRequestFilter instance = injector.getInstance(clazz);
|
HttpRequestFilter instance = injector.getInstance(clazz);
|
||||||
request.getFilters().add(instance);
|
request.getFilters().add(instance);
|
||||||
logger.trace("%s - adding filter %s from annotation on %s", request, instance,
|
logger.trace("%s - adding filter %s from annotation on %s",
|
||||||
declaring.getName());
|
request, instance, declaring.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (method.isAnnotationPresent(RequestFilters.class)) {
|
if (method.isAnnotationPresent(RequestFilters.class)) {
|
||||||
if (method.isAnnotationPresent(OverrideRequestFilters.class))
|
if (method.isAnnotationPresent(OverrideRequestFilters.class))
|
||||||
request.getFilters().clear();
|
request.getFilters().clear();
|
||||||
for (Class<? extends HttpRequestFilter> clazz : method.getAnnotation(RequestFilters.class)
|
for (Class<? extends HttpRequestFilter> clazz : method.getAnnotation(
|
||||||
.value()) {
|
RequestFilters.class).value()) {
|
||||||
HttpRequestFilter instance = injector.getInstance(clazz);
|
HttpRequestFilter instance = injector.getInstance(clazz);
|
||||||
request.getFilters().add(instance);
|
request.getFilters().add(instance);
|
||||||
logger.trace("%s - adding filter %s from annotation on %s", request, instance, method
|
logger.trace("%s - adding filter %s from annotation on %s",
|
||||||
.getName());
|
request, instance, method.getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
URI getEndpointInParametersOrNull(Method method, Object... args) {
|
public static URI getEndpointInParametersOrNull(Method method,
|
||||||
Map<Integer, Set<Annotation>> map = indexWithOnlyOneAnnotation(method, "@EndpointParam",
|
Object[] args, Injector injector) {
|
||||||
methodToIndexOfParamToEndpointParamAnnotations);
|
Map<Integer, Set<Annotation>> map = RestAnnotationProcessor
|
||||||
|
.indexWithOnlyOneAnnotation(
|
||||||
|
method,
|
||||||
|
"@EndpointParam",
|
||||||
|
RestAnnotationProcessor.methodToIndexOfParamToEndpointParamAnnotations);
|
||||||
if (map.size() == 1 && args.length > 0) {
|
if (map.size() == 1 && args.length > 0) {
|
||||||
EndpointParam annotation = (EndpointParam) map.values().iterator().next().iterator()
|
EndpointParam annotation = (EndpointParam) map.values().iterator()
|
||||||
.next();
|
.next().iterator().next();
|
||||||
int index = map.keySet().iterator().next();
|
int index = map.keySet().iterator().next();
|
||||||
Function<Object, URI> parser = injector.getInstance(annotation.parser());
|
Function<Object, URI> parser = injector.getInstance(annotation
|
||||||
|
.parser());
|
||||||
try {
|
try {
|
||||||
URI returnVal = parser.apply(args[index]);
|
URI returnVal = parser.apply(args[index]);
|
||||||
checkArgument(returnVal != null, String.format(
|
checkArgument(returnVal != null, String.format(
|
||||||
"endpoint for [%s] not configured for %s", args[index], method));
|
"endpoint for [%s] not configured for %s", args[index],
|
||||||
|
method));
|
||||||
return returnVal;
|
return returnVal;
|
||||||
} catch (NullPointerException e) {
|
} catch (NullPointerException e) {
|
||||||
logger.error("argument at index %d on method %s", index, method);
|
throw new IllegalArgumentException(String.format(
|
||||||
throw e;
|
"argument at index %d on method %s", index, method), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static URI getEndpointFor(Method method, Object[] args, Injector injector) {
|
||||||
|
URI endpoint = getEndpointInParametersOrNull(method, args, injector);
|
||||||
|
if (endpoint == null) {
|
||||||
|
Endpoint annotation;
|
||||||
|
if (method.isAnnotationPresent(Endpoint.class)) {
|
||||||
|
annotation = method.getAnnotation(Endpoint.class);
|
||||||
|
} else if (method.getDeclaringClass().isAnnotationPresent(
|
||||||
|
Endpoint.class)) {
|
||||||
|
annotation = method.getDeclaringClass().getAnnotation(
|
||||||
|
Endpoint.class);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"no annotations on class or method: " + method);
|
||||||
|
}
|
||||||
|
return injector.getInstance(Key.get(URI.class, annotation.value()));
|
||||||
|
}
|
||||||
|
return endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
public static final TypeLiteral<ListenableFuture<Boolean>> futureBooleanLiteral = new TypeLiteral<ListenableFuture<Boolean>>() {
|
public static final TypeLiteral<ListenableFuture<Boolean>> futureBooleanLiteral = new TypeLiteral<ListenableFuture<Boolean>>() {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -640,43 +712,52 @@ public class RestAnnotationProcessor<T> {
|
||||||
public static final TypeLiteral<ListenableFuture<InputStream>> futureInputStreamLiteral = new TypeLiteral<ListenableFuture<InputStream>>() {
|
public static final TypeLiteral<ListenableFuture<InputStream>> futureInputStreamLiteral = new TypeLiteral<ListenableFuture<InputStream>>() {
|
||||||
};
|
};
|
||||||
|
|
||||||
public static Class<? extends Function<HttpResponse, ?>> getParserOrThrowException(Method method) {
|
public static Class<? extends Function<HttpResponse, ?>> getParserOrThrowException(
|
||||||
|
Method method) {
|
||||||
ResponseParser annotation = method.getAnnotation(ResponseParser.class);
|
ResponseParser annotation = method.getAnnotation(ResponseParser.class);
|
||||||
if (annotation == null) {
|
if (annotation == null) {
|
||||||
if (method.getReturnType().equals(boolean.class)
|
if (method.getReturnType().equals(boolean.class)
|
||||||
|| method.getReturnType().equals(Boolean.class)
|
|| method.getReturnType().equals(Boolean.class)
|
||||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureBooleanLiteral)) {
|
|| TypeLiteral.get(method.getGenericReturnType()).equals(
|
||||||
|
futureBooleanLiteral)) {
|
||||||
return ReturnTrueIf2xx.class;
|
return ReturnTrueIf2xx.class;
|
||||||
} 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 ReturnStringIf2xx.class;
|
return ReturnStringIf2xx.class;
|
||||||
} else if (method.getReturnType().equals(void.class)
|
} else if (method.getReturnType().equals(void.class)
|
||||||
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureVoidLiteral)) {
|
|| TypeLiteral.get(method.getGenericReturnType()).equals(
|
||||||
|
futureVoidLiteral)) {
|
||||||
return ReleasePayloadAndReturn.class;
|
return ReleasePayloadAndReturn.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 ParseURIFromListOrLocationHeaderIf20x.class;
|
return ParseURIFromListOrLocationHeaderIf20x.class;
|
||||||
} else if (method.getReturnType().equals(InputStream.class)
|
} else if (method.getReturnType().equals(InputStream.class)
|
||||||
|| TypeLiteral.get(method.getGenericReturnType())
|
|| TypeLiteral.get(method.getGenericReturnType()).equals(
|
||||||
.equals(futureInputStreamLiteral)) {
|
futureInputStreamLiteral)) {
|
||||||
return ReturnInputStream.class;
|
return ReturnInputStream.class;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"You must specify a ResponseTransformer annotation on: " + method.toString());
|
"You must specify a ResponseTransformer annotation on: "
|
||||||
|
+ method.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return annotation.value();
|
return annotation.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Class<? extends HandlerWithResult<?>> getSaxResponseParserClassOrNull(Method method) {
|
public static Class<? extends HandlerWithResult<?>> getSaxResponseParserClassOrNull(
|
||||||
XMLResponseParser annotation = method.getAnnotation(XMLResponseParser.class);
|
Method method) {
|
||||||
|
XMLResponseParser annotation = method
|
||||||
|
.getAnnotation(XMLResponseParser.class);
|
||||||
if (annotation != null) {
|
if (annotation != null) {
|
||||||
return annotation.value();
|
return annotation.value();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public org.jclouds.rest.MapBinder getMapPayloadBinderOrNull(Method method, Object... args) {
|
public org.jclouds.rest.MapBinder getMapPayloadBinderOrNull(Method method,
|
||||||
|
Object... args) {
|
||||||
if (args != null) {
|
if (args != null) {
|
||||||
for (Object arg : args) {
|
for (Object arg : args) {
|
||||||
if (arg instanceof Object[]) {
|
if (arg instanceof Object[]) {
|
||||||
|
@ -712,16 +793,19 @@ public class RestAnnotationProcessor<T> {
|
||||||
private Multimap<String, String> constants = LinkedHashMultimap.create();
|
private Multimap<String, String> constants = LinkedHashMultimap.create();
|
||||||
|
|
||||||
public boolean isHttpMethod(Method method) {
|
public boolean isHttpMethod(Method method) {
|
||||||
return method.isAnnotationPresent(Path.class) || IsHttpMethod.getHttpMethods(method) != null;
|
return method.isAnnotationPresent(Path.class)
|
||||||
|
|| IsHttpMethod.getHttpMethods(method) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isConstantDeclaration(Method method) {
|
public boolean isConstantDeclaration(Method method) {
|
||||||
return method.isAnnotationPresent(PathParam.class) && method.isAnnotationPresent(Named.class);
|
return method.isAnnotationPresent(PathParam.class)
|
||||||
|
&& method.isAnnotationPresent(Named.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bindConstant(Method method) {
|
public void bindConstant(Method method) {
|
||||||
String key = method.getAnnotation(PathParam.class).value();
|
String key = method.getAnnotation(PathParam.class).value();
|
||||||
String value = injector.getInstance(Key.get(String.class, method.getAnnotation(Named.class)));
|
String value = injector.getInstance(Key.get(String.class, method
|
||||||
|
.getAnnotation(Named.class)));
|
||||||
constants.put(key, value);
|
constants.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -735,18 +819,20 @@ public class RestAnnotationProcessor<T> {
|
||||||
return requests.iterator().next();
|
return requests.iterator().next();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addHostHeaderIfAnnotatedWithVirtualHost(Multimap<String, String> headers,
|
public void addHostHeaderIfAnnotatedWithVirtualHost(
|
||||||
String host, Method method) {
|
Multimap<String, String> headers, String host, Method method) {
|
||||||
if (declaring.isAnnotationPresent(VirtualHost.class)
|
if (declaring.isAnnotationPresent(VirtualHost.class)
|
||||||
|| method.isAnnotationPresent(VirtualHost.class)) {
|
|| method.isAnnotationPresent(VirtualHost.class)) {
|
||||||
headers.put(HOST, host);
|
headers.put(HOST, host);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void decorateRequest(GeneratedHttpRequest<T> request, Multimap<String, String> headers) {
|
public void decorateRequest(GeneratedHttpRequest<T> request,
|
||||||
org.jclouds.rest.MapBinder mapBinder = getMapPayloadBinderOrNull(request.getJavaMethod(),
|
Multimap<String, String> headers) {
|
||||||
|
org.jclouds.rest.MapBinder mapBinder = getMapPayloadBinderOrNull(request
|
||||||
|
.getJavaMethod(), request.getArgs());
|
||||||
|
Map<String, String> mapParams = buildPostParams(request.getJavaMethod(),
|
||||||
request.getArgs());
|
request.getArgs());
|
||||||
Map<String, String> mapParams = buildPostParams(request.getJavaMethod(), request.getArgs());
|
|
||||||
// MapPayloadBinder is only useful if there are parameters. We guard here
|
// MapPayloadBinder is only useful if there are parameters. We guard here
|
||||||
// in case the
|
// in case the
|
||||||
// MapPayloadBinder is also an PayloadBinder. If so, it can be used with
|
// MapPayloadBinder is also an PayloadBinder. If so, it can be used with
|
||||||
|
@ -756,31 +842,37 @@ public class RestAnnotationProcessor<T> {
|
||||||
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
|
||||||
new Predicate<Set<Annotation>>() {
|
.getJavaMethod()), 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());
|
||||||
if (request.getArgs().length >= entry.getKey() + 1
|
if (request.getArgs().length >= entry.getKey() + 1
|
||||||
&& request.getArgs()[entry.getKey()] != null) {
|
&& request.getArgs()[entry.getKey()] != null) {
|
||||||
Object input;
|
Object input;
|
||||||
Class<?> parameterType = request.getJavaMethod().getParameterTypes()[entry.getKey()];
|
Class<?> parameterType = request.getJavaMethod()
|
||||||
Class<? extends Object> argType = request.getArgs()[entry.getKey()].getClass();
|
.getParameterTypes()[entry.getKey()];
|
||||||
|
Class<? extends Object> argType = request.getArgs()[entry
|
||||||
|
.getKey()].getClass();
|
||||||
if (!argType.isArray() && request.getJavaMethod().isVarArgs()
|
if (!argType.isArray() && request.getJavaMethod().isVarArgs()
|
||||||
&& parameterType.isArray()) {
|
&& parameterType.isArray()) {
|
||||||
int arrayLength = request.getArgs().length
|
int arrayLength = request.getArgs().length
|
||||||
- request.getJavaMethod().getParameterTypes().length + 1;
|
- request.getJavaMethod().getParameterTypes().length
|
||||||
|
+ 1;
|
||||||
if (arrayLength == 0)
|
if (arrayLength == 0)
|
||||||
break OUTER;
|
break OUTER;
|
||||||
input = (Object[]) Array.newInstance(
|
input = (Object[]) Array.newInstance(request.getArgs()[entry
|
||||||
request.getArgs()[entry.getKey()].getClass(), arrayLength);
|
.getKey()].getClass(), arrayLength);
|
||||||
System.arraycopy(request.getArgs(), entry.getKey(), input, 0, arrayLength);
|
System.arraycopy(request.getArgs(), entry.getKey(), input, 0,
|
||||||
|
arrayLength);
|
||||||
shouldBreak = true;
|
shouldBreak = true;
|
||||||
} else if (argType.isArray() && request.getJavaMethod().isVarArgs()
|
} else if (argType.isArray()
|
||||||
|
&& request.getJavaMethod().isVarArgs()
|
||||||
&& parameterType.isArray()) {
|
&& parameterType.isArray()) {
|
||||||
input = request.getArgs()[entry.getKey()];
|
input = request.getArgs()[entry.getKey()];
|
||||||
} else {
|
} else {
|
||||||
|
@ -801,19 +893,23 @@ public class RestAnnotationProcessor<T> {
|
||||||
utils.setPayloadPropertiesFromHeaders(headers, request);
|
utils.setPayloadPropertiesFromHeaders(headers, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Map<Integer, Set<Annotation>> indexWithOnlyOneAnnotation(Method method,
|
public static Map<Integer, Set<Annotation>> indexWithOnlyOneAnnotation(
|
||||||
String description, Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
|
Method method, String description,
|
||||||
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = filterValues(toRefine.get(method),
|
Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
|
||||||
new Predicate<Set<Annotation>>() {
|
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = filterValues(
|
||||||
|
toRefine.get(method), new Predicate<Set<Annotation>>() {
|
||||||
public boolean apply(Set<Annotation> input) {
|
public boolean apply(Set<Annotation> input) {
|
||||||
return input.size() == 1;
|
return input.size() == 1;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (indexToPayloadAnnotation.size() > 1) {
|
if (indexToPayloadAnnotation.size() > 1) {
|
||||||
throw new IllegalStateException(String.format(
|
throw new IllegalStateException(
|
||||||
"You must not specify more than one %s annotation on: %s; found %s", description,
|
String
|
||||||
method.toString(), indexToPayloadAnnotation));
|
.format(
|
||||||
|
"You must not specify more than one %s annotation on: %s; found %s",
|
||||||
|
description, method.toString(),
|
||||||
|
indexToPayloadAnnotation));
|
||||||
}
|
}
|
||||||
return indexToPayloadAnnotation;
|
return indexToPayloadAnnotation;
|
||||||
}
|
}
|
||||||
|
@ -845,13 +941,15 @@ public class RestAnnotationProcessor<T> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Multimap<String, String> buildHeaders(Collection<Entry<String, String>> tokenValues,
|
public Multimap<String, String> buildHeaders(
|
||||||
Method method, final Object... args) {
|
Collection<Entry<String, String>> tokenValues, Method method,
|
||||||
|
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
|
Map<Integer, Set<Annotation>> indexToHeaderParam = methodToIndexOfParamToHeaderParamAnnotations
|
||||||
.get(method);
|
.get(method);
|
||||||
for (Entry<Integer, Set<Annotation>> entry : indexToHeaderParam.entrySet()) {
|
for (Entry<Integer, Set<Annotation>> entry : indexToHeaderParam
|
||||||
|
.entrySet()) {
|
||||||
for (Annotation key : entry.getValue()) {
|
for (Annotation key : entry.getValue()) {
|
||||||
String value = args[entry.getKey()].toString();
|
String value = args[entry.getKey()].toString();
|
||||||
value = replaceTokens(value, tokenValues);
|
value = replaceTokens(value, tokenValues);
|
||||||
|
@ -863,7 +961,8 @@ public class RestAnnotationProcessor<T> {
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addConsumesIfPresentOnTypeOrMethod(Multimap<String, String> headers, Method method) {
|
void addConsumesIfPresentOnTypeOrMethod(Multimap<String, String> headers,
|
||||||
|
Method method) {
|
||||||
if (declaring.isAnnotationPresent(Consumes.class)) {
|
if (declaring.isAnnotationPresent(Consumes.class)) {
|
||||||
Consumes header = declaring.getAnnotation(Consumes.class);
|
Consumes header = declaring.getAnnotation(Consumes.class);
|
||||||
headers.replaceValues(ACCEPT, asList(header.value()));
|
headers.replaceValues(ACCEPT, asList(header.value()));
|
||||||
|
@ -874,7 +973,8 @@ public class RestAnnotationProcessor<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addProducesIfPresentOnTypeOrMethod(Multimap<String, String> headers, Method method) {
|
void addProducesIfPresentOnTypeOrMethod(Multimap<String, String> headers,
|
||||||
|
Method method) {
|
||||||
if (declaring.isAnnotationPresent(Produces.class)) {
|
if (declaring.isAnnotationPresent(Produces.class)) {
|
||||||
Produces header = declaring.getAnnotation(Produces.class);
|
Produces header = declaring.getAnnotation(Produces.class);
|
||||||
headers.replaceValues(CONTENT_TYPE, asList(header.value()));
|
headers.replaceValues(CONTENT_TYPE, asList(header.value()));
|
||||||
|
@ -885,8 +985,9 @@ public class RestAnnotationProcessor<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addHeaderIfAnnotationPresentOnMethod(Multimap<String, String> headers,
|
public void addHeaderIfAnnotationPresentOnMethod(
|
||||||
Method method, Collection<Entry<String, String>> tokenValues) {
|
Multimap<String, String> headers, Method method,
|
||||||
|
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);
|
||||||
|
@ -928,7 +1029,8 @@ public class RestAnnotationProcessor<T> {
|
||||||
options.contentType(param.contentType());
|
options.contentType(param.contentType());
|
||||||
if (!PartParam.NO_FILENAME.equals(param.filename()))
|
if (!PartParam.NO_FILENAME.equals(param.filename()))
|
||||||
options.filename(replaceTokens(param.filename(), iterable));
|
options.filename(replaceTokens(param.filename(), iterable));
|
||||||
Part part = Part.create(param.name(), newPayload(args[entry.getKey()]), options);
|
Part part = Part.create(param.name(), newPayload(args[entry
|
||||||
|
.getKey()]), options);
|
||||||
parts.add(part);
|
parts.add(part);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -946,7 +1048,8 @@ public class RestAnnotationProcessor<T> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Multimap<String, String> getPathParamKeyValues(Method method, Object... args) {
|
private Multimap<String, String> getPathParamKeyValues(Method method,
|
||||||
|
Object... args) {
|
||||||
Multimap<String, String> pathParamValues = LinkedHashMultimap.create();
|
Multimap<String, String> pathParamValues = LinkedHashMultimap.create();
|
||||||
pathParamValues.putAll(constants);
|
pathParamValues.putAll(constants);
|
||||||
Map<Integer, Set<Annotation>> indexToPathParam = methodToIndexOfParamToPathParamAnnotations
|
Map<Integer, Set<Annotation>> indexToPathParam = methodToIndexOfParamToPathParamAnnotations
|
||||||
|
@ -956,12 +1059,15 @@ public class RestAnnotationProcessor<T> {
|
||||||
.get(method);
|
.get(method);
|
||||||
for (Entry<Integer, Set<Annotation>> entry : indexToPathParam.entrySet()) {
|
for (Entry<Integer, Set<Annotation>> entry : indexToPathParam.entrySet()) {
|
||||||
for (Annotation key : entry.getValue()) {
|
for (Annotation key : entry.getValue()) {
|
||||||
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
|
Set<Annotation> extractors = indexToParamExtractor.get(entry
|
||||||
|
.getKey());
|
||||||
String paramKey = ((PathParam) key).value();
|
String paramKey = ((PathParam) key).value();
|
||||||
String paramValue;
|
String paramValue;
|
||||||
if (extractors != null && extractors.size() > 0) {
|
if (extractors != null && extractors.size() > 0) {
|
||||||
ParamParser extractor = (ParamParser) extractors.iterator().next();
|
ParamParser extractor = (ParamParser) extractors.iterator()
|
||||||
paramValue = injector.getInstance(extractor.value()).apply(args[entry.getKey()]);
|
.next();
|
||||||
|
paramValue = injector.getInstance(extractor.value()).apply(
|
||||||
|
args[entry.getKey()]);
|
||||||
} else {
|
} else {
|
||||||
paramValue = args[entry.getKey()].toString();
|
paramValue = args[entry.getKey()].toString();
|
||||||
}
|
}
|
||||||
|
@ -972,15 +1078,16 @@ public class RestAnnotationProcessor<T> {
|
||||||
if (method.isAnnotationPresent(PathParam.class)
|
if (method.isAnnotationPresent(PathParam.class)
|
||||||
&& method.isAnnotationPresent(ParamParser.class)) {
|
&& method.isAnnotationPresent(ParamParser.class)) {
|
||||||
String paramKey = method.getAnnotation(PathParam.class).value();
|
String paramKey = method.getAnnotation(PathParam.class).value();
|
||||||
String paramValue = injector.getInstance(method.getAnnotation(ParamParser.class).value())
|
String paramValue = injector.getInstance(
|
||||||
.apply(args);
|
method.getAnnotation(ParamParser.class).value()).apply(args);
|
||||||
pathParamValues.put(paramKey, paramValue);
|
pathParamValues.put(paramKey, paramValue);
|
||||||
|
|
||||||
}
|
}
|
||||||
return pathParamValues;
|
return pathParamValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Multimap<String, String> encodeValues(Multimap<String, String> unencoded, char... skips) {
|
private Multimap<String, String> encodeValues(
|
||||||
|
Multimap<String, String> unencoded, char... skips) {
|
||||||
Multimap<String, String> encoded = LinkedHashMultimap.create();
|
Multimap<String, String> encoded = LinkedHashMultimap.create();
|
||||||
for (Entry<String, String> entry : unencoded.entries()) {
|
for (Entry<String, String> entry : unencoded.entries()) {
|
||||||
encoded.put(entry.getKey(), urlEncode(entry.getValue(), skips));
|
encoded.put(entry.getKey(), urlEncode(entry.getValue(), skips));
|
||||||
|
@ -988,7 +1095,8 @@ public class RestAnnotationProcessor<T> {
|
||||||
return encoded;
|
return encoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Multimap<String, String> getMatrixParamKeyValues(Method method, Object... args) {
|
private Multimap<String, String> getMatrixParamKeyValues(Method method,
|
||||||
|
Object... args) {
|
||||||
Multimap<String, String> matrixParamValues = LinkedHashMultimap.create();
|
Multimap<String, String> matrixParamValues = LinkedHashMultimap.create();
|
||||||
matrixParamValues.putAll(constants);
|
matrixParamValues.putAll(constants);
|
||||||
Map<Integer, Set<Annotation>> indexToMatrixParam = methodToIndexOfParamToMatrixParamAnnotations
|
Map<Integer, Set<Annotation>> indexToMatrixParam = methodToIndexOfParamToMatrixParamAnnotations
|
||||||
|
@ -996,14 +1104,18 @@ public class RestAnnotationProcessor<T> {
|
||||||
|
|
||||||
Map<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations
|
Map<Integer, Set<Annotation>> indexToParamExtractor = methodToIndexOfParamToParamParserAnnotations
|
||||||
.get(method);
|
.get(method);
|
||||||
for (Entry<Integer, Set<Annotation>> entry : indexToMatrixParam.entrySet()) {
|
for (Entry<Integer, Set<Annotation>> entry : indexToMatrixParam
|
||||||
|
.entrySet()) {
|
||||||
for (Annotation key : entry.getValue()) {
|
for (Annotation key : entry.getValue()) {
|
||||||
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
|
Set<Annotation> extractors = indexToParamExtractor.get(entry
|
||||||
|
.getKey());
|
||||||
String paramKey = ((MatrixParam) key).value();
|
String paramKey = ((MatrixParam) key).value();
|
||||||
String paramValue;
|
String paramValue;
|
||||||
if (extractors != null && extractors.size() > 0) {
|
if (extractors != null && extractors.size() > 0) {
|
||||||
ParamParser extractor = (ParamParser) extractors.iterator().next();
|
ParamParser extractor = (ParamParser) extractors.iterator()
|
||||||
paramValue = injector.getInstance(extractor.value()).apply(args[entry.getKey()]);
|
.next();
|
||||||
|
paramValue = injector.getInstance(extractor.value()).apply(
|
||||||
|
args[entry.getKey()]);
|
||||||
} else {
|
} else {
|
||||||
paramValue = args[entry.getKey()].toString();
|
paramValue = args[entry.getKey()].toString();
|
||||||
}
|
}
|
||||||
|
@ -1014,15 +1126,16 @@ public class RestAnnotationProcessor<T> {
|
||||||
if (method.isAnnotationPresent(MatrixParam.class)
|
if (method.isAnnotationPresent(MatrixParam.class)
|
||||||
&& method.isAnnotationPresent(ParamParser.class)) {
|
&& method.isAnnotationPresent(ParamParser.class)) {
|
||||||
String paramKey = method.getAnnotation(MatrixParam.class).value();
|
String paramKey = method.getAnnotation(MatrixParam.class).value();
|
||||||
String paramValue = injector.getInstance(method.getAnnotation(ParamParser.class).value())
|
String paramValue = injector.getInstance(
|
||||||
.apply(args);
|
method.getAnnotation(ParamParser.class).value()).apply(args);
|
||||||
matrixParamValues.put(paramKey, paramValue);
|
matrixParamValues.put(paramKey, paramValue);
|
||||||
|
|
||||||
}
|
}
|
||||||
return matrixParamValues;
|
return matrixParamValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Multimap<String, String> getFormParamKeyValues(Method method, Object... args) {
|
private Multimap<String, String> getFormParamKeyValues(Method method,
|
||||||
|
Object... args) {
|
||||||
Multimap<String, String> formParamValues = LinkedHashMultimap.create();
|
Multimap<String, String> formParamValues = LinkedHashMultimap.create();
|
||||||
formParamValues.putAll(constants);
|
formParamValues.putAll(constants);
|
||||||
Map<Integer, Set<Annotation>> indexToFormParam = methodToIndexOfParamToFormParamAnnotations
|
Map<Integer, Set<Annotation>> indexToFormParam = methodToIndexOfParamToFormParamAnnotations
|
||||||
|
@ -1032,12 +1145,15 @@ public class RestAnnotationProcessor<T> {
|
||||||
.get(method);
|
.get(method);
|
||||||
for (Entry<Integer, Set<Annotation>> entry : indexToFormParam.entrySet()) {
|
for (Entry<Integer, Set<Annotation>> entry : indexToFormParam.entrySet()) {
|
||||||
for (Annotation key : entry.getValue()) {
|
for (Annotation key : entry.getValue()) {
|
||||||
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
|
Set<Annotation> extractors = indexToParamExtractor.get(entry
|
||||||
|
.getKey());
|
||||||
String paramKey = ((FormParam) key).value();
|
String paramKey = ((FormParam) key).value();
|
||||||
String paramValue;
|
String paramValue;
|
||||||
if (extractors != null && extractors.size() > 0) {
|
if (extractors != null && extractors.size() > 0) {
|
||||||
ParamParser extractor = (ParamParser) extractors.iterator().next();
|
ParamParser extractor = (ParamParser) extractors.iterator()
|
||||||
paramValue = injector.getInstance(extractor.value()).apply(args[entry.getKey()]);
|
.next();
|
||||||
|
paramValue = injector.getInstance(extractor.value()).apply(
|
||||||
|
args[entry.getKey()]);
|
||||||
} else {
|
} else {
|
||||||
paramValue = args[entry.getKey()].toString();
|
paramValue = args[entry.getKey()].toString();
|
||||||
}
|
}
|
||||||
|
@ -1048,15 +1164,16 @@ public class RestAnnotationProcessor<T> {
|
||||||
if (method.isAnnotationPresent(FormParam.class)
|
if (method.isAnnotationPresent(FormParam.class)
|
||||||
&& method.isAnnotationPresent(ParamParser.class)) {
|
&& method.isAnnotationPresent(ParamParser.class)) {
|
||||||
String paramKey = method.getAnnotation(FormParam.class).value();
|
String paramKey = method.getAnnotation(FormParam.class).value();
|
||||||
String paramValue = injector.getInstance(method.getAnnotation(ParamParser.class).value())
|
String paramValue = injector.getInstance(
|
||||||
.apply(args);
|
method.getAnnotation(ParamParser.class).value()).apply(args);
|
||||||
formParamValues.put(paramKey, paramValue);
|
formParamValues.put(paramKey, paramValue);
|
||||||
|
|
||||||
}
|
}
|
||||||
return formParamValues;
|
return formParamValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Multimap<String, String> getQueryParamKeyValues(Method method, Object... args) {
|
private Multimap<String, String> getQueryParamKeyValues(Method method,
|
||||||
|
Object... args) {
|
||||||
Multimap<String, String> queryParamValues = LinkedHashMultimap.create();
|
Multimap<String, String> queryParamValues = LinkedHashMultimap.create();
|
||||||
queryParamValues.putAll(constants);
|
queryParamValues.putAll(constants);
|
||||||
Map<Integer, Set<Annotation>> indexToQueryParam = methodToIndexOfParamToQueryParamAnnotations
|
Map<Integer, Set<Annotation>> indexToQueryParam = methodToIndexOfParamToQueryParamAnnotations
|
||||||
|
@ -1066,12 +1183,15 @@ public class RestAnnotationProcessor<T> {
|
||||||
.get(method);
|
.get(method);
|
||||||
for (Entry<Integer, Set<Annotation>> entry : indexToQueryParam.entrySet()) {
|
for (Entry<Integer, Set<Annotation>> entry : indexToQueryParam.entrySet()) {
|
||||||
for (Annotation key : entry.getValue()) {
|
for (Annotation key : entry.getValue()) {
|
||||||
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
|
Set<Annotation> extractors = indexToParamExtractor.get(entry
|
||||||
|
.getKey());
|
||||||
String paramKey = ((QueryParam) key).value();
|
String paramKey = ((QueryParam) key).value();
|
||||||
String paramValue;
|
String paramValue;
|
||||||
if (extractors != null && extractors.size() > 0) {
|
if (extractors != null && extractors.size() > 0) {
|
||||||
ParamParser extractor = (ParamParser) extractors.iterator().next();
|
ParamParser extractor = (ParamParser) extractors.iterator()
|
||||||
paramValue = injector.getInstance(extractor.value()).apply(args[entry.getKey()]);
|
.next();
|
||||||
|
paramValue = injector.getInstance(extractor.value()).apply(
|
||||||
|
args[entry.getKey()]);
|
||||||
} else {
|
} else {
|
||||||
paramValue = args[entry.getKey()].toString();
|
paramValue = args[entry.getKey()].toString();
|
||||||
}
|
}
|
||||||
|
@ -1082,8 +1202,8 @@ public class RestAnnotationProcessor<T> {
|
||||||
if (method.isAnnotationPresent(QueryParam.class)
|
if (method.isAnnotationPresent(QueryParam.class)
|
||||||
&& method.isAnnotationPresent(ParamParser.class)) {
|
&& method.isAnnotationPresent(ParamParser.class)) {
|
||||||
String paramKey = method.getAnnotation(QueryParam.class).value();
|
String paramKey = method.getAnnotation(QueryParam.class).value();
|
||||||
String paramValue = injector.getInstance(method.getAnnotation(ParamParser.class).value())
|
String paramValue = injector.getInstance(
|
||||||
.apply(args);
|
method.getAnnotation(ParamParser.class).value()).apply(args);
|
||||||
queryParamValues.put(paramKey, paramValue);
|
queryParamValues.put(paramKey, paramValue);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1098,12 +1218,15 @@ public class RestAnnotationProcessor<T> {
|
||||||
.get(method);
|
.get(method);
|
||||||
for (Entry<Integer, Set<Annotation>> entry : indexToPathParam.entrySet()) {
|
for (Entry<Integer, Set<Annotation>> entry : indexToPathParam.entrySet()) {
|
||||||
for (Annotation key : entry.getValue()) {
|
for (Annotation key : entry.getValue()) {
|
||||||
Set<Annotation> extractors = indexToParamExtractor.get(entry.getKey());
|
Set<Annotation> extractors = indexToParamExtractor.get(entry
|
||||||
|
.getKey());
|
||||||
String paramKey = ((MapPayloadParam) key).value();
|
String paramKey = ((MapPayloadParam) key).value();
|
||||||
String paramValue;
|
String paramValue;
|
||||||
if (extractors != null && extractors.size() > 0) {
|
if (extractors != null && extractors.size() > 0) {
|
||||||
ParamParser extractor = (ParamParser) extractors.iterator().next();
|
ParamParser extractor = (ParamParser) extractors.iterator()
|
||||||
paramValue = injector.getInstance(extractor.value()).apply(args[entry.getKey()]);
|
.next();
|
||||||
|
paramValue = injector.getInstance(extractor.value()).apply(
|
||||||
|
args[entry.getKey()]);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
paramValue = args[entry.getKey()].toString();
|
paramValue = args[entry.getKey()].toString();
|
||||||
|
@ -1115,19 +1238,4 @@ public class RestAnnotationProcessor<T> {
|
||||||
return postParams;
|
return postParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
public URI getEndpointFor(Method method, Object... args) {
|
|
||||||
URI endpoint = getEndpointInParametersOrNull(method, args);
|
|
||||||
if (endpoint == null) {
|
|
||||||
Endpoint annotation;
|
|
||||||
if (method.isAnnotationPresent(Endpoint.class)) {
|
|
||||||
annotation = method.getAnnotation(Endpoint.class);
|
|
||||||
} else if (method.getDeclaringClass().isAnnotationPresent(Endpoint.class)) {
|
|
||||||
annotation = method.getDeclaringClass().getAnnotation(Endpoint.class);
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("no annotations on class or method: " + method);
|
|
||||||
}
|
|
||||||
return injector.getInstance(Key.get(URI.class, annotation.value()));
|
|
||||||
}
|
|
||||||
return endpoint;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue