diff --git a/core/src/main/java/org/jclouds/collect/internal/CallerArg0ToPagedIterable.java b/core/src/main/java/org/jclouds/collect/internal/CallerArg0ToPagedIterable.java index 51f4603f5b..d1da558336 100644 --- a/core/src/main/java/org/jclouds/collect/internal/CallerArg0ToPagedIterable.java +++ b/core/src/main/java/org/jclouds/collect/internal/CallerArg0ToPagedIterable.java @@ -55,7 +55,7 @@ import com.google.common.base.Optional; public abstract class CallerArg0ToPagedIterable> implements Function, PagedIterable>, InvocationContext { - private GeneratedHttpRequest request; + private GeneratedHttpRequest request; @Override public PagedIterable apply(IterableWithMarker input) { diff --git a/core/src/main/java/org/jclouds/http/HttpUtils.java b/core/src/main/java/org/jclouds/http/HttpUtils.java index a2774c8a65..d173a2fb32 100644 --- a/core/src/main/java/org/jclouds/http/HttpUtils.java +++ b/core/src/main/java/org/jclouds/http/HttpUtils.java @@ -66,7 +66,7 @@ import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Multimap; import com.google.common.collect.ImmutableSet.Builder; -import org.jclouds.reflect.Invokable; +import com.google.common.reflect.Invokable; import com.google.inject.Inject; /** diff --git a/core/src/main/java/org/jclouds/reflect/Element.java b/core/src/main/java/org/jclouds/reflect/Element.java deleted file mode 100644 index e06cd9d7e5..0000000000 --- a/core/src/main/java/org/jclouds/reflect/Element.java +++ /dev/null @@ -1,180 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.jclouds.reflect; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.lang.annotation.Annotation; -import java.lang.reflect.AccessibleObject; -import java.lang.reflect.Member; -import java.lang.reflect.Modifier; - -import org.jclouds.javax.annotation.Nullable; - -import org.jclouds.reflect.Invokable; - -/** - * - * based on the {@link com.google.reflect.AccessibleObject} copied in as {@link com.google.reflect.Invokable} is package - * private. - * - * @author Adrian Cole - * @since 1.6 - */ -class Element extends AccessibleObject implements Member { - - private final AccessibleObject accessibleObject; - protected final Member member; - - Element( M member) { - this.member = checkNotNull(member, "member"); - this.accessibleObject = member; - } - - @Override - public final boolean isAnnotationPresent(Class annotationClass) { - return accessibleObject.isAnnotationPresent(annotationClass); - } - - @Override - public final A getAnnotation(Class annotationClass) { - return accessibleObject.getAnnotation(annotationClass); - } - - @Override - public final Annotation[] getAnnotations() { - return accessibleObject.getAnnotations(); - } - - @Override - public final Annotation[] getDeclaredAnnotations() { - return accessibleObject.getDeclaredAnnotations(); - } - - @Override - public final void setAccessible(boolean flag) throws SecurityException { - accessibleObject.setAccessible(flag); - } - - @Override - public final boolean isAccessible() { - return accessibleObject.isAccessible(); - } - - @Override - public Class getDeclaringClass() { - return member.getDeclaringClass(); - } - - @Override - public final String getName() { - return member.getName(); - } - - @Override - public final int getModifiers() { - return member.getModifiers(); - } - - @Override - public final boolean isSynthetic() { - return member.isSynthetic(); - } - - /** Returns true if the element is public. */ - public final boolean isPublic() { - return Modifier.isPublic(getModifiers()); - } - - /** Returns true if the element is protected. */ - public final boolean isProtected() { - return Modifier.isProtected(getModifiers()); - } - - /** Returns true if the element is package-private. */ - public final boolean isPackagePrivate() { - return !isPrivate() && !isPublic() && !isProtected(); - } - - /** Returns true if the element is private. */ - public final boolean isPrivate() { - return Modifier.isPrivate(getModifiers()); - } - - /** Returns true if the element is static. */ - public final boolean isStatic() { - return Modifier.isStatic(getModifiers()); - } - - /** - * Returns {@code true} if this method is final, per {@code Modifier.isFinal(getModifiers())}. - * - *

- * Note that a method may still be effectively "final", or non-overridable when it has no {@code final} keyword. For - * example, it could be private, or it could be declared by a final class. To tell whether a method is overridable, - * use {@link Invokable#isOverridable}. - */ - public final boolean isFinal() { - return Modifier.isFinal(getModifiers()); - } - - /** Returns true if the method is abstract. */ - public final boolean isAbstract() { - return Modifier.isAbstract(getModifiers()); - } - - /** Returns true if the element is native. */ - public final boolean isNative() { - return Modifier.isNative(getModifiers()); - } - - /** Returns true if the method is synchronized. */ - public final boolean isSynchronized() { - return Modifier.isSynchronized(getModifiers()); - } - - /** Returns true if the field is volatile. */ - final boolean isVolatile() { - return Modifier.isVolatile(getModifiers()); - } - - /** Returns true if the field is transient. */ - final boolean isTransient() { - return Modifier.isTransient(getModifiers()); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj instanceof Element) { - Element that = (Element) obj; - return member.equals(that.member); - } - return false; - } - - @Override - public int hashCode() { - return member.hashCode(); - } - - @Override - public String toString() { - return member.toString(); - } -} diff --git a/core/src/main/java/org/jclouds/reflect/FunctionalReflection.java b/core/src/main/java/org/jclouds/reflect/FunctionalReflection.java index 0e92fdca5a..30a6e245c8 100644 --- a/core/src/main/java/org/jclouds/reflect/FunctionalReflection.java +++ b/core/src/main/java/org/jclouds/reflect/FunctionalReflection.java @@ -38,6 +38,7 @@ import com.google.common.annotations.Beta; import com.google.common.base.Function; import com.google.common.base.Objects; import com.google.common.collect.ImmutableList; +import com.google.common.reflect.Invokable; import com.google.common.reflect.TypeToken; /** @@ -113,7 +114,7 @@ public final class FunctionalReflection { args = ImmutableList.copyOf(args); else args = Collections.unmodifiableList(args); - Invokable invokable = Invokable.from(enclosingType, invoked); + Invokable invokable = Invokable.from(invoked); // not yet support the proxy arg Invocation invocation = Invocation.create(invokable, args); Result result; diff --git a/core/src/main/java/org/jclouds/reflect/Invocation.java b/core/src/main/java/org/jclouds/reflect/Invocation.java index cb9168b6d9..896b2d5861 100644 --- a/core/src/main/java/org/jclouds/reflect/Invocation.java +++ b/core/src/main/java/org/jclouds/reflect/Invocation.java @@ -28,9 +28,10 @@ import org.jclouds.javax.annotation.Nullable; import com.google.common.annotations.Beta; import com.google.common.base.Objects; import com.google.common.base.Optional; +import com.google.common.reflect.Invokable; /** - * Context needed to call {@link org.jclouds.reflect.Invokable#invoke(Object, Object...)} + * Context needed to call {@link com.google.common.reflect.Invokable#invoke(Object, Object...)} * * @author Adrian Cole */ diff --git a/core/src/main/java/org/jclouds/reflect/InvocationSuccess.java b/core/src/main/java/org/jclouds/reflect/InvocationSuccess.java index ff1334728d..fbc018a74c 100644 --- a/core/src/main/java/org/jclouds/reflect/InvocationSuccess.java +++ b/core/src/main/java/org/jclouds/reflect/InvocationSuccess.java @@ -29,7 +29,7 @@ import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Optional; /** - * Holds the context of a successful call to {@link org.jclouds.reflect.Invokable#invoke(Object, Object...)} + * Holds the context of a successful call to {@link com.google.common.reflect.Invokable#invoke(Object, Object...)} * * @author Adrian Cole */ diff --git a/core/src/main/java/org/jclouds/reflect/Invokable.java b/core/src/main/java/org/jclouds/reflect/Invokable.java deleted file mode 100644 index c10bc568f7..0000000000 --- a/core/src/main/java/org/jclouds/reflect/Invokable.java +++ /dev/null @@ -1,347 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.jclouds.reflect; - -import static com.google.common.base.Objects.equal; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import java.lang.annotation.Annotation; -import java.lang.reflect.AccessibleObject; -import java.lang.reflect.Constructor; -import java.lang.reflect.GenericDeclaration; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Member; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; -import java.util.Arrays; - -import org.jclouds.javax.annotation.Nullable; - -import com.google.common.annotations.Beta; -import com.google.common.base.Objects; -import com.google.common.collect.ImmutableList; -import com.google.common.reflect.TypeToken; - -/** - * based on the {@link com.google.reflect.AccessibleObject} copied in as {@link com.google.reflect.Invokable} is package - * private. This adds access to {#link {@link #getEnclosingType()} and folds in ability to lookup methods and - * constructors by name. - * - * @author Adrian Cole - * @since 1.6 - */ -@Beta -public abstract class Invokable extends Element implements GenericDeclaration { - protected final TypeToken enclosingType; - - Invokable(TypeToken enclosingType, M member) { - super(member); - this.enclosingType = checkNotNull(enclosingType, "enclosingType"); - } - - /** Returns {@link Invokable} of {@code method}. */ - public static Invokable from(Method method) { - return from(TypeToken.of(method.getDeclaringClass()), method); - } - - /** Returns {@link Invokable} of {@code constructor}. */ - public static Invokable from(Constructor constructor) { - return from(TypeToken.of(constructor.getDeclaringClass()), constructor); - } - - /** Returns {@link Invokable} of {@code method}. */ - public static Invokable from(TypeToken enclosingType, Method method) { - return new MethodInvokable(enclosingType, method); - } - - /** Returns {@link Invokable} of {@code constructor}. */ - public static Invokable from(TypeToken enclosingType, Constructor constructor) { - return new ConstructorInvokable(enclosingType, constructor); - } - - /** - * different than {@link #getDeclaringClass()} when this is a member of a class it was not declared in. - */ - public TypeToken getEnclosingType() { - return enclosingType; - } - - /** - * Returns {@code true} if this is an overridable method. Constructors, private, static or final methods, or methods - * declared by final classes are not overridable. - */ - public abstract boolean isOverridable(); - - /** Returns {@code true} if this was declared to take a variable number of arguments. */ - public abstract boolean isVarArgs(); - - /** - * Invokes with {@code receiver} as 'this' and {@code args} passed to the underlying method and returns the return - * value; or calls the underlying constructor with {@code args} and returns the constructed instance. - * - * @throws IllegalAccessException - * if this {@code Constructor} object enforces Java language access control and the underlying method or - * constructor is inaccessible. - * @throws IllegalArgumentException - * if the number of actual and formal parameters differ; if an unwrapping conversion for primitive - * arguments fails; or if, after possible unwrapping, a parameter value cannot be converted to the - * corresponding formal parameter type by a method invocation conversion. - * @throws InvocationTargetException - * if the underlying method or constructor throws an exception. - */ - // All subclasses are owned by us and we'll make sure to get the R type right. - @SuppressWarnings("unchecked") - public final R invoke(@Nullable T receiver, Object... args) throws InvocationTargetException, IllegalAccessException { - return (R) invokeInternal(receiver, checkNotNull(args, "args")); - } - - /** Returns the return type of this {@code Invokable}. */ - // All subclasses are owned by us and we'll make sure to get the R type right. - @SuppressWarnings("unchecked") - public final TypeToken getReturnType() { - return (TypeToken) TypeToken.of(getGenericReturnType()); - } - - /** - * Returns all declared parameters of this {@code Invokable}. Note that if this is a constructor of a non-static - * inner class, unlike {@link Constructor#getParameterTypes}, the hidden {@code this} parameter of the enclosing - * class is excluded from the returned parameters. - */ - public final ImmutableList getParameters() { - Type[] parameterTypes = getGenericParameterTypes(); - Annotation[][] annotations = getParameterAnnotations(); - ImmutableList.Builder builder = ImmutableList.builder(); - for (int i = 0; i < parameterTypes.length; i++) { - builder.add(new Parameter(this, i, TypeToken.of(parameterTypes[i]), annotations[i])); - } - return builder.build(); - } - - /** Returns all declared exception types of this {@code Invokable}. */ - public final ImmutableList> getExceptionTypes() { - ImmutableList.Builder> builder = ImmutableList.builder(); - for (Type type : getGenericExceptionTypes()) { - // getGenericExceptionTypes() will never return a type that's not exception - @SuppressWarnings("unchecked") - TypeToken exceptionType = (TypeToken) TypeToken.of(type); - builder.add(exceptionType); - } - return builder.build(); - } - - /** - * Explicitly specifies the return type of this {@code Invokable}. For example: - * - *

-    * {
-    *    @code
-    *    Method factoryMethod = Person.class.getMethod("create");
-    *    Invokable<?, Person> factory = Invokable.of(getNameMethod).returning(Person.class);
-    * }
-    * 
- */ - public final Invokable returning(Class returnType) { - return returning(TypeToken.of(returnType)); - } - - /** Explicitly specifies the return type of this {@code Invokable}. */ - public final Invokable returning(TypeToken returnType) { - if (!returnType.isAssignableFrom(getReturnType())) { - throw new IllegalArgumentException("Invokable is known to return " + getReturnType() + ", not " + returnType); - } - @SuppressWarnings("unchecked") - // guarded by previous check - Invokable specialized = (Invokable) this; - return specialized; - } - - @SuppressWarnings("unchecked") - // The declaring class is T's raw class, or one of its supertypes. - @Override - public final Class getDeclaringClass() { - return (Class) super.getDeclaringClass(); - } - - abstract Object invokeInternal(@Nullable Object receiver, Object[] args) throws InvocationTargetException, - IllegalAccessException; - - abstract Type[] getGenericParameterTypes(); - - /** This should never return a type that's not a subtype of Throwable. */ - abstract Type[] getGenericExceptionTypes(); - - abstract Annotation[][] getParameterAnnotations(); - - abstract Type getGenericReturnType(); - - static class MethodInvokable extends Invokable { - - private final Method method; - - MethodInvokable(TypeToken enclosingType, Method method) { - super(enclosingType, method); - this.method = method; - checkArgument(TypeToken.of(method.getDeclaringClass()).isAssignableFrom(enclosingType), - "%s not declared by %s", method, enclosingType); - } - - @Override - final Object invokeInternal(@Nullable Object receiver, Object[] args) throws InvocationTargetException, - IllegalAccessException { - return method.invoke(receiver, args); - } - - @Override - Type getGenericReturnType() { - return resolveType(method.getGenericReturnType()).getType(); - } - - @Override - Type[] getGenericParameterTypes() { - return resolveInPlace(method.getGenericParameterTypes()); - } - - @Override - Type[] getGenericExceptionTypes() { - return resolveInPlace(method.getGenericExceptionTypes()); - } - - @Override - final Annotation[][] getParameterAnnotations() { - return method.getParameterAnnotations(); - } - - @Override - public final TypeVariable[] getTypeParameters() { - return method.getTypeParameters(); - } - - @Override - public final boolean isOverridable() { - return !(isFinal() || isPrivate() || isStatic() || Modifier.isFinal(getDeclaringClass().getModifiers())); - } - - @Override - public final boolean isVarArgs() { - return method.isVarArgs(); - } - } - - protected TypeToken resolveType(Type type) { - return enclosingType.resolveType(type); - } - - protected Type[] resolveInPlace(Type[] types) { - for (int i = 0; i < types.length; i++) { - types[i] = resolveType(types[i]).getType(); - } - return types; - } - - static class ConstructorInvokable extends Invokable { - - private final Constructor constructor; - - ConstructorInvokable(TypeToken enclosingType, Constructor constructor) { - super(enclosingType, constructor); - this.constructor = constructor; - checkArgument(constructor.getDeclaringClass() == enclosingType.getRawType(), "%s not declared by %s", - constructor, enclosingType.getRawType()); - } - - @Override - final Object invokeInternal(@Nullable Object receiver, Object[] args) throws InvocationTargetException, - IllegalAccessException { - try { - return constructor.newInstance(args); - } catch (InstantiationException e) { - throw new RuntimeException(constructor + " failed.", e); - } - } - - @Override - Type getGenericReturnType() { - return resolveType(constructor.getDeclaringClass()).getType(); - } - - @Override - Type[] getGenericParameterTypes() { - Type[] types = constructor.getGenericParameterTypes(); - Class declaringClass = constructor.getDeclaringClass(); - if (!Modifier.isStatic(declaringClass.getModifiers()) && declaringClass.getEnclosingClass() != null) { - if (types.length == constructor.getParameterTypes().length) { - // first parameter is the hidden 'this' - return Arrays.copyOfRange(types, 1, types.length); - } - } - return resolveInPlace(types); - } - - @Override - Type[] getGenericExceptionTypes() { - return resolveInPlace(constructor.getGenericExceptionTypes()); - } - - @Override - final Annotation[][] getParameterAnnotations() { - return constructor.getParameterAnnotations(); - } - - @Override - public final TypeVariable[] getTypeParameters() { - return constructor.getTypeParameters(); - } - - @Override - public final boolean isOverridable() { - return false; - } - - @Override - public final boolean isVarArgs() { - return constructor.isVarArgs(); - } - } - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - if (o == null || getClass() != o.getClass()) - return false; - Invokable that = Invokable.class.cast(o); - return equal(this.enclosingType, that.enclosingType) && super.equals(o); - } - - @Override - public int hashCode() { - return Objects.hashCode(enclosingType, super.hashCode()); - } - - @Override - public String toString() { - int parametersTypeHashCode = 0; - for (Parameter param : getParameters()) - parametersTypeHashCode += param.getType().hashCode(); - return String.format("%s.%s[%s]", enclosingType.getRawType().getSimpleName(), getName(), parametersTypeHashCode); - } -} diff --git a/core/src/main/java/org/jclouds/reflect/Parameter.java b/core/src/main/java/org/jclouds/reflect/Parameter.java deleted file mode 100644 index 7948de399c..0000000000 --- a/core/src/main/java/org/jclouds/reflect/Parameter.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.jclouds.reflect; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; - -import org.jclouds.javax.annotation.Nullable; - -import com.google.common.annotations.Beta; -import com.google.common.collect.ImmutableList; -import com.google.common.reflect.TypeToken; - -/** - * - * based on the {@link com.google.reflect.AccessibleObject} copied in as {@link com.google.reflect.Parameter} is package - * private and decided not to add {@link #getPosition} - * - * @author Adrian Cole - * @since 1.6 - */ -@Beta -public final class Parameter implements AnnotatedElement { - - private final Invokable declaration; - private final int position; - private final TypeToken type; - private final ImmutableList annotations; - - Parameter(Invokable declaration, int position, TypeToken type, Annotation[] annotations) { - this.declaration = declaration; - this.position = position; - this.type = type; - this.annotations = ImmutableList.copyOf(annotations); - } - - /** Returns the position of the parameter. */ - public int getPosition() { - return position; - } - - /** Returns the type of the parameter. */ - public TypeToken getType() { - return type; - } - - /** Returns the {@link Invokable} that declares this parameter. */ - public Invokable getDeclaringInvokable() { - return declaration; - } - - @Override - public boolean isAnnotationPresent(Class annotationType) { - return getAnnotation(annotationType) != null; - } - - @Override - @Nullable - public
A getAnnotation(Class annotationType) { - checkNotNull(annotationType); - for (Annotation annotation : annotations) { - if (annotationType.isInstance(annotation)) { - return annotationType.cast(annotation); - } - } - return null; - } - - @Override - public Annotation[] getAnnotations() { - return getDeclaredAnnotations(); - } - - @Override - public Annotation[] getDeclaredAnnotations() { - return annotations.toArray(new Annotation[annotations.size()]); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (obj instanceof Parameter) { - Parameter that = (Parameter) obj; - return position == that.position && declaration.equals(that.declaration); - } - return false; - } - - @Override - public int hashCode() { - return position; - } - - @Override - public String toString() { - return type + " arg" + position; - } -} diff --git a/core/src/main/java/org/jclouds/rest/InputParamValidator.java b/core/src/main/java/org/jclouds/rest/InputParamValidator.java index fa61c5fef0..f33e4b82ad 100644 --- a/core/src/main/java/org/jclouds/rest/InputParamValidator.java +++ b/core/src/main/java/org/jclouds/rest/InputParamValidator.java @@ -27,12 +27,12 @@ import javax.inject.Inject; import org.jclouds.predicates.Validator; import org.jclouds.reflect.Invocation; -import org.jclouds.reflect.Parameter; import org.jclouds.rest.annotations.ParamValidators; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; +import com.google.common.reflect.Parameter; import com.google.inject.Injector; /** diff --git a/core/src/main/java/org/jclouds/rest/binders/BindMapToStringPayload.java b/core/src/main/java/org/jclouds/rest/binders/BindMapToStringPayload.java index 2be6fc7f45..cc3332db2d 100644 --- a/core/src/main/java/org/jclouds/rest/binders/BindMapToStringPayload.java +++ b/core/src/main/java/org/jclouds/rest/binders/BindMapToStringPayload.java @@ -32,7 +32,7 @@ import org.jclouds.rest.MapBinder; import org.jclouds.rest.annotations.Payload; import org.jclouds.rest.internal.GeneratedHttpRequest; -import org.jclouds.reflect.Invokable; +import com.google.common.reflect.Invokable; /** * diff --git a/core/src/main/java/org/jclouds/rest/config/AsyncClientProvider.java b/core/src/main/java/org/jclouds/rest/config/AsyncHttpApiProvider.java similarity index 64% rename from core/src/main/java/org/jclouds/rest/config/AsyncClientProvider.java rename to core/src/main/java/org/jclouds/rest/config/AsyncHttpApiProvider.java index e4920d0d52..a8125229a1 100644 --- a/core/src/main/java/org/jclouds/rest/config/AsyncClientProvider.java +++ b/core/src/main/java/org/jclouds/rest/config/AsyncHttpApiProvider.java @@ -22,7 +22,8 @@ import javax.inject.Inject; import javax.inject.Singleton; import org.jclouds.reflect.FunctionalReflection; -import org.jclouds.rest.internal.InvokeAsyncApi; +import org.jclouds.rest.internal.DelegatingInvocationFunction; +import org.jclouds.rest.internal.InvokeHttpMethod; import com.google.inject.Provider; import com.google.inject.TypeLiteral; @@ -32,21 +33,21 @@ import com.google.inject.TypeLiteral; * @author Adrian Cole */ @Singleton -public class AsyncClientProvider implements Provider { - private final Class asyncClientType; - private final InvokeAsyncApi proxy; +public class AsyncHttpApiProvider implements Provider { + private final Class asyncApiType; + private final DelegatingInvocationFunction> httpInvoker; @Inject - private AsyncClientProvider(InvokeAsyncApi proxy, TypeLiteral asyncClientType) { - this.proxy = proxy; - this.asyncClientType = asyncClientType.getRawType(); + private AsyncHttpApiProvider(DelegatingInvocationFunction> httpInvoker, + TypeLiteral asyncApiType) { + this.httpInvoker = httpInvoker; + this.asyncApiType = asyncApiType.getRawType(); } @SuppressWarnings("unchecked") @Override - @Singleton public A get() { - return (A) FunctionalReflection.newProxy(asyncClientType, proxy); + return (A) FunctionalReflection.newProxy(asyncApiType, httpInvoker); } } diff --git a/core/src/main/java/org/jclouds/rest/config/BinderUtils.java b/core/src/main/java/org/jclouds/rest/config/BinderUtils.java index 3a8463a600..4cf560c9f9 100644 --- a/core/src/main/java/org/jclouds/rest/config/BinderUtils.java +++ b/core/src/main/java/org/jclouds/rest/config/BinderUtils.java @@ -45,13 +45,31 @@ public class BinderUtils { * @param async * type type that returns {@link ListenableFuture} */ - public static void bindClientAndAsyncClient(Binder binder, Class sync, Class async) { + public static void bindHttpApi(Binder binder, Class sync, Class async) { bindClass(binder, sync); bindClass(binder, async); - bindAsyncClientProvider(binder, async); - bindClientProvider(binder, sync, async); + bindAsyncHttpApiProvider(binder, async); + bindHttpApiProvider(binder, sync, async); + } + + @SuppressWarnings("unchecked") + private static void bindAsyncHttpApiProvider(Binder binder, Class async) { + TypeToken> token = new TypeToken>() { + private static final long serialVersionUID = 1L; + }.where(new TypeParameter() { + }, async); + binder.bind(async).toProvider(TypeLiteral.class.cast(TypeLiteral.get(token.getType()))); + } + + @SuppressWarnings("unchecked") + private static void bindHttpApiProvider(Binder binder, Class sync, Class async) { + TypeToken> token = new TypeToken>() { + private static final long serialVersionUID = 1L; + }.where(new TypeParameter() { + }, sync).where(new TypeParameter() { + }, async); + binder.bind(sync).toProvider(TypeLiteral.class.cast(TypeLiteral.get(token.getType()))); } - /** * adds an explicit binding for an interface which synchronously blocks on similar calls to an {@code async} type. * @@ -66,15 +84,15 @@ public class BinderUtils { * @param async * type type that returns {@link ListenableFuture} */ - public static void bindClient(Binder binder, Class sync, Class async) { + public static void bindBlockingApi(Binder binder, Class sync, Class async) { bindClass(binder, sync); bindClass(binder, async); - bindClientProvider(binder, sync, async); + bindCallGetOnFutures(binder, sync, async); } @SuppressWarnings("unchecked") - private static void bindClientProvider(Binder binder, Class sync, Class async) { - TypeToken> token = new TypeToken>() { + private static void bindCallGetOnFutures(Binder binder, Class sync, Class async) { + TypeToken> token = new TypeToken>() { private static final long serialVersionUID = 1L; }.where(new TypeParameter() { }, sync).where(new TypeParameter() { @@ -89,19 +107,4 @@ public class BinderUtils { }.where(new TypeParameter() { }, sync).getType()))).toInstance(sync); } - - public static void bindAsyncClient(Binder binder, Class async) { - bindClass(binder, async); - bindAsyncClientProvider(binder, async); - } - - @SuppressWarnings("unchecked") - private static void bindAsyncClientProvider(Binder binder, Class async) { - TypeToken> token = new TypeToken>() { - private static final long serialVersionUID = 1L; - }.where(new TypeParameter() { - }, async); - binder.bind(async).toProvider(TypeLiteral.class.cast(TypeLiteral.get(token.getType()))); - } - } diff --git a/core/src/main/java/org/jclouds/rest/config/CallGetOnFuturesProvider.java b/core/src/main/java/org/jclouds/rest/config/CallGetOnFuturesProvider.java new file mode 100644 index 0000000000..edb266b379 --- /dev/null +++ b/core/src/main/java/org/jclouds/rest/config/CallGetOnFuturesProvider.java @@ -0,0 +1,57 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.rest.config; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.reflect.FunctionalReflection; +import com.google.common.reflect.Invokable; +import org.jclouds.rest.internal.DelegatingInvocationFunction; +import org.jclouds.rest.internal.InvokeAndCallGetOnFutures; + +import com.google.common.cache.Cache; +import com.google.common.reflect.TypeToken; +import com.google.inject.Provider; + +/** + * @author Adrian Cole + */ +@Singleton +public class CallGetOnFuturesProvider implements Provider { + + private final Class apiType; + private final DelegatingInvocationFunction> syncInvoker; + + @Inject + private CallGetOnFuturesProvider(Cache, Invokable> invokables, + DelegatingInvocationFunction> syncInvoker, Class apiType, + Class asyncApiType) { + this.syncInvoker = syncInvoker; + this.apiType = apiType; + RestModule.putInvokables(TypeToken.of(apiType), TypeToken.of(asyncApiType), invokables); + } + + @SuppressWarnings("unchecked") + @Override + @Singleton + public S get() { + return (S) FunctionalReflection.newProxy(apiType, syncInvoker); + } +} diff --git a/core/src/main/java/org/jclouds/rest/config/ClientProvider.java b/core/src/main/java/org/jclouds/rest/config/HttpApiProvider.java similarity index 55% rename from core/src/main/java/org/jclouds/rest/config/ClientProvider.java rename to core/src/main/java/org/jclouds/rest/config/HttpApiProvider.java index ec8487611d..cfdfa12fba 100644 --- a/core/src/main/java/org/jclouds/rest/config/ClientProvider.java +++ b/core/src/main/java/org/jclouds/rest/config/HttpApiProvider.java @@ -22,38 +22,36 @@ import javax.inject.Inject; import javax.inject.Singleton; import org.jclouds.reflect.FunctionalReflection; -import org.jclouds.reflect.Invokable; -import org.jclouds.rest.internal.InvokeSyncApi; +import com.google.common.reflect.Invokable; +import org.jclouds.rest.internal.DelegatingInvocationFunction; +import org.jclouds.rest.internal.InvokeHttpMethod; import com.google.common.cache.Cache; import com.google.common.reflect.TypeToken; import com.google.inject.Provider; /** - * ClientProvider makes the primary interface for the provider context. ex. - * {@code context.getProviderSpecificContext().getApi()} is created by ClientProvider, which is a singleton * * @author Adrian Cole */ @Singleton -public class ClientProvider implements Provider { - - private final InvokeSyncApi.Factory factory; - private final Class syncClientType; - private final A asyncClient; +public class HttpApiProvider implements Provider { + private final Class apiType; + private final DelegatingInvocationFunction> httpInvoker; @Inject - private ClientProvider(Cache, Invokable> invokables, InvokeSyncApi.Factory factory, - Class syncClientType, Class asyncClientType, A asyncClient) { - this.factory = factory; - this.asyncClient = asyncClient; - this.syncClientType = syncClientType; - RestModule.putInvokables(TypeToken.of(syncClientType), TypeToken.of(asyncClientType), invokables); + private HttpApiProvider(Cache, Invokable> invokables, + DelegatingInvocationFunction> httpInvoker, Class apiType, Class asyncApiType) { + this.httpInvoker = httpInvoker; + this.apiType = apiType; + RestModule.putInvokables(TypeToken.of(apiType), TypeToken.of(asyncApiType), invokables); } + @SuppressWarnings("unchecked") @Override @Singleton public S get() { - return FunctionalReflection.newProxy(syncClientType, factory.create(asyncClient)); + return (S) FunctionalReflection.newProxy(apiType, httpInvoker); } + } diff --git a/core/src/main/java/org/jclouds/rest/config/RestClientModule.java b/core/src/main/java/org/jclouds/rest/config/RestClientModule.java index 9f2b685497..dfa63c1770 100644 --- a/core/src/main/java/org/jclouds/rest/config/RestClientModule.java +++ b/core/src/main/java/org/jclouds/rest/config/RestClientModule.java @@ -19,7 +19,7 @@ package org.jclouds.rest.config; import static com.google.common.base.Preconditions.checkState; -import static org.jclouds.rest.config.BinderUtils.bindClientAndAsyncClient; +import static org.jclouds.rest.config.BinderUtils.bindHttpApi; import java.lang.reflect.TypeVariable; import java.util.Map; @@ -87,7 +87,7 @@ public class RestClientModule extends RestModule { @Override protected void configure() { super.configure(); - bindClientAndAsyncClient(binder(), syncClientType.getRawType(), asyncClientType.getRawType()); + bindHttpApi(binder(), syncClientType.getRawType(), asyncClientType.getRawType()); bindErrorHandlers(); bindRetryHandlers(); } diff --git a/core/src/main/java/org/jclouds/rest/config/RestModule.java b/core/src/main/java/org/jclouds/rest/config/RestModule.java index 2d4625ca87..47999c0dad 100644 --- a/core/src/main/java/org/jclouds/rest/config/RestModule.java +++ b/core/src/main/java/org/jclouds/rest/config/RestModule.java @@ -20,12 +20,10 @@ package org.jclouds.rest.config; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Throwables.propagate; -import static com.google.common.collect.Iterables.any; import static com.google.common.collect.Maps.transformValues; import static com.google.common.util.concurrent.Atomics.newReference; import static org.jclouds.Constants.PROPERTY_TIMEOUTS_PREFIX; -import static org.jclouds.http.HttpUtils.tryFindHttpMethod; -import static org.jclouds.rest.config.BinderUtils.bindClientAndAsyncClient; +import static org.jclouds.rest.config.BinderUtils.bindHttpApi; import static org.jclouds.util.Maps2.transformKeys; import static org.jclouds.util.Predicates2.startsWith; @@ -38,40 +36,27 @@ import java.util.concurrent.atomic.AtomicReference; import javax.inject.Named; import javax.inject.Singleton; -import javax.ws.rs.Path; import org.jclouds.functions.IdentityFunction; -import org.jclouds.http.HttpRequest; -import org.jclouds.http.HttpResponse; import org.jclouds.http.functions.config.SaxParserModule; import org.jclouds.internal.FilterStringsBoundToInjectorByName; import org.jclouds.json.config.GsonModule; import org.jclouds.location.config.LocationModule; -import org.jclouds.reflect.Invocation; -import org.jclouds.reflect.Invokable; -import org.jclouds.reflect.Parameter; +import com.google.common.reflect.Invokable; import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.HttpAsyncClient; import org.jclouds.rest.HttpClient; import org.jclouds.rest.binders.BindToJsonPayloadWrappedWith; -import org.jclouds.rest.internal.GeneratedHttpRequest; -import org.jclouds.rest.internal.InvokeAsyncApi; -import org.jclouds.rest.internal.InvokeFutureAndBlock; -import org.jclouds.rest.internal.InvokeListenableFutureViaHttp; -import org.jclouds.rest.internal.InvokeSyncApi; -import org.jclouds.rest.internal.TransformerForRequest; +import org.jclouds.rest.internal.BlockOnFuture; import com.google.common.base.Function; -import com.google.common.base.Objects; import com.google.common.base.Predicate; import com.google.common.base.Supplier; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; -import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.reflect.TypeToken; -import com.google.common.util.concurrent.ListenableFuture; import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.TypeLiteral; @@ -94,42 +79,7 @@ public class RestModule extends AbstractModule { public RestModule(Map, Class> sync2Async) { this.sync2Async = sync2Async; } - - @Provides - @Singleton - protected Predicate> mapsToAsyncHttpRequest(final Cache, Invokable> backing) { - return new Predicate>() { - public boolean apply(Invokable in) { // TODO: this is dynamic, but perhaps needs to be cached - return FluentIterable.from(backing.asMap().values()).anyMatch(mapsToAsyncHttpRequest(in)); - } - }; - } - - private static Predicate> mapsToAsyncHttpRequest(Invokable toTest) { - final int soughtHash = hashEnclosingTypeNameAndParameters(toTest); - return new Predicate>() { - public boolean apply(Invokable in) { - return in.isAnnotationPresent(Path.class) || tryFindHttpMethod(in).isPresent() - || any(in.getParameters(), new Predicate() { - public boolean apply(Parameter in) { - return in.getType().getRawType().isAssignableFrom(HttpRequest.class); - } - }) && in.getReturnType().getRawType().isAssignableFrom(ListenableFuture.class) - && soughtHash == hashEnclosingTypeNameAndParameters(in); - } - }; - } - - /** - * when looking for a match, we ignore the return type - */ - public static int hashEnclosingTypeNameAndParameters(Invokable in) { - int parametersTypeHashCode = 0; - for (Parameter param : in.getParameters()) - parametersTypeHashCode += param.getType().hashCode(); - return Objects.hashCode(in.getEnclosingType(), in.getName(), parametersTypeHashCode); - } - + /** * seeds well-known invokables. */ @@ -150,11 +100,11 @@ public class RestModule extends AbstractModule { if (!objectMethods.contains(invoked)) { try { Method delegatedMethod = async.getRawType().getMethod(invoked.getName(), invoked.getParameterTypes()); - checkArgument(Arrays.equals(delegatedMethod.getExceptionTypes(), invoked.getExceptionTypes()), "invoked %s has different typed exceptions than delegated invoked %s", invoked, - delegatedMethod); + checkArgument(Arrays.equals(delegatedMethod.getExceptionTypes(), invoked.getExceptionTypes()), + "invoked %s has different typed exceptions than delegated invoked %s", invoked, delegatedMethod); invoked.setAccessible(true); delegatedMethod.setAccessible(true); - cache.put(Invokable.from(sync, invoked), Invokable.from(async, delegatedMethod)); + cache.put(Invokable.from(invoked), Invokable.from(delegatedMethod)); } catch (SecurityException e) { throw propagate(e); } catch (NoSuchMethodException e) { @@ -174,13 +124,11 @@ public class RestModule extends AbstractModule { }).toInstance(sync2Async); install(new SaxParserModule()); install(new GsonModule()); + install(new SetCaller.Module()); install(new FactoryModuleBuilder().build(BindToJsonPayloadWrappedWith.Factory.class)); - install(new FactoryModuleBuilder().build(InvokeAsyncApi.Delegate.Factory.class)); - install(new FactoryModuleBuilder().build(InvokeFutureAndBlock.Factory.class)); - install(new FactoryModuleBuilder().build(InvokeListenableFutureViaHttp.Caller.Factory.class)); + install(new FactoryModuleBuilder().build(BlockOnFuture.Factory.class)); bind(IdentityFunction.class).toInstance(IdentityFunction.INSTANCE); - install(new FactoryModuleBuilder().build(InvokeSyncApi.Factory.class)); - bindClientAndAsyncClient(binder(), HttpClient.class, HttpAsyncClient.class); + bindHttpApi(binder(), HttpClient.class, HttpAsyncClient.class); // this will help short circuit scenarios that can otherwise lock out users bind(new TypeLiteral>() { }).toInstance(authException); @@ -188,10 +136,6 @@ public class RestModule extends AbstractModule { }).to(FilterStringsBoundToInjectorByName.class); bind(new TypeLiteral, Map>>() { }).to(FilterStringsBoundToInjectorByName.class); - bind(new TypeLiteral>>() { - }).to(InvokeListenableFutureViaHttp.class); - bind(new TypeLiteral>>() { - }).to(TransformerForRequest.class); installLocations(); } @@ -199,7 +143,8 @@ public class RestModule extends AbstractModule { @Singleton @Named("TIMEOUTS") protected Map timeouts(Function, Map> filterStringsBoundByName) { - Map stringBoundWithTimeoutPrefix = filterStringsBoundByName.apply(startsWith(PROPERTY_TIMEOUTS_PREFIX)); + Map stringBoundWithTimeoutPrefix = filterStringsBoundByName + .apply(startsWith(PROPERTY_TIMEOUTS_PREFIX)); Map longsByName = transformValues(stringBoundWithTimeoutPrefix, new Function() { public Long apply(String input) { return Long.valueOf(String.valueOf(input)); diff --git a/core/src/main/java/org/jclouds/rest/config/SetCaller.java b/core/src/main/java/org/jclouds/rest/config/SetCaller.java new file mode 100644 index 0000000000..06b1bd868a --- /dev/null +++ b/core/src/main/java/org/jclouds/rest/config/SetCaller.java @@ -0,0 +1,83 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.rest.config; + +import static com.google.common.base.Preconditions.checkState; + +import org.jclouds.reflect.Invocation; + +import com.google.common.reflect.TypeToken; +import com.google.inject.AbstractModule; +import com.google.inject.Key; +import com.google.inject.Provider; +import com.google.inject.TypeLiteral; +import com.google.inject.name.Names; + +/** + * Allows the provider to supply a value set in a threadlocal. + * + * @author Adrian Cole + */ +public class SetCaller { + + private final ThreadLocal> callerEnclosingType = new ThreadLocal>(); + private final ThreadLocal caller = new ThreadLocal(); + + public void enter(TypeToken callerEnclosingType, Invocation caller) { + checkState(this.callerEnclosingType.get() == null, "A scoping block is already in progress"); + this.callerEnclosingType.set(callerEnclosingType); + this.caller.set(caller); + } + + public void exit() { + checkState(caller.get() != null, "No scoping block in progress"); + callerEnclosingType.remove(); + caller.remove(); + } + + public static class Module extends AbstractModule { + public void configure() { + SetCaller delegateScope = new SetCaller(); + bind(CALLER_ENCLOSING_TYPE).toProvider(delegateScope.new CallerEnclosingTypeProvider()); + bind(CALLER_INVOCATION).toProvider(delegateScope.new CallerInvocationProvider()); + bind(SetCaller.class).toInstance(delegateScope); + } + } + + private static final Key> CALLER_ENCLOSING_TYPE = Key.get(new TypeLiteral>() { + }, Names.named("caller")); + + private static final Key CALLER_INVOCATION = Key.get(new TypeLiteral() { + }, Names.named("caller")); + + class CallerEnclosingTypeProvider implements Provider> { + @Override + public TypeToken get() { + return callerEnclosingType.get(); + } + } + + class CallerInvocationProvider implements Provider { + @Override + public Invocation get() { + return caller.get(); + } + } + +} diff --git a/core/src/main/java/org/jclouds/rest/internal/BaseInvocationFunction.java b/core/src/main/java/org/jclouds/rest/internal/BaseInvocationFunction.java deleted file mode 100644 index e06a77c995..0000000000 --- a/core/src/main/java/org/jclouds/rest/internal/BaseInvocationFunction.java +++ /dev/null @@ -1,127 +0,0 @@ -package org.jclouds.rest.internal; - -import static com.google.common.base.Throwables.propagate; -import static com.google.common.collect.Iterables.find; -import static com.google.inject.util.Types.newParameterizedType; -import static org.jclouds.util.Optionals2.isReturnTypeOptional; -import static org.jclouds.util.Optionals2.unwrapIfOptional; -import static org.jclouds.util.Throwables2.getFirstThrowableOfType; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Type; - -import javax.inject.Qualifier; - -import org.jclouds.reflect.FunctionalReflection; -import org.jclouds.reflect.Invocation; -import org.jclouds.reflect.Invocation.Result; -import org.jclouds.reflect.InvocationSuccess; -import org.jclouds.reflect.Invokable; -import org.jclouds.rest.AuthorizationException; -import org.jclouds.rest.annotations.Delegate; - -import com.google.common.annotations.Beta; -import com.google.common.base.Function; -import com.google.common.base.Optional; -import com.google.common.base.Predicate; -import com.google.common.base.Supplier; -import com.google.common.collect.ImmutableList; -import com.google.inject.Binding; -import com.google.inject.ConfigurationException; -import com.google.inject.Injector; -import com.google.inject.Key; -import com.google.inject.Provides; -import com.google.inject.ProvisionException; - -@Beta -abstract class BaseInvocationFunction implements Function { - protected final Injector injector; - protected final Function> optionalConverter; - - protected BaseInvocationFunction(Injector injector, Function> optionalConverter) { - this.injector = injector; - this.optionalConverter = optionalConverter; - } - - protected abstract Result invoke(Invocation in); - - protected abstract Function forwardInvocations(Invocation invocation, Class returnType); - - @Override - public Result apply(Invocation invocation) { - if (invocation.getInvokable().isAnnotationPresent(Provides.class)) - return Result.success(lookupValueFromGuice(invocation.getInvokable())); - else if (invocation.getInvokable().isAnnotationPresent(Delegate.class)) - return Result.success(propagateContextToDelegate(invocation)); - return invoke(invocation); - } - - private Object propagateContextToDelegate(Invocation invocation) { - Class returnType = unwrapIfOptional(invocation.getInvokable().getReturnType()); - Object result = FunctionalReflection.newProxy(returnType, forwardInvocations(invocation, returnType)); - if (isReturnTypeOptional(invocation.getInvokable())) { - result = optionalConverter.apply(InvocationSuccess.create(invocation, result)); - } - return result; - } - - static final Predicate isQualifierPresent = new Predicate() { - public boolean apply(Annotation input) { - return input.annotationType().isAnnotationPresent(Qualifier.class); - } - }; - - private Object lookupValueFromGuice(Invokable invoked) { - try { - Type genericReturnType = invoked.getReturnType().getType(); - try { - Annotation qualifier = find(ImmutableList.copyOf(invoked.getAnnotations()), isQualifierPresent); - return getInstanceOfTypeWithQualifier(genericReturnType, qualifier); - } catch (ProvisionException e) { - throw propagate(e.getCause()); - } catch (RuntimeException e) { - return instanceOfTypeOrPropagate(genericReturnType, e); - } - } catch (ProvisionException e) { - AuthorizationException aex = getFirstThrowableOfType(e, AuthorizationException.class); - if (aex != null) - throw aex; - throw e; - } - } - - Object instanceOfTypeOrPropagate(Type genericReturnType, RuntimeException e) { - try { - // look for an existing binding - Binding binding = injector.getExistingBinding(Key.get(genericReturnType)); - if (binding != null) - return binding.getProvider().get(); - - // then, try looking via supplier - binding = injector.getExistingBinding(Key.get(newParameterizedType(Supplier.class, genericReturnType))); - if (binding != null) - return Supplier.class.cast(binding.getProvider().get()).get(); - - // else try to create an instance - return injector.getInstance(Key.get(genericReturnType)); - } catch (ConfigurationException ce) { - throw e; - } - } - - Object getInstanceOfTypeWithQualifier(Type genericReturnType, Annotation qualifier) { - // look for an existing binding - Binding binding = injector.getExistingBinding(Key.get(genericReturnType, qualifier)); - if (binding != null) - return binding.getProvider().get(); - - // then, try looking via supplier - binding = injector - .getExistingBinding(Key.get(newParameterizedType(Supplier.class, genericReturnType), qualifier)); - if (binding != null) - return Supplier.class.cast(binding.getProvider().get()).get(); - - // else try to create an instance - return injector.getInstance(Key.get(genericReturnType, qualifier)); - } -} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/rest/internal/InvokeFutureAndBlock.java b/core/src/main/java/org/jclouds/rest/internal/BlockOnFuture.java similarity index 65% rename from core/src/main/java/org/jclouds/rest/internal/InvokeFutureAndBlock.java rename to core/src/main/java/org/jclouds/rest/internal/BlockOnFuture.java index 46ffdadc5d..73efb50efe 100644 --- a/core/src/main/java/org/jclouds/rest/internal/InvokeFutureAndBlock.java +++ b/core/src/main/java/org/jclouds/rest/internal/BlockOnFuture.java @@ -20,7 +20,6 @@ package org.jclouds.rest.internal; import static com.google.common.base.Optional.fromNullable; -import java.lang.reflect.InvocationTargetException; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -33,57 +32,45 @@ import javax.inject.Named; import org.jclouds.logging.Logger; import org.jclouds.reflect.Invocation; import org.jclouds.reflect.Invocation.Result; -import org.jclouds.reflect.Invokable; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; import com.google.common.base.Optional; -import com.google.common.cache.Cache; +import com.google.common.reflect.Invokable; +import com.google.common.reflect.TypeToken; import com.google.common.util.concurrent.ListenableFuture; import com.google.inject.assistedinject.Assisted; -public class InvokeFutureAndBlock implements Function { +public class BlockOnFuture implements Function, Result> { public static interface Factory { /** - * @param receiver - * object whose interface matched {@code declaring} except all invokeds return {@link ListenableFuture} - * @return blocking invocation handler + * @param invocation + * context for how the future was created */ - InvokeFutureAndBlock create(Object async); + BlockOnFuture create(TypeToken enclosingType, Invocation invocation); } @Resource private Logger logger = Logger.NULL; - private final Cache, Invokable> sync2AsyncInvokables; private final Map timeouts; - private final Object receiver; + private final TypeToken enclosingType; + private final Invocation invocation; @Inject @VisibleForTesting - InvokeFutureAndBlock(Cache, Invokable> sync2AsyncInvokables, - @Named("TIMEOUTS") Map timeouts, @Assisted Object receiver) { - this.receiver = receiver; - this.sync2AsyncInvokables = sync2AsyncInvokables; + BlockOnFuture(@Named("TIMEOUTS") Map timeouts, @Assisted TypeToken enclosingType, + @Assisted Invocation invocation) { this.timeouts = timeouts; + this.enclosingType = enclosingType; + this.invocation = invocation; } @Override - public Result apply(Invocation invocation) { - @SuppressWarnings("unchecked") - Invokable> asyncMethod = Invokable.class.cast(sync2AsyncInvokables - .getIfPresent(invocation.getInvokable())); - try { - ListenableFuture future = asyncMethod.invoke(receiver, invocation.getArgs().toArray()); - Optional timeoutNanos = timeoutInNanos(invocation.getInvokable(), timeouts); - return block(future, timeoutNanos); - } catch (InvocationTargetException e) { - return Result.fail(e); - } catch (IllegalAccessException e) { - return Result.fail(e); - } - + public Result apply(ListenableFuture future) { + Optional timeoutNanos = timeoutInNanos(invocation.getInvokable(), timeouts); + return block(future, timeoutNanos); } private Result block(ListenableFuture future, Optional timeoutNanos) { @@ -106,7 +93,7 @@ public class InvokeFutureAndBlock implements Function { // override timeout by values configured in properties(in ms) private Optional timeoutInNanos(Invokable invoked, Map timeouts) { - String className = invoked.getEnclosingType().getRawType().getSimpleName(); + String className = enclosingType.getRawType().getSimpleName(); Optional timeoutMillis = fromNullable(timeouts.get(className + "." + invoked.getName())).or( fromNullable(timeouts.get(className))).or(fromNullable(timeouts.get("default"))); if (timeoutMillis.isPresent()) diff --git a/core/src/main/java/org/jclouds/rest/internal/DelegatingInvocationFunction.java b/core/src/main/java/org/jclouds/rest/internal/DelegatingInvocationFunction.java new file mode 100644 index 0000000000..61859b84c1 --- /dev/null +++ b/core/src/main/java/org/jclouds/rest/internal/DelegatingInvocationFunction.java @@ -0,0 +1,207 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.rest.internal; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Throwables.propagate; +import static com.google.common.collect.Iterables.find; +import static com.google.inject.util.Types.newParameterizedType; +import static org.jclouds.util.Optionals2.isReturnTypeOptional; +import static org.jclouds.util.Optionals2.unwrapIfOptional; +import static org.jclouds.util.Throwables2.getFirstThrowableOfType; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.Map; + +import javax.inject.Inject; +import javax.inject.Qualifier; + +import org.jclouds.reflect.FunctionalReflection; +import org.jclouds.reflect.Invocation; +import org.jclouds.reflect.Invocation.Result; +import org.jclouds.reflect.InvocationSuccess; +import com.google.common.reflect.Invokable; +import org.jclouds.rest.AuthorizationException; +import org.jclouds.rest.annotations.Delegate; +import org.jclouds.rest.config.SetCaller; + +import com.google.common.annotations.Beta; +import com.google.common.base.Function; +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableList; +import com.google.common.reflect.TypeToken; +import com.google.inject.Binding; +import com.google.inject.ConfigurationException; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.Provides; +import com.google.inject.ProvisionException; +import com.google.inject.TypeLiteral; +import com.google.inject.util.Types; + +/** + * + * @param + * The enclosing type of the interface that a dynamic proxy like this implements + * @param + * The enclosing type that is processed by this proxy + * @param + * The function that implements this dynamic proxy + */ +@Beta +public final class DelegatingInvocationFunction> implements + Function { + private final Injector injector; + private final TypeToken enclosingType; + private final SetCaller setCaller; + private final Map, Class> syncToAsync; + private final Function> optionalConverter; + private final F methodInvoker; + + @SuppressWarnings("unchecked") + @Inject + DelegatingInvocationFunction(Injector injector, SetCaller setCaller, Map, Class> syncToAsync, + TypeLiteral enclosingType, Function> optionalConverter, F methodInvoker) { + this.injector = checkNotNull(injector, "injector"); + this.enclosingType = (TypeToken) TypeToken.of(checkNotNull(enclosingType, "enclosingType").getType()); + this.setCaller = checkNotNull(setCaller, "setCaller"); + this.syncToAsync = checkNotNull(syncToAsync, "syncToAsync"); + this.optionalConverter = checkNotNull(optionalConverter, "optionalConverter"); + this.methodInvoker = checkNotNull(methodInvoker, "methodInvoker"); + } + + @Override + public Result apply(Invocation in) { + if (in.getInvokable().isAnnotationPresent(Provides.class)) + return Result.success(lookupValueFromGuice(in.getInvokable())); + else if (in.getInvokable().isAnnotationPresent(Delegate.class)) + return Result.success(propagateContextToDelegate(in)); + return methodInvoker.apply(in); + } + + private Object propagateContextToDelegate(Invocation caller) { + Class returnType = unwrapIfOptional(caller.getInvokable().getReturnType()); + Function delegate; + setCaller.enter(enclosingType, caller); + try { + @SuppressWarnings("unchecked") + Key> delegateType = (Key>) methodInvokerFor(returnType); + delegate = injector.getInstance(delegateType); + } finally { + setCaller.exit(); + } + Object result = FunctionalReflection.newProxy(returnType, delegate); + if (isReturnTypeOptional(caller.getInvokable())) { + result = optionalConverter.apply(InvocationSuccess.create(caller, result)); + } + return result; + } + + /** + * attempts to guess the generic type params for the delegate's invocation function based on the supplied type + */ + private Key methodInvokerFor(Class returnType) { + switch (methodInvoker.getClass().getTypeParameters().length) { + case 0: + return Key.get(methodInvoker.getClass()); + case 1: + return Key.get(Types.newParameterizedType(methodInvoker.getClass(), returnType)); + case 2: + if (syncToAsync.containsValue(returnType)) + return Key.get(Types.newParameterizedType(methodInvoker.getClass(), returnType, returnType)); + return Key.get(Types.newParameterizedType( + methodInvoker.getClass(), + returnType, + checkNotNull(syncToAsync.get(returnType), "need async type of %s for %s", returnType, + methodInvoker.getClass()))); + } + throw new IllegalArgumentException(returnType + " has too many type parameters"); + } + + static final Predicate isQualifierPresent = new Predicate() { + public boolean apply(Annotation input) { + return input.annotationType().isAnnotationPresent(Qualifier.class); + } + }; + + private Object lookupValueFromGuice(Invokable invoked) { + try { + Type genericReturnType = invoked.getReturnType().getType(); + try { + Annotation qualifier = find(ImmutableList.copyOf(invoked.getAnnotations()), isQualifierPresent); + return getInstanceOfTypeWithQualifier(genericReturnType, qualifier); + } catch (ProvisionException e) { + throw propagate(e.getCause()); + } catch (RuntimeException e) { + return instanceOfTypeOrPropagate(genericReturnType, e); + } + } catch (ProvisionException e) { + AuthorizationException aex = getFirstThrowableOfType(e, AuthorizationException.class); + if (aex != null) + throw aex; + throw e; + } + } + + Object instanceOfTypeOrPropagate(Type genericReturnType, RuntimeException e) { + try { + // look for an existing binding + Binding binding = injector.getExistingBinding(Key.get(genericReturnType)); + if (binding != null) + return binding.getProvider().get(); + + // then, try looking via supplier + binding = injector.getExistingBinding(Key.get(newParameterizedType(Supplier.class, genericReturnType))); + if (binding != null) + return Supplier.class.cast(binding.getProvider().get()).get(); + + // else try to create an instance + return injector.getInstance(Key.get(genericReturnType)); + } catch (ConfigurationException ce) { + throw e; + } + } + + Object getInstanceOfTypeWithQualifier(Type genericReturnType, Annotation qualifier) { + // look for an existing binding + Binding binding = injector.getExistingBinding(Key.get(genericReturnType, qualifier)); + if (binding != null) + return binding.getProvider().get(); + + // then, try looking via supplier + binding = injector + .getExistingBinding(Key.get(newParameterizedType(Supplier.class, genericReturnType), qualifier)); + if (binding != null) + return Supplier.class.cast(binding.getProvider().get()).get(); + + // else try to create an instance + return injector.getInstance(Key.get(genericReturnType, qualifier)); + } + + @Override + public String toString() { + return Objects.toStringHelper("").omitNullValues() + .add("enclosingType", enclosingType.getRawType().getSimpleName()).add("methodInvoker", methodInvoker) + .toString(); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/rest/internal/GeneratedHttpRequest.java b/core/src/main/java/org/jclouds/rest/internal/GeneratedHttpRequest.java index 3970eb61a4..268a6c5edd 100644 --- a/core/src/main/java/org/jclouds/rest/internal/GeneratedHttpRequest.java +++ b/core/src/main/java/org/jclouds/rest/internal/GeneratedHttpRequest.java @@ -30,75 +30,101 @@ import org.jclouds.reflect.Invocation; import com.google.common.base.Optional; import com.google.common.collect.Multimap; +import com.google.common.reflect.TypeToken; /** - * Represents a request generated from annotations * - * @author Adrian Cole + * @author adriancole + * + * @param + * enclosing type of the interface parsed to generate this request. */ -public final class GeneratedHttpRequest extends HttpRequest { - public static Builder builder() { - return new Builder(); +public final class GeneratedHttpRequest extends HttpRequest { + public static Builder builder(Class enclosingType) { + return new Builder(TypeToken.of(enclosingType)); } - public Builder toBuilder() { - return new Builder().fromGeneratedHttpRequest(this); + public static Builder builder(TypeToken enclosingType) { + return new Builder(enclosingType); } - public final static class Builder extends HttpRequest.Builder { - protected Invocation invocation; - protected Optional caller = Optional.absent(); + public Builder toBuilder() { + return new Builder(enclosingType).fromGeneratedHttpRequest(this); + } + + public final static class Builder extends HttpRequest.Builder> { + private final TypeToken enclosingType; + + private Builder(TypeToken enclosingType) { + this.enclosingType = checkNotNull(enclosingType, "enclosingType"); + } + + private Invocation invocation; + private Optional> callerEnclosingType = Optional.absent(); + private Optional caller = Optional.absent(); /** * @see GeneratedHttpRequest#getInvocation() */ - public Builder invocation(Invocation invocation) { + public Builder invocation(Invocation invocation) { this.invocation = checkNotNull(invocation, "invocation"); return this; } + /** + * @see GeneratedHttpRequest#getCallerEnclosingType() + */ + public Builder callerEnclosingType(@Nullable TypeToken callerEnclosingType) { + this.callerEnclosingType = Optional.> fromNullable(callerEnclosingType); + return this; + } + /** * @see GeneratedHttpRequest#getCaller() */ - public Builder caller(@Nullable Invocation caller) { + public Builder caller(@Nullable Invocation caller) { this.caller = Optional.fromNullable(caller); return this; } - public GeneratedHttpRequest build() { - return new GeneratedHttpRequest(method, endpoint, headers.build(), payload, invocation, filters.build(), - caller); + public GeneratedHttpRequest build() { + return new GeneratedHttpRequest(method, endpoint, headers.build(), payload, filters.build(), enclosingType, + invocation, callerEnclosingType, caller); } - public Builder fromGeneratedHttpRequest(GeneratedHttpRequest in) { - return super.fromHttpRequest(in).invocation(in.invocation).caller(in.getCaller().orNull()); - } - - Invocation getInvocation() { - return invocation; - } - - Optional getCaller() { - return caller; + public Builder fromGeneratedHttpRequest(GeneratedHttpRequest in) { + return super.fromHttpRequest(in).invocation(in.invocation) + .callerEnclosingType(in.getCallerEnclosingType().orNull()).caller(in.getCaller().orNull()); } @Override - protected Builder self() { + protected Builder self() { return this; } } + private final TypeToken enclosingType; private final Invocation invocation; + private final Optional> callerEnclosingType; private final Optional caller; protected GeneratedHttpRequest(String method, URI endpoint, Multimap headers, - @Nullable Payload payload, Invocation invocation, Iterable filters, - Optional caller) { + @Nullable Payload payload, Iterable filters, TypeToken enclosingType, + Invocation invocation, Optional> callerEnclosingType, Optional caller) { super(method, endpoint, headers, payload, filters); + this.enclosingType = checkNotNull(enclosingType, "enclosingType"); this.invocation = checkNotNull(invocation, "invocation"); + this.callerEnclosingType = checkNotNull(callerEnclosingType, "callerEnclosingType"); this.caller = checkNotNull(caller, "caller"); } + /** + * different than {@link #getDeclaringClass()} when this is a member of a class it was not declared in. + */ + public TypeToken getEnclosingType() { + return enclosingType; + } + /** * what was interpreted to create this request */ @@ -106,6 +132,14 @@ public final class GeneratedHttpRequest extends HttpRequest { return invocation; } + /** + * different than {@link #getDeclaringClass()} when {@link #getCaller()} is a member of a class it was not declared + * in. + */ + public Optional> getCallerEnclosingType() { + return callerEnclosingType; + } + public Optional getCaller() { return caller; } diff --git a/core/src/main/java/org/jclouds/rest/internal/GetAcceptHeaders.java b/core/src/main/java/org/jclouds/rest/internal/GetAcceptHeaders.java new file mode 100644 index 0000000000..33195df9f7 --- /dev/null +++ b/core/src/main/java/org/jclouds/rest/internal/GetAcceptHeaders.java @@ -0,0 +1,48 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.rest.internal; + +import java.util.Set; + +import javax.ws.rs.Consumes; + +import org.jclouds.reflect.Invocation; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableSet; +import com.google.inject.Inject; +import com.google.inject.TypeLiteral; + +class GetAcceptHeaders implements Function> { + private Class enclosingType; + + @SuppressWarnings("unchecked") + @Inject + GetAcceptHeaders(TypeLiteral enclosingType) { + this.enclosingType = (Class) enclosingType.getRawType(); + } + + @Override + public Set apply(Invocation invocation) { + Optional accept = Optional.fromNullable(invocation.getInvokable().getAnnotation(Consumes.class)).or( + Optional.fromNullable(enclosingType.getAnnotation(Consumes.class))); + return (accept.isPresent()) ? ImmutableSet.copyOf(accept.get().value()) : ImmutableSet. of(); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/jclouds/rest/internal/InvokeAndCallGetOnFutures.java b/core/src/main/java/org/jclouds/rest/internal/InvokeAndCallGetOnFutures.java new file mode 100644 index 0000000000..53a98cfe90 --- /dev/null +++ b/core/src/main/java/org/jclouds/rest/internal/InvokeAndCallGetOnFutures.java @@ -0,0 +1,91 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.rest.internal; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.lang.reflect.InvocationTargetException; + +import javax.annotation.Resource; +import javax.inject.Inject; + +import org.jclouds.logging.Logger; +import org.jclouds.reflect.Invocation; +import org.jclouds.reflect.Invocation.Result; +import com.google.common.reflect.Invokable; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Function; +import com.google.common.cache.Cache; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; + +/** + * + * @author Adrian Cole + */ +public final class InvokeAndCallGetOnFutures implements Function { + + @Resource + private Logger logger = Logger.NULL; + + private final Cache, Invokable> sync2AsyncInvokables; + private final R receiver; + + /** + * @param receiver + * will have any methods that return {@link ListenableFuture} unwrapped. + * @return blocking invocation handler + */ + @Inject + @VisibleForTesting + InvokeAndCallGetOnFutures(Cache, Invokable> sync2AsyncInvokables, R receiver) { + this.sync2AsyncInvokables = sync2AsyncInvokables; + this.receiver = receiver; + } + + @SuppressWarnings("unchecked") + @Override + public Result apply(Invocation in) { + @SuppressWarnings("rawtypes") + Invokable target = checkNotNull(sync2AsyncInvokables.getIfPresent(in.getInvokable()), "invokable %s not in %s", + in.getInvokable(), sync2AsyncInvokables); + Object returnVal; + try { + returnVal = target.invoke(receiver, in.getArgs().toArray()); + } catch (InvocationTargetException e) { + return Result.fail(e); + } catch (IllegalAccessException e) { + return Result.fail(e); + } + if (!isFuture(target)) + return Result.success(returnVal); + return Result.success(Futures.getUnchecked(ListenableFuture.class.cast(returnVal))); + } + + private boolean isFuture(Invokable target) { + return target.getReturnType().getRawType().isAssignableFrom(ListenableFuture.class); + } + + @Override + public String toString() { + return String.format("InvokeAndCallGetOnFutures(%s)", receiver); + } + +} diff --git a/core/src/main/java/org/jclouds/rest/internal/InvokeAsyncApi.java b/core/src/main/java/org/jclouds/rest/internal/InvokeAsyncApi.java deleted file mode 100644 index 4686085854..0000000000 --- a/core/src/main/java/org/jclouds/rest/internal/InvokeAsyncApi.java +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.jclouds.rest.internal; - -import static com.google.common.base.Preconditions.checkState; - -import javax.annotation.Resource; -import javax.inject.Inject; -import javax.inject.Singleton; - -import org.jclouds.logging.Logger; -import org.jclouds.reflect.Invocation; -import org.jclouds.reflect.Invocation.Result; -import org.jclouds.reflect.InvocationSuccess; -import org.jclouds.reflect.Invokable; - -import com.google.common.base.Function; -import com.google.common.base.Optional; -import com.google.common.base.Predicate; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.inject.Injector; -import com.google.inject.Provides; -import com.google.inject.assistedinject.Assisted; - -/** - * Generates RESTful clients from appropriately annotated interfaces. - *

- * Particularly, this code delegates calls to other things. - *

    - *
  1. if the invoked has a {@link Provides} annotation, it responds via a {@link Injector} lookup
  2. - *
  3. if the invoked has a {@link Delegate} annotation, it responds with an instance of interface set in returnVal, - * adding the current JAXrs annotations to whatever are on that class.
  4. - *
      - *
    • ex. if the invoked with {@link Delegate} has a {@code Path} annotation, and the returnval interface also has - * {@code Path}, these values are combined.
    • - *
    - *
  5. if {@link RestAnnotationProcessor#delegationMap} contains a mapping for this, and the returnVal is properly - * assigned as a {@link ListenableFuture}, it responds with an http implementation.
  6. - *
  7. otherwise a RuntimeException is thrown with a message including: - * {@code invoked is intended solely to set constants}
  8. - *
- * - * @author Adrian Cole - */ -@Singleton -public class InvokeAsyncApi extends BaseInvocationFunction { - - public final static class Delegate extends InvokeAsyncApi { - - public static interface Factory { - Delegate caller(Invocation caller); - } - - private final String string; - - @Inject - private Delegate(Injector injector, Function> optionalConverter, - Predicate> mapsToAsyncHttpRequest, - InvokeListenableFutureViaHttp.Caller.Factory httpCallerFactory, Delegate.Factory factory, - @Assisted Invocation caller) { - super(injector, optionalConverter, mapsToAsyncHttpRequest, httpCallerFactory.caller(caller), factory); - this.string = String.format("%s->%s", caller, caller.getInvokable().getReturnType().getRawType() - .getSimpleName()); - } - - @Override - public String toString() { - return string; - } - } - - @Resource - private Logger logger = Logger.NULL; - - private final Predicate> mapsToAsyncHttpRequest; - private final Function> invokeMethod; - private final Delegate.Factory factory; - - @Inject - private InvokeAsyncApi(Injector injector, Function> optionalConverter, - Predicate> mapsToAsyncHttpRequest, Function> invokeMethod, - Delegate.Factory factory) { - super(injector, optionalConverter); - this.mapsToAsyncHttpRequest = mapsToAsyncHttpRequest; - this.invokeMethod = invokeMethod; - this.factory = factory; - } - - @Override - protected Result invoke(Invocation invocation) { - checkState(mapsToAsyncHttpRequest.apply(invocation.getInvokable()), - "please configure corresponding async class for %s in your RestClientModule", invocation.getInvokable()); - return Result.success(invokeMethod.apply(invocation)); - } - - @Override - protected Function forwardInvocations(Invocation invocation, Class returnType) { - return factory.caller(invocation); - } - - @Override - public String toString() { - return String.format("async->http"); - } - -} diff --git a/core/src/main/java/org/jclouds/rest/internal/InvokeListenableFutureViaHttp.java b/core/src/main/java/org/jclouds/rest/internal/InvokeHttpMethod.java similarity index 66% rename from core/src/main/java/org/jclouds/rest/internal/InvokeListenableFutureViaHttp.java rename to core/src/main/java/org/jclouds/rest/internal/InvokeHttpMethod.java index b73f4cd5a7..73f49e48fd 100644 --- a/core/src/main/java/org/jclouds/rest/internal/InvokeListenableFutureViaHttp.java +++ b/core/src/main/java/org/jclouds/rest/internal/InvokeHttpMethod.java @@ -19,6 +19,8 @@ package org.jclouds.rest.internal; import static com.google.common.base.Objects.equal; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; import static com.google.common.util.concurrent.Futures.transform; import static com.google.common.util.concurrent.Futures.withFallback; import static org.jclouds.concurrent.Futures.makeListenable; @@ -28,7 +30,6 @@ import java.util.concurrent.ExecutorService; import javax.annotation.Resource; import javax.inject.Inject; import javax.inject.Named; -import javax.inject.Singleton; import org.jclouds.Constants; import org.jclouds.fallbacks.MapHttp4xxCodesToExceptions; @@ -37,55 +38,50 @@ import org.jclouds.http.HttpCommandExecutorService; import org.jclouds.http.HttpResponse; import org.jclouds.logging.Logger; import org.jclouds.reflect.Invocation; -import org.jclouds.reflect.Invokable; +import org.jclouds.reflect.Invocation.Result; import org.jclouds.rest.InvocationContext; import org.jclouds.rest.annotations.Fallback; import com.google.common.base.Function; import com.google.common.base.Objects; +import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import com.google.common.reflect.Invokable; +import com.google.common.reflect.TypeToken; import com.google.common.util.concurrent.FutureFallback; import com.google.common.util.concurrent.ListenableFuture; import com.google.inject.Injector; -import com.google.inject.assistedinject.Assisted; +import com.google.inject.TypeLiteral; -@Singleton -public class InvokeListenableFutureViaHttp implements Function> { - - public final static class Caller extends InvokeListenableFutureViaHttp { - - public static interface Factory { - Caller caller(Invocation caller); - } - - @Inject - private Caller(Injector injector, RestAnnotationProcessor annotationProcessor, HttpCommandExecutorService http, - Function> transformerForRequest, - @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads, @Assisted Invocation caller) { - super(injector, annotationProcessor.caller(caller), http, transformerForRequest, userThreads); - } - } +public class InvokeHttpMethod implements Function { @Resource private Logger logger = Logger.NULL; private final Injector injector; - private final RestAnnotationProcessor annotationProcessor; + private final TypeToken
enclosingType; + private final Cache, Invokable> sync2AsyncInvokables; + private final RestAnnotationProcessor annotationProcessor; private final HttpCommandExecutorService http; - private final Function> transformerForRequest; + private final TransformerForRequest transformerForRequest; private final ExecutorService userThreads; + private final BlockOnFuture.Factory blocker; + @SuppressWarnings("unchecked") @Inject - private InvokeListenableFutureViaHttp(Injector injector, RestAnnotationProcessor annotationProcessor, - HttpCommandExecutorService http, - Function> transformerForRequest, - @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads) { + private InvokeHttpMethod(Injector injector, TypeLiteral enclosingType, + Cache, Invokable> sync2AsyncInvokables, RestAnnotationProcessor annotationProcessor, + HttpCommandExecutorService http, TransformerForRequest transformerForRequest, + @Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads, BlockOnFuture.Factory blocker) { this.injector = injector; + this.enclosingType = (TypeToken) TypeToken.of(enclosingType.getType()); + this.sync2AsyncInvokables = sync2AsyncInvokables; this.annotationProcessor = annotationProcessor; this.http = http; this.userThreads = userThreads; + this.blocker = blocker; this.transformerForRequest = transformerForRequest; } @@ -104,18 +100,34 @@ public class InvokeListenableFutureViaHttp implements Function apply(Invocation invocation) { + public Result apply(Invocation in) { + if (isFuture(in.getInvokable())) { + return Result.success(createFuture(in)); + } + @SuppressWarnings("rawtypes") + Invokable async = checkNotNull(sync2AsyncInvokables.getIfPresent(in.getInvokable()), "invokable %s not in %s", + in.getInvokable(), sync2AsyncInvokables); + checkState(isFuture(async), "not a future: %s", async); + return blocker.create(enclosingType, in).apply(createFuture(Invocation.create(async, in.getArgs()))); + } + + private boolean isFuture(Invokable in) { + return in.getReturnType().getRawType().equals(ListenableFuture.class); + } + + public ListenableFuture createFuture(Invocation invocation) { String name = invocation.getInvokable().toString(); logger.trace(">> converting %s", name); - GeneratedHttpRequest request = annotationProcessor.apply(invocation); + GeneratedHttpRequest request = annotationProcessor.apply(invocation); logger.trace("<< converted %s to %s", name, request.getRequestLine()); Function transformer = transformerForRequest.apply(request); logger.trace("<< response from %s is parsed by %s", name, transformer.getClass().getSimpleName()); logger.debug(">> invoking %s", name); - ListenableFuture result = transform(makeListenable(http.submit(new HttpCommand(request)), userThreads), transformer); - + ListenableFuture result = transform(makeListenable(http.submit(new HttpCommand(request)), userThreads), + transformer); + FutureFallback fallback = fallbacks.getUnchecked(invocation.getInvokable()); if (fallback instanceof InvocationContext) { InvocationContext.class.cast(fallback).setContext(request); @@ -130,7 +142,7 @@ public class InvokeListenableFutureViaHttp implements Function that = InvokeHttpMethod.class.cast(o); return equal(this.annotationProcessor, that.annotationProcessor); } diff --git a/core/src/main/java/org/jclouds/rest/internal/InvokeSyncApi.java b/core/src/main/java/org/jclouds/rest/internal/InvokeSyncApi.java deleted file mode 100644 index aed156243f..0000000000 --- a/core/src/main/java/org/jclouds/rest/internal/InvokeSyncApi.java +++ /dev/null @@ -1,123 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.jclouds.rest.internal; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -import java.lang.reflect.InvocationTargetException; -import java.util.Map; - -import javax.annotation.Resource; -import javax.inject.Inject; - -import org.jclouds.logging.Logger; -import org.jclouds.reflect.FunctionalReflection; -import org.jclouds.reflect.Invocation; -import org.jclouds.reflect.Invocation.Result; -import org.jclouds.reflect.InvocationSuccess; -import org.jclouds.reflect.Invokable; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Function; -import com.google.common.base.Optional; -import com.google.common.cache.Cache; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.inject.Injector; -import com.google.inject.assistedinject.Assisted; - -/** - * - * @author Adrian Cole - */ -public final class InvokeSyncApi extends BaseInvocationFunction { - - public static interface Factory { - /** - * @param receiver - * object whose interface matched {@code declaring} except all invokeds return {@link ListenableFuture} - * @return blocking invocation handler - */ - InvokeSyncApi create(Object receiver); - } - - @Resource - private Logger logger = Logger.NULL; - - private final InvokeSyncApi.Factory factory; - private final InvokeAsyncApi.Delegate.Factory asyncFactory; - private final Map, Class> sync2Async; - private final Cache, Invokable> sync2AsyncInvokables; - private final InvokeFutureAndBlock.Factory blocker; - private final Object receiver; - - @Inject - @VisibleForTesting - InvokeSyncApi(Injector injector, Function> optionalConverter, - InvokeSyncApi.Factory factory, InvokeAsyncApi.Delegate.Factory asyncFactory, - Map, Class> sync2Async, Cache, Invokable> sync2AsyncInvokables, - InvokeFutureAndBlock.Factory blocker, @Assisted Object receiver) { - super(injector, optionalConverter); - this.factory = factory; - this.asyncFactory = asyncFactory; - this.sync2Async = sync2Async; - this.sync2AsyncInvokables = sync2AsyncInvokables; - this.blocker = blocker; - this.receiver = receiver; - } - - @SuppressWarnings("unchecked") - @Override - protected Result invoke(Invocation in) { - @SuppressWarnings("rawtypes") - Invokable async = checkNotNull(sync2AsyncInvokables.getIfPresent(in.getInvokable()), "invokable %s not in %s", - in.getInvokable(), sync2AsyncInvokables); - if (async.getReturnType().getRawType().isAssignableFrom(ListenableFuture.class)) { - return blocker.create(receiver).apply(in); - } - try { // try any method - return Result.success(async.invoke(receiver, in.getArgs().toArray())); - } catch (InvocationTargetException e) { - return Result.fail(e); - } catch (IllegalAccessException e) { - return Result.fail(e); - } - } - - @Override - protected Function forwardInvocations(Invocation invocation, Class returnType) { - // get the return type of the asynchronous class associated with this client - // ex. FloatingIPClient is associated with FloatingIPAsyncClient - Class asyncClass = sync2Async.get(returnType); - checkState(asyncClass != null, "please configure corresponding async class for %s in your RestClientModule", - returnType); - // pass any parameters necessary to get a relevant instance of that async class - // ex. getClientForRegion("north") might return an instance whose endpoint is - // different that "south" - Object asyncProxy = FunctionalReflection.newProxy(asyncClass, asyncFactory.caller(invocation)); - checkState(asyncProxy != null, "configuration error, sync client for " + invocation + " not found"); - return factory.create(asyncProxy); - } - - @Override - public String toString() { - return String.format("syncProxy(%s)", receiver); - } - -} diff --git a/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java b/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java index 1847420d3b..e1c2cdecca 100644 --- a/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java +++ b/core/src/main/java/org/jclouds/rest/internal/RestAnnotationProcessor.java @@ -54,7 +54,7 @@ import java.util.NoSuchElementException; import java.util.Set; import javax.annotation.Resource; -import javax.ws.rs.Consumes; +import javax.inject.Named; import javax.ws.rs.FormParam; import javax.ws.rs.HeaderParam; import javax.ws.rs.Path; @@ -78,8 +78,8 @@ import org.jclouds.io.payloads.Part.PartOptions; import org.jclouds.javax.annotation.Nullable; import org.jclouds.logging.Logger; import org.jclouds.reflect.Invocation; -import org.jclouds.reflect.Invokable; -import org.jclouds.reflect.Parameter; +import com.google.common.reflect.Invokable; +import com.google.common.reflect.Parameter; import org.jclouds.rest.Binder; import org.jclouds.rest.InputParamValidator; import org.jclouds.rest.annotations.ApiVersion; @@ -105,6 +105,7 @@ import org.jclouds.rest.binders.BindToJsonPayloadWrappedWith; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; +import com.google.common.base.Objects; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.base.Supplier; @@ -121,17 +122,19 @@ import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.primitives.Chars; +import com.google.common.reflect.TypeToken; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.TypeLiteral; /** - * Creates http invocation.getInvoked()s based on annotations on a class or interface. * - * @author Adrian Cole + * @author adriancole + * + * @param */ -public class RestAnnotationProcessor implements Function { +public class RestAnnotationProcessor implements Function> { @Resource protected Logger logger = Logger.NULL; @@ -149,16 +152,27 @@ public class RestAnnotationProcessor implements Function getAcceptHeaders; + private final TypeToken enclosingType; + private final TypeToken callerEnclosingType; + private final Invocation caller; + @SuppressWarnings("unchecked") @Inject private RestAnnotationProcessor(Injector injector, @ApiVersion String apiVersion, @BuildVersion String buildVersion, - HttpUtils utils, ContentMetadataCodec contentMetadataCodec, InputParamValidator inputParamValidator) { + HttpUtils utils, ContentMetadataCodec contentMetadataCodec, InputParamValidator inputParamValidator, + GetAcceptHeaders getAcceptHeaders, TypeLiteral enclosingType, + @Nullable @Named("caller") TypeToken callerEnclosingType, @Nullable @Named("caller") Invocation caller) { this.injector = injector; this.utils = utils; this.contentMetadataCodec = contentMetadataCodec; this.apiVersion = apiVersion; this.buildVersion = buildVersion; this.inputParamValidator = inputParamValidator; + this.getAcceptHeaders = getAcceptHeaders; + this.enclosingType = (TypeToken) TypeToken.of(enclosingType.getType()); + this.callerEnclosingType = callerEnclosingType; + this.caller = caller; } /** @@ -166,19 +180,12 @@ public class RestAnnotationProcessor implements Function invokable, List args) { + public GeneratedHttpRequest createRequest(Invokable invokable, List args) { return apply(Invocation.create(invokable, args)); } - - private Invocation caller; - - RestAnnotationProcessor caller(Invocation caller) { - this.caller = caller; - return this; - } @Override - public GeneratedHttpRequest apply(Invocation invocation) { + public GeneratedHttpRequest apply(Invocation invocation) { checkNotNull(invocation, "invocation"); inputParamValidator.validateMethodParametersOrThrow(invocation); @@ -188,27 +195,27 @@ public class RestAnnotationProcessor implements Function requestBuilder = GeneratedHttpRequest.builder(enclosingType) + .invocation(invocation).callerEnclosingType(callerEnclosingType).caller(caller); if (r != null) { requestBuilder.fromHttpRequest(r); } else { requestBuilder.method(tryFindHttpMethod(invocation.getInvokable()).get()); } - requestBuilder.invocation(invocation).filters(getFiltersIfAnnotated(invocation)); + requestBuilder.filters(getFiltersIfAnnotated(invocation)); Multimap tokenValues = LinkedHashMultimap.create(); @@ -220,8 +227,8 @@ public class RestAnnotationProcessor implements Function formParams = addFormParams(tokenValues, invocation); Multimap queryParams = addQueryParams(tokenValues, invocation); @@ -291,7 +298,7 @@ public class RestAnnotationProcessor implements Function request = requestBuilder.build(); org.jclouds.rest.MapBinder mapBinder = getMapPayloadBinderOrNull(invocation); if (mapBinder != null) { @@ -312,7 +319,7 @@ public class RestAnnotationProcessor implements Function T findOrNull(Iterable args, Class clazz) { + private static A findOrNull(Iterable args, Class clazz) { return clazz.cast(tryFind(args, instanceOf(clazz)).orNull()); } @@ -324,14 +331,10 @@ public class RestAnnotationProcessor implements Function findEndpoint(Invocation invocation) { - Optional endpoint = getEndpointFor(invocation); + Optional endpoint = getEndpointFor(enclosingType, invocation); if (endpoint.isPresent()) logger.trace("using endpoint %s for %s", endpoint, invocation); if (!endpoint.isPresent()) { @@ -363,10 +366,10 @@ public class RestAnnotationProcessor implements Function addPathAndGetTokens(Invocation invocation, UriBuilder uriBuilder) { - if (invocation.getInvokable().getEnclosingType().getRawType().isAnnotationPresent(Path.class)) - uriBuilder.appendPath(invocation.getInvokable().getEnclosingType().getRawType().getAnnotation(Path.class) - .value()); + private Multimap addPathAndGetTokens(TypeToken enclosingType, Invocation invocation, + UriBuilder uriBuilder) { + if (enclosingType.getRawType().isAnnotationPresent(Path.class)) + uriBuilder.appendPath(enclosingType.getRawType().getAnnotation(Path.class).value()); if (invocation.getInvokable().isAnnotationPresent(Path.class)) uriBuilder.appendPath(invocation.getInvokable().getAnnotation(Path.class).value()); return getPathParamKeyValues(invocation); @@ -374,8 +377,8 @@ public class RestAnnotationProcessor implements Function addFormParams(Multimap tokenValues, Invocation invocation) { Multimap formMap = LinkedListMultimap.create(); - if (invocation.getInvokable().getEnclosingType().getRawType().isAnnotationPresent(FormParams.class)) { - FormParams form = invocation.getInvokable().getEnclosingType().getRawType().getAnnotation(FormParams.class); + if (enclosingType.getRawType().isAnnotationPresent(FormParams.class)) { + FormParams form = enclosingType.getRawType().getAnnotation(FormParams.class); addForm(formMap, form, tokenValues); } @@ -392,8 +395,8 @@ public class RestAnnotationProcessor implements Function addQueryParams(Multimap tokenValues, Invocation invocation) { Multimap queryMap = LinkedListMultimap.create(); - if (invocation.getInvokable().getEnclosingType().getRawType().isAnnotationPresent(QueryParams.class)) { - QueryParams query = invocation.getInvokable().getEnclosingType().getRawType().getAnnotation(QueryParams.class); + if (enclosingType.getRawType().isAnnotationPresent(QueryParams.class)) { + QueryParams query = enclosingType.getRawType().getAnnotation(QueryParams.class); addQuery(queryMap, query, tokenValues); } @@ -443,13 +446,12 @@ public class RestAnnotationProcessor implements Function getFiltersIfAnnotated(Invocation invocation) { List filters = newArrayList(); - if (invocation.getInvokable().getEnclosingType().getRawType().isAnnotationPresent(RequestFilters.class)) { - for (Class clazz : invocation.getInvokable().getEnclosingType().getRawType() - .getAnnotation(RequestFilters.class).value()) { + if (enclosingType.getRawType().isAnnotationPresent(RequestFilters.class)) { + for (Class clazz : enclosingType.getRawType().getAnnotation(RequestFilters.class) + .value()) { HttpRequestFilter instance = injector.getInstance(clazz); filters.add(instance); - logger.trace("adding filter %s from annotation on %s", instance, invocation.getInvokable() - .getEnclosingType().getRawType().getName()); + logger.trace("adding filter %s from annotation on %s", instance, enclosingType.getRawType().getName()); } } if (invocation.getInvokable().isAnnotationPresent(RequestFilters.class)) { @@ -498,14 +500,14 @@ public class RestAnnotationProcessor implements Function> uriSupplierLiteral = new TypeLiteral>() { }; - protected Optional getEndpointFor(Invocation invocation) { + protected Optional getEndpointFor(TypeToken enclosingType, Invocation invocation) { URI endpoint = getEndpointInParametersOrNull(invocation, injector); if (endpoint == null) { Endpoint annotation; if (invocation.getInvokable().isAnnotationPresent(Endpoint.class)) { annotation = invocation.getInvokable().getAnnotation(Endpoint.class); - } else if (invocation.getInvokable().getEnclosingType().getRawType().isAnnotationPresent(Endpoint.class)) { - annotation = invocation.getInvokable().getEnclosingType().getRawType().getAnnotation(Endpoint.class); + } else if (enclosingType.getRawType().isAnnotationPresent(Endpoint.class)) { + annotation = enclosingType.getRawType().getAnnotation(Endpoint.class); } else { logger.trace("no annotations on class or invocation.getInvoked(): %s", invocation.getInvokable()); return Optional.absent(); @@ -565,11 +567,11 @@ public class RestAnnotationProcessor implements Function decorateRequest(GeneratedHttpRequest request) throws NegativeArraySizeException { Invocation invocation = request.getInvocation(); List args = request.getInvocation().getArgs(); Set binderOrWrapWith = ImmutableSet.copyOf(concat( @@ -588,14 +590,14 @@ public class RestAnnotationProcessor implements Function= position + 1 && arg != null) { Class parameterType = entry.getType().getRawType(); Class argType = arg.getClass(); - if (!argType.isArray() && parameterType.isArray() && invocation.getInvokable().isVarArgs()) { + if (!argType.isArray() && parameterType.isArray()) {// TODO: && invocation.getInvokable().isVarArgs()) { int arrayLength = args.size() - invocation.getInvokable().getParameters().size() + 1; if (arrayLength == 0) break OUTER; arg = (Object[]) Array.newInstance(arg.getClass(), arrayLength); System.arraycopy(args.toArray(), position, arg, 0, arrayLength); shouldBreak = true; - } else if (argType.isArray() && parameterType.isArray() && invocation.getInvokable().isVarArgs()) { + } else if (argType.isArray() && parameterType.isArray()){// TODO: && invocation.getInvokable().isVarArgs()) { } else { if (arg.getClass().isArray()) { Object[] payloadArray = (Object[]) arg; @@ -608,8 +610,7 @@ public class RestAnnotationProcessor implements Function type = param.getType().getRawType(); if (HttpRequestOptions.class.isAssignableFrom(type) || HttpRequestOptions[].class.isAssignableFrom(type)) - toReturn.add(param.getPosition()); + toReturn.add(param.hashCode()); } return toReturn.build(); } @@ -663,7 +664,7 @@ public class RestAnnotationProcessor implements Function headers, Invocation invocation) { - Set accept = getAcceptHeaders(invocation); + private void addConsumesIfPresentOnTypeOrMethod(Multimap headers, Invocation invocation) { + Set accept = getAcceptHeaders.apply(invocation); if (!accept.isEmpty()) headers.replaceValues(ACCEPT, accept); } - // TODO: refactor this out - static Set getAcceptHeaders(Invocation invocation) { - Optional accept = Optional.fromNullable(invocation.getInvokable().getAnnotation(Consumes.class)).or( - Optional.fromNullable(invocation.getInvokable().getEnclosingType().getRawType() - .getAnnotation(Consumes.class))); - return (accept.isPresent()) ? ImmutableSet.copyOf(accept.get().value()) : ImmutableSet. of(); - } - - private static void addProducesIfPresentOnTypeOrMethod(Multimap headers, Invocation invocation) { - if (invocation.getInvokable().getEnclosingType().getRawType().isAnnotationPresent(Produces.class)) { - Produces header = invocation.getInvokable().getEnclosingType().getRawType().getAnnotation(Produces.class); + private void addProducesIfPresentOnTypeOrMethod(Multimap headers, Invocation invocation) { + if (enclosingType.getRawType().isAnnotationPresent(Produces.class)) { + Produces header = enclosingType.getRawType().getAnnotation(Produces.class); headers.replaceValues(CONTENT_TYPE, asList(header.value())); } if (invocation.getInvokable().isAnnotationPresent(Produces.class)) { @@ -697,10 +690,10 @@ public class RestAnnotationProcessor implements Function headers, Invocation invocation, + private void addHeaderIfAnnotationPresentOnMethod(Multimap headers, Invocation invocation, Multimap tokenValues) { - if (invocation.getInvokable().getEnclosingType().getRawType().isAnnotationPresent(Headers.class)) { - Headers header = invocation.getInvokable().getEnclosingType().getRawType().getAnnotation(Headers.class); + if (enclosingType.getRawType().isAnnotationPresent(Headers.class)) { + Headers header = enclosingType.getRawType().getAnnotation(Headers.class); addHeader(headers, header, tokenValues); } if (invocation.getInvokable().isAnnotationPresent(Headers.class)) { @@ -726,7 +719,7 @@ public class RestAnnotationProcessor implements Function paramValue = getParamValue(invocation, param.getAnnotation(ParamParser.class), - param.getPosition(), paramKey); + param.hashCode(), paramKey); if (paramValue.isPresent()) pathParamValues.put(paramKey, paramValue.get().toString()); } @@ -757,10 +750,10 @@ public class RestAnnotationProcessor implements Function paramValue = getParamValue(invocation, param.getAnnotation(ParamParser.class), - param.getPosition(), paramKey); + param.hashCode(), paramKey); if (paramValue.isPresent()) formParamValues.put(paramKey, paramValue.get().toString()); } @@ -783,7 +776,7 @@ public class RestAnnotationProcessor implements Function paramValue = getParamValue(invocation, param.getAnnotation(ParamParser.class), - param.getPosition(), paramKey); + param.hashCode(), paramKey); if (paramValue.isPresent()) if (paramValue.get() instanceof Iterable) { @SuppressWarnings("unchecked") @@ -802,10 +795,21 @@ public class RestAnnotationProcessor implements Function paramValue = getParamValue(invocation, param.getAnnotation(ParamParser.class), - param.getPosition(), paramKey); + param.hashCode(), paramKey); if (paramValue.isPresent()) payloadParamValues.put(paramKey, paramValue.get()); } return payloadParamValues; } + + @Override + public String toString() { + String callerString = null; + if (callerEnclosingType != null) { + callerString = String.format("%s.%s%s", callerEnclosingType.getRawType().getSimpleName(), caller + .getInvokable().getName(), caller.getArgs()); + } + return Objects.toStringHelper("").omitNullValues().add("caller", callerString) + .add("enclosingType", enclosingType.getRawType().getSimpleName()).toString(); + } } diff --git a/core/src/main/java/org/jclouds/rest/internal/TransformerForRequest.java b/core/src/main/java/org/jclouds/rest/internal/TransformerForRequest.java index acf3bbfdb2..af7de21ca7 100644 --- a/core/src/main/java/org/jclouds/rest/internal/TransformerForRequest.java +++ b/core/src/main/java/org/jclouds/rest/internal/TransformerForRequest.java @@ -50,7 +50,7 @@ import org.jclouds.http.functions.ReturnTrueIf2xx; import org.jclouds.http.functions.UnwrapOnlyJsonValue; import org.jclouds.json.internal.GsonWrapper; import org.jclouds.reflect.Invocation; -import org.jclouds.reflect.Invokable; +import com.google.common.reflect.Invokable; import org.jclouds.rest.InvocationContext; import org.jclouds.rest.annotations.JAXBResponseParser; import org.jclouds.rest.annotations.OnlyElement; @@ -62,6 +62,7 @@ import org.jclouds.rest.annotations.XMLResponseParser; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Function; +import com.google.common.base.Objects; import com.google.common.base.Optional; import com.google.common.reflect.TypeToken; import com.google.common.util.concurrent.ListenableFuture; @@ -69,19 +70,45 @@ import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.TypeLiteral; -public class TransformerForRequest implements Function> { +public class TransformerForRequest implements Function, Function> { private final ParseSax.Factory parserFactory; private final Injector injector; + private final GetAcceptHeaders getAcceptHeaders; + private final Class enclosingType; + @SuppressWarnings("unchecked") @Inject - TransformerForRequest(Injector injector, Factory parserFactory) { + TransformerForRequest(Injector injector, Factory parserFactory, GetAcceptHeaders getAcceptHeaders, + TypeLiteral enclosingType) { this.injector = injector; this.parserFactory = parserFactory; + this.getAcceptHeaders = getAcceptHeaders; + this.enclosingType = (Class) enclosingType.getRawType(); } + @SuppressWarnings("unchecked") @Override - public Function apply(GeneratedHttpRequest request) { - return createResponseParser(parserFactory, injector, request); + public Function apply(GeneratedHttpRequest request) { + Function transformer; + Class> handler = TransformerForRequest.getSaxResponseParserClassOrNull(request + .getInvocation().getInvokable()); + if (handler != null) { + transformer = parserFactory.create(injector.getInstance(handler)); + } else { + transformer = getTransformerForMethod(request.getInvocation(), injector); + } + if (transformer instanceof InvocationContext) { + ((InvocationContext) transformer).setContext(request); + } + if (request.getInvocation().getInvokable().isAnnotationPresent(Transform.class)) { + Function wrappingTransformer = injector.getInstance(request.getInvocation().getInvokable() + .getAnnotation(Transform.class).value()); + if (wrappingTransformer instanceof InvocationContext) { + ((InvocationContext) wrappingTransformer).setContext(request); + } + transformer = compose(Function.class.cast(wrappingTransformer), transformer); + } + return transformer; } private static final TypeToken> futureBooleanLiteral = new TypeToken>() { @@ -105,8 +132,9 @@ public class TransformerForRequest implements Function> getParserOrThrowException(Invocation invocation) { + protected Key> getParserOrThrowException(Invocation invocation) { Invokable invoked = invocation.getInvokable(); + Set acceptHeaders = getAcceptHeaders.apply(invocation); ResponseParser annotation = invoked.getAnnotation(ResponseParser.class); if (annotation == null) { if (invoked.getReturnType().equals(void.class) || invoked.getReturnType().equals(futureVoidLiteral)) { @@ -120,10 +148,9 @@ public class TransformerForRequest implements Function getTransformerForMethod(Invocation invocation, Injector injector) { + public Function getTransformerForMethod(Invocation invocation, Injector injector) { Invokable invoked = invocation.getInvokable(); Function transformer; if (invoked.isAnnotationPresent(SelectJson.class)) { @@ -193,32 +220,6 @@ public class TransformerForRequest implements Function createResponseParser(ParseSax.Factory parserFactory, Injector injector, - GeneratedHttpRequest request) { - Function transformer; - Class> handler = TransformerForRequest.getSaxResponseParserClassOrNull(request - .getInvocation().getInvokable()); - if (handler != null) { - transformer = parserFactory.create(injector.getInstance(handler)); - } else { - transformer = getTransformerForMethod(request.getInvocation(), injector); - } - if (transformer instanceof InvocationContext) { - ((InvocationContext) transformer).setContext(request); - } - if (request.getInvocation().getInvokable().isAnnotationPresent(Transform.class)) { - Function wrappingTransformer = injector.getInstance(request.getInvocation().getInvokable() - .getAnnotation(Transform.class).value()); - if (wrappingTransformer instanceof InvocationContext) { - ((InvocationContext) wrappingTransformer).setContext(request); - } - transformer = compose(Function.class.cast(wrappingTransformer), transformer); - } - return transformer; - } - static Class> getSaxResponseParserClassOrNull(Invokable invoked) { XMLResponseParser annotation = invoked.getAnnotation(XMLResponseParser.class); if (annotation != null) { @@ -226,4 +227,9 @@ public class TransformerForRequest implements Function args) { - return GeneratedHttpRequest.builder().method("POST").endpoint("http://localhost/key") + return GeneratedHttpRequest.builder(TypeToken.of(String.class)).method("POST").endpoint("http://localhost/key") .invocation(Invocation.create(toString.getInvokable(), args)).build(); } } diff --git a/core/src/test/java/org/jclouds/http/handlers/BackoffLimitedRetryHandlerTest.java b/core/src/test/java/org/jclouds/http/handlers/BackoffLimitedRetryHandlerTest.java index a3c5fca4bb..38dce3d7ad 100644 --- a/core/src/test/java/org/jclouds/http/handlers/BackoffLimitedRetryHandlerTest.java +++ b/core/src/test/java/org/jclouds/http/handlers/BackoffLimitedRetryHandlerTest.java @@ -44,13 +44,15 @@ import org.jclouds.http.internal.JavaUrlHttpCommandExecutorService; import org.jclouds.io.ContentMetadataCodec; import org.jclouds.io.ContentMetadataCodec.DefaultContentMetadataCodec; import org.jclouds.io.Payloads; +import com.google.common.reflect.Invokable; import org.jclouds.rest.internal.RestAnnotationProcessor; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; -import org.jclouds.reflect.Invokable; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; @Test(groups = "unit", testName = "BackoffLimitedRetryHandlerTest") public class BackoffLimitedRetryHandlerTest { @@ -166,8 +168,8 @@ public class BackoffLimitedRetryHandlerTest { assertEquals(response.getPayload().getInput().read(), -1); } - private final RestAnnotationProcessor processor = BaseJettyTest.newBuilder(8100, new Properties()).buildInjector() - .getInstance(RestAnnotationProcessor.class); + private final RestAnnotationProcessor processor = BaseJettyTest.newBuilder(8100, new Properties()).buildInjector() + .getInstance(Key.get(new TypeLiteral>(){})); private HttpCommand createCommand() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(IntegrationTestAsyncClient.class.getMethod("download", String.class)); diff --git a/core/src/test/java/org/jclouds/http/internal/TrackingJavaUrlHttpCommandExecutorService.java b/core/src/test/java/org/jclouds/http/internal/TrackingJavaUrlHttpCommandExecutorService.java index 441213c1b5..fd5d869a09 100644 --- a/core/src/test/java/org/jclouds/http/internal/TrackingJavaUrlHttpCommandExecutorService.java +++ b/core/src/test/java/org/jclouds/http/internal/TrackingJavaUrlHttpCommandExecutorService.java @@ -41,7 +41,7 @@ import org.jclouds.rest.internal.GeneratedHttpRequest; import com.google.common.base.Supplier; import com.google.common.collect.Iterables; -import org.jclouds.reflect.Invokable; +import com.google.common.reflect.Invokable; import com.google.inject.AbstractModule; import com.google.inject.Module; import com.google.inject.TypeLiteral; diff --git a/core/src/test/java/org/jclouds/json/BaseParserTest.java b/core/src/test/java/org/jclouds/json/BaseParserTest.java index a9118433e4..8139275e96 100644 --- a/core/src/test/java/org/jclouds/json/BaseParserTest.java +++ b/core/src/test/java/org/jclouds/json/BaseParserTest.java @@ -28,19 +28,23 @@ import java.lang.annotation.Target; import javax.inject.Qualifier; import org.jclouds.http.HttpResponse; +import org.jclouds.http.functions.config.SaxParserModule; import org.jclouds.io.Payload; import org.jclouds.io.Payloads; import org.jclouds.json.config.GsonModule; import org.jclouds.reflect.Invocation; +import com.google.common.reflect.Invokable; import org.jclouds.rest.internal.TransformerForRequest; import org.testng.annotations.Test; import com.google.common.base.Function; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; -import org.jclouds.reflect.Invokable; +import com.google.common.reflect.TypeParameter; +import com.google.common.reflect.TypeToken; import com.google.inject.Guice; import com.google.inject.Injector; +import com.google.inject.Key; /** * @@ -57,9 +61,19 @@ public abstract class BaseParserTest { @SuppressWarnings("unchecked") protected Function parser(Injector i) { + TypeToken> token = new TypeToken>() { + private static final long serialVersionUID = 1L; + }.where(new TypeParameter() { + }, new TypeToken(getClass()) { + private static final long serialVersionUID = 1L; + }); + Key> xform = (Key>) Key.get(token.getType()); try { - return (Function) TransformerForRequest.getTransformerForMethod( - Invocation.create(Invokable.from(getClass().getMethod("expected")), ImmutableList.of()), i); + return (Function) i + .createChildInjector(new SaxParserModule()) + .getInstance(xform) + .getTransformerForMethod( + Invocation.create(Invokable.from(getClass().getMethod("expected")), ImmutableList.of()), i); } catch (Exception e) { throw Throwables.propagate(e); } @@ -83,13 +97,10 @@ public abstract class BaseParserTest { protected Injector injector() { return Guice.createInjector(new GsonModule() { - - @Override protected void configure() { bind(DateAdapter.class).to(Iso8601DateAdapter.class); super.configure(); } - }); } diff --git a/core/src/test/java/org/jclouds/reflect/FunctionalReflectionTest.java b/core/src/test/java/org/jclouds/reflect/FunctionalReflectionTest.java index 98f06c9c10..6252da5eb4 100644 --- a/core/src/test/java/org/jclouds/reflect/FunctionalReflectionTest.java +++ b/core/src/test/java/org/jclouds/reflect/FunctionalReflectionTest.java @@ -27,7 +27,6 @@ import static org.testng.Assert.assertTrue; import java.io.Closeable; import java.io.IOException; import java.util.Set; -import java.util.SortedSet; import java.util.concurrent.TimeoutException; import org.jclouds.reflect.Invocation.Result; @@ -43,22 +42,6 @@ import com.google.common.collect.ImmutableList; @Test(singleThreaded = true) public class FunctionalReflectionTest { - /** - * a method only has reference to its declaring type, not the interface specified to the proxy. this shows how to get - * access to the actual proxied interface - */ - @SuppressWarnings("unchecked") - public void testCanAccessContravariantTypeInsideFunction() { - final Function test = new Function() { - public Result apply(Invocation e) { - assertEquals(e.getInvokable().getDeclaringClass(), Set.class); - assertEquals(e.getInvokable().getEnclosingType().getRawType(), SortedSet.class); - return Result.success(true); - } - }; - FunctionalReflection.newProxy(SortedSet.class, test).add(null); - } - @SuppressWarnings("unchecked") @Test(expectedExceptions = UnsupportedOperationException.class) public void testNullArgsAreAllowedAndUnmodifiable() { diff --git a/core/src/test/java/org/jclouds/reflect/InvokableTest.java b/core/src/test/java/org/jclouds/reflect/InvokableTest.java deleted file mode 100644 index d52c454c1e..0000000000 --- a/core/src/test/java/org/jclouds/reflect/InvokableTest.java +++ /dev/null @@ -1,345 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.jclouds.reflect; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.lang.reflect.TypeVariable; -import java.util.Collections; - -import org.testng.annotations.Test; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; -import com.google.common.reflect.TypeToken; - -/** - * ported from {@link com.google.common.reflect.InvokableTest} - * - */ -@Test -@SuppressWarnings("serial") -public class InvokableTest { - - public void testConstructor_returnType() throws Exception { - assertEquals(Prepender.class, Prepender.constructor().getReturnType().getType()); - } - - public void testConstructor_exceptionTypes() throws Exception { - assertEquals(ImmutableList.of(TypeToken.of(NullPointerException.class)), - Prepender.constructor(String.class, int.class).getExceptionTypes()); - } - - public void testConstructor_typeParameters() throws Exception { - TypeVariable[] variables = Prepender.constructor().getTypeParameters(); - assertEquals(1, variables.length); - assertEquals("A", variables[0].getName()); - } - - public void testConstructor_parameters() throws Exception { - Invokable delegate = Prepender.constructor(String.class, int.class); - ImmutableList parameters = delegate.getParameters(); - assertEquals(2, parameters.size()); - assertEquals(String.class, parameters.get(0).getType().getType()); - assertTrue(parameters.get(0).isAnnotationPresent(NotBlank.class)); - assertEquals(int.class, parameters.get(1).getType().getType()); - assertFalse(parameters.get(1).isAnnotationPresent(NotBlank.class)); - } - - public void testConstructor_call() throws Exception { - Invokable delegate = Prepender.constructor(String.class, int.class); - Prepender prepender = delegate.invoke(null, "a", 1); - assertEquals("a", prepender.prefix); - assertEquals(1, prepender.times); - } - - public void testConstructor_returning() throws Exception { - Invokable delegate = Prepender.constructor(String.class, int.class).returning(Prepender.class); - Prepender prepender = delegate.invoke(null, "a", 1); - assertEquals("a", prepender.prefix); - assertEquals(1, prepender.times); - } - - public void testConstructor_invalidReturning() throws Exception { - Invokable delegate = Prepender.constructor(String.class, int.class); - try { - delegate.returning(SubPrepender.class); - fail(); - } catch (IllegalArgumentException expected) { - } - } - - public void testStaticMethod_returnType() throws Exception { - Invokable delegate = Prepender.method("prepend", String.class, Iterable.class); - assertEquals(new TypeToken>() { - }, delegate.getReturnType()); - } - - public void testStaticMethod_exceptionTypes() throws Exception { - Invokable delegate = Prepender.method("prepend", String.class, Iterable.class); - assertEquals(ImmutableList.of(), delegate.getExceptionTypes()); - } - - public void testStaticMethod_typeParameters() throws Exception { - Invokable delegate = Prepender.method("prepend", String.class, Iterable.class); - TypeVariable[] variables = delegate.getTypeParameters(); - assertEquals(1, variables.length); - assertEquals("T", variables[0].getName()); - } - - public void testStaticMethod_parameters() throws Exception { - Invokable delegate = Prepender.method("prepend", String.class, Iterable.class); - ImmutableList parameters = delegate.getParameters(); - assertEquals(2, parameters.size()); - assertEquals(String.class, parameters.get(0).getType().getType()); - assertTrue(parameters.get(0).isAnnotationPresent(NotBlank.class)); - assertEquals(new TypeToken>() { - }, parameters.get(1).getType()); - assertFalse(parameters.get(1).isAnnotationPresent(NotBlank.class)); - } - - public void testStaticMethod_call() throws Exception { - Invokable delegate = Prepender.method("prepend", String.class, Iterable.class); - @SuppressWarnings("unchecked") - // prepend() returns Iterable - Iterable result = (Iterable) delegate.invoke(null, "a", ImmutableList.of("b", "c")); - assertEquals(ImmutableList.of("a", "b", "c"), ImmutableList.copyOf(result)); - } - - public void testStaticMethod_returning() throws Exception { - Invokable> delegate = Prepender.method("prepend", String.class, Iterable.class).returning( - new TypeToken>() { - }); - assertEquals(new TypeToken>() { - }, delegate.getReturnType()); - Iterable result = delegate.invoke(null, "a", ImmutableList.of("b", "c")); - assertEquals(ImmutableList.of("a", "b", "c"), ImmutableList.copyOf(result)); - } - - public void testStaticMethod_returningRawType() throws Exception { - @SuppressWarnings("rawtypes") - // the purpose is to test raw type - Invokable delegate = Prepender.method("prepend", String.class, Iterable.class).returning( - Iterable.class); - assertEquals(new TypeToken>() { - }, delegate.getReturnType()); - @SuppressWarnings("unchecked") - // prepend() returns Iterable - Iterable result = delegate.invoke(null, "a", ImmutableList.of("b", "c")); - assertEquals(ImmutableList.of("a", "b", "c"), ImmutableList.copyOf(result)); - } - - public void testStaticMethod_invalidReturning() throws Exception { - Invokable delegate = Prepender.method("prepend", String.class, Iterable.class); - try { - delegate.returning(new TypeToken>() { - }); - fail(); - } catch (IllegalArgumentException expected) { - } - } - - public void testInstanceMethod_returnType() throws Exception { - Invokable delegate = Prepender.method("prepend", Iterable.class); - assertEquals(new TypeToken>() { - }, delegate.getReturnType()); - } - - public void testInstanceMethod_exceptionTypes() throws Exception { - Invokable delegate = Prepender.method("prepend", Iterable.class); - assertEquals( - ImmutableList.of(TypeToken.of(IllegalArgumentException.class), TypeToken.of(NullPointerException.class)), - delegate.getExceptionTypes()); - } - - public void testInstanceMethod_typeParameters() throws Exception { - Invokable delegate = Prepender.method("prepend", Iterable.class); - assertEquals(0, delegate.getTypeParameters().length); - } - - public void testInstanceMethod_parameters() throws Exception { - Invokable delegate = Prepender.method("prepend", Iterable.class); - ImmutableList parameters = delegate.getParameters(); - assertEquals(1, parameters.size()); - assertEquals(new TypeToken>() { - }, parameters.get(0).getType()); - assertEquals(0, parameters.get(0).getAnnotations().length); - } - - public void testInstanceMethod_call() throws Exception { - Invokable delegate = Prepender.method("prepend", Iterable.class); - @SuppressWarnings("unchecked") - // prepend() returns Iterable - Iterable result = (Iterable) delegate.invoke(new Prepender("a", 2), ImmutableList.of("b", "c")); - assertEquals(ImmutableList.of("a", "a", "b", "c"), ImmutableList.copyOf(result)); - } - - public void testInstanceMethod_returning() throws Exception { - Invokable> delegate = Prepender.method("prepend", Iterable.class).returning( - new TypeToken>() { - }); - assertEquals(new TypeToken>() { - }, delegate.getReturnType()); - Iterable result = delegate.invoke(new Prepender("a", 2), ImmutableList.of("b", "c")); - assertEquals(ImmutableList.of("a", "a", "b", "c"), ImmutableList.copyOf(result)); - } - - public void testInstanceMethod_returningRawType() throws Exception { - @SuppressWarnings("rawtypes") - // the purpose is to test raw type - Invokable delegate = Prepender.method("prepend", Iterable.class).returning(Iterable.class); - assertEquals(new TypeToken>() { - }, delegate.getReturnType()); - @SuppressWarnings("unchecked") - // prepend() returns Iterable - Iterable result = delegate.invoke(new Prepender("a", 2), ImmutableList.of("b", "c")); - assertEquals(ImmutableList.of("a", "a", "b", "c"), ImmutableList.copyOf(result)); - } - - public void testInstanceMethod_invalidReturning() throws Exception { - Invokable delegate = Prepender.method("prepend", Iterable.class); - try { - delegate.returning(new TypeToken>() { - }); - fail(); - } catch (IllegalArgumentException expected) { - } - } - - public void testPrivateInstanceMethod_isOverridable() throws Exception { - Invokable delegate = Prepender.method("privateMethod"); - assertTrue(delegate.isPrivate()); - assertFalse(delegate.isOverridable()); - } - - public void testPrivateFinalInstanceMethod_isOverridable() throws Exception { - Invokable delegate = Prepender.method("privateFinalMethod"); - assertTrue(delegate.isPrivate()); - assertTrue(delegate.isFinal()); - assertFalse(delegate.isOverridable()); - } - - public void testStaticMethod_isOverridable() throws Exception { - Invokable delegate = Prepender.method("staticMethod"); - assertTrue(delegate.isStatic()); - assertFalse(delegate.isOverridable()); - } - - public void testStaticFinalMethod_isFinal() throws Exception { - Invokable delegate = Prepender.method("staticFinalMethod"); - assertTrue(delegate.isStatic()); - assertTrue(delegate.isFinal()); - assertFalse(delegate.isOverridable()); - } - - static class Foo { - } - - public void testConstructor_isOverridablel() throws Exception { - Invokable delegate = Invokable.from(Foo.class.getDeclaredConstructor()); - assertFalse(delegate.isOverridable()); - } - - private static final class FinalClass { - @SuppressWarnings("unused") - // used by reflection - void notFinalMethod() { - } - } - - public void testNonFinalMethodInFinalClass_isOverridable() throws Exception { - Invokable delegate = Invokable.from(FinalClass.class.getDeclaredMethod("notFinalMethod")); - assertFalse(delegate.isOverridable()); - } - - @Retention(RetentionPolicy.RUNTIME) - private @interface NotBlank { - } - - /** Class for testing construcrtor, static method and instance method. */ - @SuppressWarnings("unused") - // most are called by reflection - private static class Prepender { - - private final String prefix; - private final int times; - - Prepender(@NotBlank String prefix, int times) throws NullPointerException { - this.prefix = prefix; - this.times = times; - } - - // just for testing - private Prepender() { - this(null, 0); - } - - static Iterable prepend(@NotBlank String first, Iterable tail) { - return Iterables.concat(ImmutableList.of(first), tail); - } - - Iterable prepend(Iterable tail) throws IllegalArgumentException, NullPointerException { - return Iterables.concat(Collections.nCopies(times, prefix), tail); - } - - static Invokable constructor(Class... parameterTypes) throws Exception { - Constructor constructor = Prepender.class.getDeclaredConstructor(parameterTypes); - return Invokable.from(constructor); - } - - static Invokable method(String name, Class... parameterTypes) { - try { - Method method = Prepender.class.getDeclaredMethod(name, parameterTypes); - @SuppressWarnings("unchecked") - // The method is from Prepender. - Invokable invokable = (Invokable) Invokable.from(method); - return invokable; - } catch (NoSuchMethodException e) { - throw new IllegalArgumentException(e); - } - } - - private void privateMethod() { - } - - private final void privateFinalMethod() { - } - - static void staticMethod() { - } - - static final void staticFinalMethod() { - } - } - - private static class SubPrepender extends Prepender { - @SuppressWarnings("unused") - // needed to satisfy compiler, never called - public SubPrepender() throws NullPointerException { - throw new AssertionError(); - } - } -} diff --git a/core/src/test/java/org/jclouds/rest/InputParamValidatorTest.java b/core/src/test/java/org/jclouds/rest/InputParamValidatorTest.java index 7506757aa6..b1936fdc25 100644 --- a/core/src/test/java/org/jclouds/rest/InputParamValidatorTest.java +++ b/core/src/test/java/org/jclouds/rest/InputParamValidatorTest.java @@ -34,8 +34,10 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.google.common.collect.ImmutableList; -import org.jclouds.reflect.Invokable; +import com.google.common.reflect.Invokable; import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; @Test(groups = "unit") public class InputParamValidatorTest { @@ -104,7 +106,7 @@ public class InputParamValidatorTest { } Injector injector; - RestAnnotationProcessor restAnnotationProcessor; + RestAnnotationProcessor restAnnotationProcessor; @BeforeClass void setupFactory() { @@ -112,7 +114,7 @@ public class InputParamValidatorTest { .newBuilder( AnonymousProviderMetadata.forClientMappedToAsyncClientOnEndpoint(IntegrationTestClient.class, IntegrationTestAsyncClient.class, "http://localhost:9999")).buildInjector(); - restAnnotationProcessor = injector.getInstance(RestAnnotationProcessor.class); + restAnnotationProcessor = injector.getInstance(Key.get(new TypeLiteral>(){})); } } diff --git a/core/src/test/java/org/jclouds/rest/binders/BindMapToStringPayloadTest.java b/core/src/test/java/org/jclouds/rest/binders/BindMapToStringPayloadTest.java index 3f0a9865fc..4182edb6c1 100644 --- a/core/src/test/java/org/jclouds/rest/binders/BindMapToStringPayloadTest.java +++ b/core/src/test/java/org/jclouds/rest/binders/BindMapToStringPayloadTest.java @@ -33,7 +33,9 @@ import org.testng.annotations.Test; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import org.jclouds.reflect.Invokable; +import com.google.common.reflect.TypeToken; + +import com.google.common.reflect.Invokable; /** * Tests behavior of {@code BindMapToStringPayload} @@ -55,12 +57,12 @@ public class BindMapToStringPayloadTest { @Test public void testCorrect() throws SecurityException, NoSuchMethodException { Invokable testPayload = Invokable.from(TestPayload.class.getMethod("testPayload", String.class)); - GeneratedHttpRequest request = GeneratedHttpRequest.builder() + GeneratedHttpRequest request = GeneratedHttpRequest.builder(TypeToken.of(TestPayload.class)) .invocation(Invocation.create(testPayload, ImmutableList. of("robot"))) .method("POST").endpoint("http://localhost").build(); - GeneratedHttpRequest newRequest = binder() - .bindToRequest(request, ImmutableMap.of("fooble", "robot")); + GeneratedHttpRequest newRequest = binder().bindToRequest(request, + ImmutableMap. of("fooble", "robot")); assertEquals(newRequest.getRequestLine(), request.getRequestLine()); assertEquals(newRequest.getPayload().getRawContent(), "name robot"); @@ -69,11 +71,11 @@ public class BindMapToStringPayloadTest { @Test public void testDecodes() throws SecurityException, NoSuchMethodException { Invokable testPayload = Invokable.from(TestPayload.class.getMethod("changeAdminPass", String.class)); - GeneratedHttpRequest request = GeneratedHttpRequest.builder() + GeneratedHttpRequest request = GeneratedHttpRequest.builder(TypeToken.of(TestPayload.class)) .invocation(Invocation.create(testPayload, ImmutableList. of("foo"))) .method("POST").endpoint("http://localhost").build(); - GeneratedHttpRequest newRequest = binder() + GeneratedHttpRequest newRequest = binder() .bindToRequest(request, ImmutableMap.of("adminPass", "foo")); assertEquals(newRequest.getRequestLine(), request.getRequestLine()); @@ -83,7 +85,7 @@ public class BindMapToStringPayloadTest { @Test(expectedExceptions = IllegalArgumentException.class) public void testMustHavePayloadAnnotation() throws SecurityException, NoSuchMethodException { Invokable noPayload = Invokable.from(TestPayload.class.getMethod("noPayload", String.class)); - GeneratedHttpRequest request = GeneratedHttpRequest.builder() + GeneratedHttpRequest request = GeneratedHttpRequest.builder(TypeToken.of(TestPayload.class)) .invocation(Invocation.create(noPayload, ImmutableList. of("robot"))) .method("POST").endpoint("http://localhost").build(); binder().bindToRequest(request, ImmutableMap.of("fooble", "robot")); diff --git a/core/src/test/java/org/jclouds/rest/functions/PresentWhenApiVersionLexicographicallyAtOrAfterSinceApiVersionTest.java b/core/src/test/java/org/jclouds/rest/functions/PresentWhenApiVersionLexicographicallyAtOrAfterSinceApiVersionTest.java index fa602b895d..6acd1bc26e 100644 --- a/core/src/test/java/org/jclouds/rest/functions/PresentWhenApiVersionLexicographicallyAtOrAfterSinceApiVersionTest.java +++ b/core/src/test/java/org/jclouds/rest/functions/PresentWhenApiVersionLexicographicallyAtOrAfterSinceApiVersionTest.java @@ -35,7 +35,7 @@ import org.testng.annotations.Test; import com.google.common.base.Optional; import com.google.common.base.Stopwatch; import com.google.common.collect.ImmutableList; -import org.jclouds.reflect.Invokable; +import com.google.common.reflect.Invokable; /** * Allows you to use simple api version comparison to determine if a feature is diff --git a/core/src/test/java/org/jclouds/rest/internal/BaseAsyncApiTest.java b/core/src/test/java/org/jclouds/rest/internal/BaseAsyncApiTest.java index 2b883e0fcc..8737aca4a1 100644 --- a/core/src/test/java/org/jclouds/rest/internal/BaseAsyncApiTest.java +++ b/core/src/test/java/org/jclouds/rest/internal/BaseAsyncApiTest.java @@ -33,8 +33,10 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.google.common.collect.ImmutableSet; +import com.google.common.reflect.TypeToken; import com.google.inject.Binder; import com.google.inject.Injector; +import com.google.inject.Key; import com.google.inject.Module; /** @@ -44,7 +46,7 @@ import com.google.inject.Module; @Test(groups = "unit") public abstract class BaseAsyncApiTest extends BaseRestApiTest { - protected RestAnnotationProcessor processor; + protected RestAnnotationProcessor processor; protected abstract void checkFilters(HttpRequest request); @@ -63,31 +65,36 @@ public abstract class BaseAsyncApiTest extends BaseRestApiTest { protected void setupFactory() throws IOException { injector = createInjector(); parserFactory = injector.getInstance(ParseSax.Factory.class); - processor = injector.getInstance(RestAnnotationProcessor.class); + processor = injector.getInstance(rapKey); } - + protected String identity = "identity"; protected String credential = "credential"; - + @SuppressWarnings("unchecked") + Key> rapKey = (Key>) Key + .get(new TypeToken>(getClass()) { + private static final long serialVersionUID = 1L; + }.getType()); + /** * @see org.jclouds.providers.Providers#withId */ protected ProviderMetadata createProviderMetadata() { return null; } - + /** * @see org.jclouds.apis.Apis#withId */ protected ApiMetadata createApiMetadata() { return null; } - + protected Injector createInjector() { ProviderMetadata pm = createProviderMetadata(); - ContextBuilder builder = pm != null ? ContextBuilder.newBuilder(pm) : ContextBuilder - .newBuilder(ApiMetadata.class.cast(checkNotNull(createApiMetadata(), + ContextBuilder builder = pm != null ? ContextBuilder.newBuilder(pm) : ContextBuilder.newBuilder(ApiMetadata.class + .cast(checkNotNull(createApiMetadata(), "either createApiMetadata or createProviderMetadata must be overridden"))); return builder.credentials(identity, credential) diff --git a/core/src/test/java/org/jclouds/rest/internal/BaseRestApiTest.java b/core/src/test/java/org/jclouds/rest/internal/BaseRestApiTest.java index 613453b3cc..e1298af21a 100644 --- a/core/src/test/java/org/jclouds/rest/internal/BaseRestApiTest.java +++ b/core/src/test/java/org/jclouds/rest/internal/BaseRestApiTest.java @@ -40,7 +40,7 @@ import org.jclouds.http.config.ConfiguresHttpCommandExecutorService; import org.jclouds.http.functions.ParseSax; import org.jclouds.io.MutableContentMetadata; import org.jclouds.javax.annotation.Nullable; -import org.jclouds.reflect.Invokable; +import com.google.common.reflect.Invokable; import org.jclouds.rest.annotations.Fallback; import org.jclouds.rest.annotations.XMLResponseParser; import org.jclouds.util.Strings2; @@ -49,8 +49,11 @@ import org.testng.annotations.Test; import com.google.common.collect.Multimap; import com.google.common.collect.SortedSetMultimap; import com.google.common.collect.TreeMultimap; +import com.google.common.reflect.TypeParameter; +import com.google.common.reflect.TypeToken; import com.google.inject.AbstractModule; import com.google.inject.Injector; +import com.google.inject.Key; import com.google.inject.name.Names; /** @@ -177,7 +180,25 @@ public abstract class BaseRestApiTest { protected void assertResponseParserClassEquals(Invokable method, GeneratedHttpRequest request, @Nullable Class parserClass) { - assertEquals(TransformerForRequest.createResponseParser(parserFactory, injector, request).getClass(), - parserClass); + assertEquals(transformer(method.getDeclaringClass()).apply(request).getClass(), parserClass); } + + protected RestAnnotationProcessor processor(Class type) { + TypeToken> token = new TypeToken>() { + private static final long serialVersionUID = 1L; + }.where(new TypeParameter() { + }, type); + Key> rapKey = (Key>) Key.get(token.getType()); + return injector.getInstance(rapKey); + } + + protected TransformerForRequest transformer(Class type) { + TypeToken> token = new TypeToken>() { + private static final long serialVersionUID = 1L; + }.where(new TypeParameter() { + }, type); + Key> rapKey = (Key>) Key.get(token.getType()); + return injector.getInstance(rapKey); + } + } diff --git a/core/src/test/java/org/jclouds/rest/internal/BaseRestClientTest.java b/core/src/test/java/org/jclouds/rest/internal/BaseRestClientTest.java deleted file mode 100644 index 480652161c..0000000000 --- a/core/src/test/java/org/jclouds/rest/internal/BaseRestClientTest.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Licensed to jclouds, Inc. (jclouds) under one or more - * contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. jclouds licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.jclouds.rest.internal; - -import org.testng.annotations.Test; - -/** - * - * @author Adrian Cole - */ -@Test(groups = "unit") -public abstract class BaseRestClientTest extends BaseRestApiTest { - -} diff --git a/core/src/test/java/org/jclouds/rest/internal/RestAnnotationProcessorTest.java b/core/src/test/java/org/jclouds/rest/internal/RestAnnotationProcessorTest.java index 4cf3fad888..a8198702b4 100644 --- a/core/src/test/java/org/jclouds/rest/internal/RestAnnotationProcessorTest.java +++ b/core/src/test/java/org/jclouds/rest/internal/RestAnnotationProcessorTest.java @@ -94,6 +94,7 @@ import org.jclouds.logging.config.NullLoggingModule; import org.jclouds.providers.AnonymousProviderMetadata; import org.jclouds.reflect.Invocation; import org.jclouds.reflect.InvocationSuccess; +import com.google.common.reflect.Invokable; import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.InvocationContext; @@ -121,7 +122,7 @@ import org.jclouds.rest.annotations.WrapWith; import org.jclouds.rest.binders.BindAsHostPrefix; import org.jclouds.rest.binders.BindToJsonPayload; import org.jclouds.rest.binders.BindToStringPayload; -import org.jclouds.rest.config.AsyncClientProvider; +import org.jclouds.rest.config.AsyncHttpApiProvider; import org.jclouds.rest.config.RestClientModule; import org.jclouds.rest.functions.ImplicitOptionalConverter; import org.jclouds.util.Strings2; @@ -143,7 +144,7 @@ import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.io.Files; -import org.jclouds.reflect.Invokable; +import com.google.common.reflect.TypeToken; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.inject.AbstractModule; @@ -186,14 +187,14 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Path("/{path}") ListenableFuture onePath(@PathParam("path") String path); } - + @Path("/client/{jclouds.api-version}") public static interface AsyncCallee2 { @GET @Path("/{path}/2") ListenableFuture onePath(@PathParam("path") String path); } - + @Endpoint(Localhost2.class) public static interface Caller { @@ -207,7 +208,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Delegate public Callee2 getCallee2(); - + @Delegate public Callee getCallee(@EndpointParam URI endpoint); @@ -222,7 +223,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public static interface Callee { void onePath(String path); } - + public static interface Callee2 { void onePath(String path); } @@ -237,7 +238,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Delegate public AsyncCallee2 getCallee2(); - + @Delegate public AsyncCallee getCallee(@EndpointParam URI endpoint); @@ -276,11 +277,16 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testDelegateIsLazyLoadedAndRequestIncludesVersionAndPath() throws InterruptedException, ExecutionException { Injector child = injectorForCaller(new HttpCommandExecutorService() { - int callCounter=0; + int callCounter = 0; + @Override public Future submit(HttpCommand command) { - if (callCounter == 1) assertEquals(command.getCurrentRequest().getRequestLine(), "GET http://localhost:1111/client/1/bar/2 HTTP/1.1"); - else assertEquals(command.getCurrentRequest().getRequestLine(), "GET http://localhost:1111/client/1/foo HTTP/1.1"); + if (callCounter == 1) + assertEquals(command.getCurrentRequest().getRequestLine(), + "GET http://localhost:1111/client/1/bar/2 HTTP/1.1"); + else + assertEquals(command.getCurrentRequest().getRequestLine(), + "GET http://localhost:1111/client/1/foo HTTP/1.1"); callCounter++; return Futures.immediateFuture(HttpResponse.builder().build()); } @@ -324,13 +330,14 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { } - public void testAsyncDelegateWithPathParamIsLazyLoadedAndRequestIncludesEndpointVersionAndPath() throws InterruptedException, - ExecutionException { + public void testAsyncDelegateWithPathParamIsLazyLoadedAndRequestIncludesEndpointVersionAndPath() + throws InterruptedException, ExecutionException { Injector child = injectorForCaller(new HttpCommandExecutorService() { @Override public Future submit(HttpCommand command) { - assertEquals(command.getCurrentRequest().getRequestLine(), "GET http://howdyboys/testing/testing/thepathparam/client/1/foo HTTP/1.1"); + assertEquals(command.getCurrentRequest().getRequestLine(), + "GET http://howdyboys/testing/testing/thepathparam/client/1/foo HTTP/1.1"); return Futures.immediateFuture(HttpResponse.builder().build()); } @@ -343,7 +350,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { } - child.getInstance(AsyncCaller.class).getCalleeWithPath(URI.create("http://howdyboys"), "thepathparam").onePath("foo").get(); + child.getInstance(AsyncCaller.class).getCalleeWithPath(URI.create("http://howdyboys"), "thepathparam") + .onePath("foo").get(); assertEquals(child.getInstance(AsyncCaller.class).getURI(), URI.create("http://localhost:1111")); } @@ -468,19 +476,19 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @FOO @Path("/") - @QueryParams(keys = { "foo", "fooble"}, values = { "bar", "baz"}) + @QueryParams(keys = { "foo", "fooble" }, values = { "bar", "baz" }) public void foo2() { } @FOO @Path("/") - @QueryParams(keys = { "foo", "fooble"}, values = { "bar", "baz"}) + @QueryParams(keys = { "foo", "fooble" }, values = { "bar", "baz" }) public void foo3(@QueryParam("robbie") String robbie) { } - + @FOO @Path("/") - @QueryParams(keys = { "foo", "fooble"}, values = { "bar", "baz"}) + @QueryParams(keys = { "foo", "fooble" }, values = { "bar", "baz" }) public void foo3Nullable(@Nullable @QueryParam("robbie") String robbie) { } @@ -492,7 +500,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testQuery() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestQuery.class.getMethod("foo")); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestQuery.class).createRequest(method, ImmutableList.of()); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPath(), "/"); assertEquals(request.getEndpoint().getQuery(), "x-ms-version=2009-07-17&x-ms-rubbish=bin"); @@ -501,7 +509,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testQuery2() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestQuery.class.getMethod("foo2")); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestQuery.class).createRequest(method, ImmutableList.of()); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPath(), "/"); assertEquals(request.getEndpoint().getQuery(), "x-ms-version=2009-07-17&foo=bar&fooble=baz"); @@ -510,32 +518,34 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testQuery3() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestQuery.class.getMethod("foo3", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("wonder")); + GeneratedHttpRequest request = processor(TestQuery.class).createRequest(method, + ImmutableList. of("wonder")); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPath(), "/"); assertEquals(request.getEndpoint().getQuery(), "x-ms-version=2009-07-17&foo=bar&fooble=baz&robbie=wonder"); assertEquals(request.getMethod(), "FOO"); } - + @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "param\\{robbie\\} for invocation TestQuery.foo3") public void testNiceNPEQueryParam() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestQuery.class.getMethod("foo3", String.class)); - processor.createRequest(method, Lists. newArrayList((String) null)); + processor(TestQuery.class).createRequest(method, Lists. newArrayList((String) null)); } public void testNoNPEOnQueryParamWithNullable() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestQuery.class.getMethod("foo3Nullable", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, Lists. newArrayList((String) null)); + GeneratedHttpRequest request = processor(TestQuery.class).createRequest(method, + Lists. newArrayList((String) null)); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPath(), "/"); assertEquals(request.getEndpoint().getQuery(), "x-ms-version=2009-07-17&foo=bar&fooble=baz"); assertEquals(request.getMethod(), "FOO"); } - + public void testQueryParamIterableOneString() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestQuery.class.getMethod("queryParamIterable", Iterable.class)); - Set bars = ImmutableSortedSet. of("1"); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of(bars)); + Set bars = ImmutableSortedSet. of("1"); + GeneratedHttpRequest request = processor(TestQuery.class).createRequest(method, ImmutableList. of(bars)); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPath(), "/"); assertEquals(request.getEndpoint().getQuery(), "x-ms-version=2009-07-17&foo=1"); @@ -544,8 +554,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testQueryParamIterableString() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestQuery.class.getMethod("queryParamIterable", Iterable.class)); - Set bars = ImmutableSortedSet. of("1", "2", "3"); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of(bars)); + Set bars = ImmutableSortedSet. of("1", "2", "3"); + GeneratedHttpRequest request = processor(TestQuery.class).createRequest(method, ImmutableList. of(bars)); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPath(), "/"); assertEquals(request.getEndpoint().getQuery(), "x-ms-version=2009-07-17&foo=1&foo=2&foo=3"); @@ -554,8 +564,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testQueryParamIterableInteger() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestQuery.class.getMethod("queryParamIterable", Iterable.class)); - Set bars = ImmutableSortedSet. of(1, 2, 3); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of(bars)); + Set bars = ImmutableSortedSet. of(1, 2, 3); + GeneratedHttpRequest request = processor(TestQuery.class).createRequest(method, ImmutableList. of(bars)); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPath(), "/"); assertEquals(request.getEndpoint().getQuery(), "x-ms-version=2009-07-17&foo=1&foo=2&foo=3"); @@ -564,8 +574,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testQueryParamIterableEmpty() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestQuery.class.getMethod("queryParamIterable", Iterable.class)); - Set bars = Collections.emptySet(); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of(bars)); + Set bars = Collections.emptySet(); + GeneratedHttpRequest request = processor(TestQuery.class).createRequest(method, ImmutableList. of(bars)); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPath(), "/"); assertEquals(request.getEndpoint().getQuery(), "x-ms-version=2009-07-17"); @@ -574,7 +584,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testQueryParamIterableNull() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestQuery.class.getMethod("queryParamIterable", Iterable.class)); - GeneratedHttpRequest request = processor.createRequest(method, Lists. newArrayList((String) null)); + GeneratedHttpRequest request = processor(TestQuery.class).createRequest(method, + Lists. newArrayList((String) null)); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPath(), "/"); assertEquals(request.getEndpoint().getQuery(), "x-ms-version=2009-07-17"); @@ -602,70 +613,90 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testHttpRequestOptionsNoPayloadParam() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPayloadParamVarargs.class.getMethod("post")); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestPayloadParamVarargs.class).createRequest(method, ImmutableList.of()); assertRequestLineEquals(request, "POST http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); assertPayloadEquals(request, "", "application/octet-stream", false); } - + private class TestHttpRequestOptions extends BaseHttpRequestOptions { - TestHttpRequestOptions payload(String payload) { this.payload = payload; return this; } - TestHttpRequestOptions headerParams(Multimap headers) { this.headers.putAll(headers); return this; } - TestHttpRequestOptions queryParams(Multimap params) { this.queryParameters.putAll(params); return this; } + TestHttpRequestOptions payload(String payload) { + this.payload = payload; + return this; + } + + TestHttpRequestOptions headerParams(Multimap headers) { + this.headers.putAll(headers); + return this; + } + + TestHttpRequestOptions queryParams(Multimap params) { + this.queryParameters.putAll(params); + return this; + } } public void testHttpRequestOptionsPayloadParam() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPayloadParamVarargs.class.getMethod("post", Payload.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of(Payloads.newStringPayload("foo"))); + GeneratedHttpRequest request = processor(TestPayloadParamVarargs.class).createRequest(method, + ImmutableList. of(Payloads.newStringPayload("foo"))); assertRequestLineEquals(request, "POST http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); assertPayloadEquals(request, "foo", "application/octet-stream", false); } - + public void testHttpRequestWithOnlyContentType() throws SecurityException, NoSuchMethodException, IOException { - Invokable method = Invokable.from(TestPayloadParamVarargs.class.getMethod("post", HttpRequestOptions.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of(new TestHttpRequestOptions().payload("fooya"))); + Invokable method = Invokable + .from(TestPayloadParamVarargs.class.getMethod("post", HttpRequestOptions.class)); + GeneratedHttpRequest request = processor(TestPayloadParamVarargs.class).createRequest(method, + ImmutableList. of(new TestHttpRequestOptions().payload("fooya"))); assertRequestLineEquals(request, "POST http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); assertPayloadEquals(request, "fooya", "application/unknown", false); } public void testHeaderAndQueryVarargs() throws SecurityException, NoSuchMethodException, IOException { - Invokable method = Invokable.from(TestPayloadParamVarargs.class.getMethod("varargs", HttpRequestOptions[].class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of( - new TestHttpRequestOptions().payload("fooya"), - new TestHttpRequestOptions().headerParams(ImmutableMultimap.of("X-header-1", "fooya")), - new TestHttpRequestOptions().queryParams(ImmutableMultimap.of("key", "value")))); + Invokable method = Invokable.from(TestPayloadParamVarargs.class.getMethod("varargs", + HttpRequestOptions[].class)); + GeneratedHttpRequest request = processor(TestPayloadParamVarargs.class).createRequest( + method, + ImmutableList. of(new TestHttpRequestOptions().payload("fooya"), + new TestHttpRequestOptions().headerParams(ImmutableMultimap.of("X-header-1", "fooya")), + new TestHttpRequestOptions().queryParams(ImmutableMultimap.of("key", "value")))); assertRequestLineEquals(request, "POST http://localhost:9999?key=value HTTP/1.1"); assertNonPayloadHeadersEqual(request, "X-header-1: fooya\n"); assertPayloadEquals(request, "fooya", "application/unknown", false); } public void testHeaderAndQueryVarargsPlusReq() throws SecurityException, NoSuchMethodException, IOException { - Invokable method = Invokable.from(TestPayloadParamVarargs.class.getMethod("varargsWithReq", String.class, HttpRequestOptions[].class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("required param", - new TestHttpRequestOptions().payload("fooya"), - new TestHttpRequestOptions().headerParams(ImmutableMultimap.of("X-header-1", "fooya")), - new TestHttpRequestOptions().queryParams(ImmutableMultimap.of("key", "value")))); + Invokable method = Invokable.from(TestPayloadParamVarargs.class.getMethod("varargsWithReq", String.class, + HttpRequestOptions[].class)); + GeneratedHttpRequest request = processor(TestPayloadParamVarargs.class).createRequest( + method, + ImmutableList. of("required param", new TestHttpRequestOptions().payload("fooya"), + new TestHttpRequestOptions().headerParams(ImmutableMultimap.of("X-header-1", "fooya")), + new TestHttpRequestOptions().queryParams(ImmutableMultimap.of("key", "value")))); assertRequestLineEquals(request, "POST http://localhost:9999?key=value HTTP/1.1"); assertNonPayloadHeadersEqual(request, "X-header-1: fooya\n"); assertPayloadEquals(request, "fooya", "application/unknown", false); } public void testDuplicateHeaderAndQueryVarargs() throws SecurityException, NoSuchMethodException, IOException { - Invokable method = Invokable.from(TestPayloadParamVarargs.class.getMethod("varargs", HttpRequestOptions[].class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of( - new TestHttpRequestOptions().queryParams(ImmutableMultimap.of("key", "value")), - new TestHttpRequestOptions().payload("fooya"), - new TestHttpRequestOptions().headerParams(ImmutableMultimap.of("X-header-1", "fooya")), - new TestHttpRequestOptions().queryParams(ImmutableMultimap.of("key", "anothervalue")), - new TestHttpRequestOptions().headerParams(ImmutableMultimap.of("X-header-1", "fooya again!")), - new TestHttpRequestOptions().payload("last_payload_wins!"))); + Invokable method = Invokable.from(TestPayloadParamVarargs.class.getMethod("varargs", + HttpRequestOptions[].class)); + GeneratedHttpRequest request = processor(TestPayloadParamVarargs.class).createRequest( + method, + ImmutableList. of(new TestHttpRequestOptions().queryParams(ImmutableMultimap.of("key", "value")), + new TestHttpRequestOptions().payload("fooya"), + new TestHttpRequestOptions().headerParams(ImmutableMultimap.of("X-header-1", "fooya")), + new TestHttpRequestOptions().queryParams(ImmutableMultimap.of("key", "anothervalue")), + new TestHttpRequestOptions().headerParams(ImmutableMultimap.of("X-header-1", "fooya again!")), + new TestHttpRequestOptions().payload("last_payload_wins!"))); assertRequestLineEquals(request, "POST http://localhost:9999?key=value&key=anothervalue HTTP/1.1"); assertNonPayloadHeadersEqual(request, "X-header-1: fooya\nX-header-1: fooya again!\n"); assertPayloadEquals(request, "last_payload_wins!", "application/unknown", false); } - + public class TestCustomMethod { @FOO public void foo() { @@ -674,7 +705,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCustomMethod() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestCustomMethod.class.getMethod("foo")); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestCustomMethod.class).createRequest(method, ImmutableList.of()); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPath(), ""); assertEquals(request.getMethod(), "FOO"); @@ -692,7 +723,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testOverriddenMethod() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestOverridden.class.getMethod("foo")); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestOverridden.class).createRequest(method, ImmutableList.of()); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPath(), ""); assertEquals(request.getMethod(), "POST"); @@ -712,7 +743,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testOverriddenEndpointMethod() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestOverriddenEndpoint.class.getMethod("foo")); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestOverriddenEndpoint.class).createRequest(method, ImmutableList.of()); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPort(), 1111); assertEquals(request.getEndpoint().getPath(), ""); @@ -721,7 +752,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testOverriddenEndpointParameter() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestOverriddenEndpoint.class.getMethod("foo", URI.class)); - GeneratedHttpRequest request = processor.createRequest(method, + GeneratedHttpRequest request = processor(TestOverriddenEndpoint.class).createRequest(method, ImmutableList. of(URI.create("http://wowsa:8001"))); assertEquals(request.getEndpoint().getHost(), "wowsa"); assertEquals(request.getEndpoint().getPort(), 8001); @@ -764,7 +795,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCreatePostRequest() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPost.class.getMethod("post", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("data")); + GeneratedHttpRequest request = processor(TestPost.class).createRequest(method, ImmutableList. of("data")); assertRequestLineEquals(request, "POST http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); @@ -773,7 +804,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCreatePostRequestNullOk1() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPost.class.getMethod("post", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestPost.class).createRequest(method, ImmutableList.of()); assertRequestLineEquals(request, "POST http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); @@ -782,7 +813,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCreatePostRequestNullOk2() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPost.class.getMethod("post", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, Lists. newArrayList((String) null)); + GeneratedHttpRequest request = processor(TestPost.class).createRequest(method, + Lists. newArrayList((String) null)); assertRequestLineEquals(request, "POST http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); @@ -792,7 +824,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCreatePostRequestNullNotOk1() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPost.class.getMethod("postNonnull", String.class)); try { - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestPost.class).createRequest(method, ImmutableList.of()); Assert.fail("call should have failed with illegal null parameter, not permitted " + request + " to be created"); } catch (NullPointerException e) { Assert.assertTrue(e.toString().indexOf("postNonnull parameter 1") >= 0, @@ -803,12 +835,12 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "postNonnull parameter 1") public void testCreatePostRequestNullNotOk2() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPost.class.getMethod("postNonnull", String.class)); - processor.createRequest(method, Lists. newArrayList((String) null)); + processor(TestPost.class).createRequest(method, Lists. newArrayList((String) null)); } public void testCreatePostJsonRequest() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPost.class.getMethod("postAsJson", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("data")); + GeneratedHttpRequest request = processor(TestPost.class).createRequest(method, ImmutableList. of("data")); assertRequestLineEquals(request, "POST http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); @@ -817,25 +849,26 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCreatePostWithPathRequest() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPost.class.getMethod("postWithPath", String.class, MapBinder.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("data", new org.jclouds.rest.MapBinder() { - @Override - public R bindToRequest(R request, Map postParams) { - request.setPayload((String) postParams.get("fooble")); - return request; - } + GeneratedHttpRequest request = processor(TestPost.class).createRequest(method, + ImmutableList. of("data", new org.jclouds.rest.MapBinder() { + @Override + public R bindToRequest(R request, Map postParams) { + request.setPayload((String) postParams.get("fooble")); + return request; + } - @Override - public R bindToRequest(R request, Object toBind) { - throw new RuntimeException("this shouldn't be used in POST"); - } - })); + @Override + public R bindToRequest(R request, Object toBind) { + throw new RuntimeException("this shouldn't be used in POST"); + } + })); assertRequestLineEquals(request, "POST http://localhost:9999/data HTTP/1.1"); assertPayloadEquals(request, "data", "application/unknown", false); } public void testCreatePostWithMethodBinder() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPost.class.getMethod("postWithMethodBinder", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("data")); + GeneratedHttpRequest request = processor(TestPost.class).createRequest(method, ImmutableList. of("data")); assertRequestLineEquals(request, "POST http://localhost:9999/data HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); @@ -843,8 +876,9 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { } public void testCreatePostWithMethodBinderAndDefaults() throws SecurityException, NoSuchMethodException, IOException { - Invokable method = Invokable.from(TestPost.class.getMethod("postWithMethodBinderAndDefaults", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("data")); + Invokable method = Invokable + .from(TestPost.class.getMethod("postWithMethodBinderAndDefaults", String.class)); + GeneratedHttpRequest request = processor(TestPost.class).createRequest(method, ImmutableList. of("data")); assertRequestLineEquals(request, "POST http://localhost:9999/data HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); @@ -853,7 +887,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCreatePostWithPayload() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPost.class.getMethod("testPayload", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("data")); + GeneratedHttpRequest request = processor(TestPost.class).createRequest(method, ImmutableList. of("data")); assertRequestLineEquals(request, "POST http://localhost:9999/data HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); @@ -882,8 +916,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testMultipartWithStringPart() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestMultipartForm.class.getMethod("withStringPart", String.class)); - GeneratedHttpRequest httpRequest = processor.createRequest(method,ImmutableList. of( - "foobledata")); + GeneratedHttpRequest httpRequest = processor(TestMultipartForm.class).createRequest(method, + ImmutableList. of("foobledata")); assertRequestLineEquals(httpRequest, "POST http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(httpRequest, ""); assertPayloadEquals(httpRequest,// @@ -897,12 +931,13 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "fooble") public void testMultipartWithStringPartNullNotOkay() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestMultipartForm.class.getMethod("withStringPart", String.class)); - processor.createRequest(method, Lists. newArrayList((String) null)); + processor(TestMultipartForm.class).createRequest(method, Lists. newArrayList((String) null)); } public void testMultipartWithParamStringPart() throws SecurityException, NoSuchMethodException, IOException { - Invokable method = Invokable.from(TestMultipartForm.class.getMethod("withParamStringPart", String.class, String.class)); - GeneratedHttpRequest httpRequest = processor.createRequest(method, + Invokable method = Invokable.from(TestMultipartForm.class.getMethod("withParamStringPart", String.class, + String.class)); + GeneratedHttpRequest httpRequest = processor(TestMultipartForm.class).createRequest(method, ImmutableList. of("name", "foobledata")); assertRequestLineEquals(httpRequest, "POST http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(httpRequest, ""); @@ -920,17 +955,19 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "param\\{name\\} for invocation TestMultipartForm.withParamStringPart") public void testMultipartWithParamStringPartNullNotOk() throws SecurityException, NoSuchMethodException, IOException { - Invokable method = Invokable.from(TestMultipartForm.class.getMethod("withParamStringPart", String.class, String.class)); - processor.createRequest(method, Lists. newArrayList(null, "foobledata")); + Invokable method = Invokable.from(TestMultipartForm.class.getMethod("withParamStringPart", String.class, + String.class)); + processor(TestMultipartForm.class).createRequest(method, Lists. newArrayList(null, "foobledata")); } public void testMultipartWithParamFilePart() throws SecurityException, NoSuchMethodException, IOException { - Invokable method = Invokable.from(TestMultipartForm.class.getMethod("withParamFilePart", String.class, File.class)); + Invokable method = Invokable.from(TestMultipartForm.class.getMethod("withParamFilePart", String.class, + File.class)); File file = File.createTempFile("foo", "bar"); Files.append("foobledata", file, UTF_8); file.deleteOnExit(); - GeneratedHttpRequest httpRequest = processor.createRequest(method, + GeneratedHttpRequest httpRequest = processor(TestMultipartForm.class).createRequest(method, ImmutableList. of("name", file)); assertRequestLineEquals(httpRequest, "POST http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(httpRequest, ""); @@ -947,8 +984,9 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { } public void testMultipartWithParamByteArrayPart() throws SecurityException, NoSuchMethodException, IOException { - Invokable method = Invokable.from(TestMultipartForm.class.getMethod("withParamByteArrayBinaryPart", String.class, byte[].class)); - GeneratedHttpRequest httpRequest = processor.createRequest(method, + Invokable method = Invokable.from(TestMultipartForm.class.getMethod("withParamByteArrayBinaryPart", + String.class, byte[].class)); + GeneratedHttpRequest httpRequest = processor(TestMultipartForm.class).createRequest(method, ImmutableList. of("name", "goo".getBytes())); assertRequestLineEquals(httpRequest, "POST http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(httpRequest, ""); @@ -966,12 +1004,13 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { }; public void testMultipartWithParamFileBinaryPart() throws SecurityException, NoSuchMethodException, IOException { - Invokable method = Invokable.from(TestMultipartForm.class.getMethod("withParamFileBinaryPart", String.class, File.class)); + Invokable method = Invokable.from(TestMultipartForm.class.getMethod("withParamFileBinaryPart", + String.class, File.class)); File file = File.createTempFile("foo", "bar"); Files.write(new byte[] { 17, 26, 39, 40, 50 }, file); file.deleteOnExit(); - GeneratedHttpRequest httpRequest = processor.createRequest(method, + GeneratedHttpRequest httpRequest = processor(TestMultipartForm.class).createRequest(method, ImmutableList. of("name", file)); assertRequestLineEquals(httpRequest, "POST http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(httpRequest, ""); @@ -1101,7 +1140,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testAlternateHttpMethod() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPut.class.getMethod("rowdy", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("data")); + GeneratedHttpRequest request = processor(TestPut.class).createRequest(method, ImmutableList. of("data")); assertRequestLineEquals(request, "ROWDY http://localhost:9999/strings/data HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); @@ -1110,7 +1149,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testAlternateHttpMethodSameArity() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPut.class.getMethod("rowdy", int.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("data")); + GeneratedHttpRequest request = processor(TestPut.class).createRequest(method, ImmutableList. of("data")); assertRequestLineEquals(request, "ROWDY http://localhost:9999/ints/data HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); @@ -1119,7 +1158,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCreatePutWithMethodBinder() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPut.class.getMethod("putWithMethodBinder", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("data")); + GeneratedHttpRequest request = processor(TestPut.class).createRequest(method, ImmutableList. of("data")); assertRequestLineEquals(request, "PUT http://localhost:9999/data HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); @@ -1128,7 +1167,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCreatePutWithMethodProduces() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPut.class.getMethod("putWithMethodBinderProduces", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("data")); + GeneratedHttpRequest request = processor(TestPut.class).createRequest(method, ImmutableList. of("data")); assertRequestLineEquals(request, "PUT http://localhost:9999/data HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); @@ -1138,34 +1177,31 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @SuppressWarnings("unchecked") public void testCreatePutWithMethodConsumes() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPut.class.getMethod("putWithMethodBinderConsumes", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("data")); + GeneratedHttpRequest request = processor(TestPut.class).createRequest(method, ImmutableList. of("data")); assertRequestLineEquals(request, "PUT http://localhost:9999/data HTTP/1.1"); assertNonPayloadHeadersEqual(request, "Accept: application/json\n"); assertPayloadEquals(request, "{\"fooble\":\"data\"}", "application/json", false); assertResponseParserClassEquals(method, request, ParseJson.class); - // now test that it works! + Function parser = transformer(TestPut.class).apply(request); - Function parser = (Function) TransformerForRequest - .createResponseParser(parserFactory, injector, request); - - assertEquals(parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload("{ foo:\"bar\"}").build()).foo, "bar"); + assertEquals( + View.class.cast(parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload("{ foo:\"bar\"}").build())).foo, + "bar"); } @SuppressWarnings("unchecked") public void testGeneric1() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPut.class.getMethod("testGeneric")); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestPut.class).createRequest(method, ImmutableList.of()); assertResponseParserClassEquals(method, request, ParseJson.class); - // now test that it works! + Function parser = transformer(TestPut.class).apply(request); - Function> parser = (Function>) TransformerForRequest - .createResponseParser(parserFactory, injector, request); - - assertEquals(parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload("{ foo:\"bar\"}").build()), + assertEquals( + parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload("{ foo:\"bar\"}").build()), ImmutableMap.of("foo", "bar")); } @@ -1173,15 +1209,13 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @SuppressWarnings("unchecked") public void testGeneric2() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPut.class.getMethod("testGeneric2")); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestPut.class).createRequest(method, ImmutableList.of()); assertResponseParserClassEquals(method, request, ParseJson.class); - // now test that it works! + Function parser = transformer(TestPut.class).apply(request); - Function> parser = (Function>) TransformerForRequest - .createResponseParser(parserFactory, injector, request); - - assertEquals(parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload("{ foo:\"bar\"}").build()), + assertEquals( + parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload("{ foo:\"bar\"}").build()), ImmutableMap.of("foo", "bar")); } @@ -1189,15 +1223,13 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @SuppressWarnings("unchecked") public void testGeneric3() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPut.class.getMethod("testGeneric3")); - GeneratedHttpRequest request = processor.createRequest(method ,ImmutableList.of()); + GeneratedHttpRequest request = processor(TestPut.class).createRequest(method, ImmutableList.of()); assertResponseParserClassEquals(method, request, ParseJson.class); - // now test that it works! + Function parser = transformer(TestPut.class).apply(request); - Function> parser = (Function>) TransformerForRequest - .createResponseParser(parserFactory, injector, request); - - assertEquals(parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload("{ foo:\"bar\"}").build()), + assertEquals( + parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload("{ foo:\"bar\"}").build()), ImmutableMap.of("foo", "bar")); } @@ -1205,111 +1237,98 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @SuppressWarnings("unchecked") public void testUnwrap1() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPut.class.getMethod("testUnwrap")); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestPut.class).createRequest(method, ImmutableList.of()); assertResponseParserClassEquals(method, request, UnwrapOnlyJsonValue.class); - // now test that it works! + Function parser = transformer(TestPut.class).apply(request); - Function> parser = (Function>) TransformerForRequest - .createResponseParser(parserFactory, injector, request); - - assertEquals(parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload("{ foo:\"bar\"}").build()), "bar"); + assertEquals( + parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload("{ foo:\"bar\"}").build()), "bar"); } @SuppressWarnings("unchecked") public void testUnwrapValueNamed() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPut.class.getMethod("testUnwrapValueNamed")); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestPut.class).createRequest(method, ImmutableList.of()); assertResponseParserClassEquals(method, request, ParseFirstJsonValueNamed.class); - // now test that it works! + Function parser = transformer(TestPut.class).apply(request); - Function> parser = (Function>) TransformerForRequest - .createResponseParser(parserFactory, injector, request); - - assertEquals(parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload("{ foo:\"bar\"}").build()), "bar"); + assertEquals( + parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload("{ foo:\"bar\"}").build()), "bar"); } public void testWrapWith() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPut.class.getMethod("testWrapWith", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("bar")); + GeneratedHttpRequest request = processor(TestPut.class).createRequest(method, ImmutableList. of("bar")); assertPayloadEquals(request, "{\"foo\":\"bar\"}", "application/json", false); } @SuppressWarnings("unchecked") public void testUnwrap2() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPut.class.getMethod("testUnwrap2")); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestPut.class).createRequest(method, ImmutableList.of()); assertResponseParserClassEquals(method, request, UnwrapOnlyJsonValue.class); - // now test that it works! + Function parser = transformer(TestPut.class).apply(request); - Function> parser = (Function>) TransformerForRequest - .createResponseParser(parserFactory, injector, request); - - assertEquals(parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload("{ foo:\"bar\"}").build()), "bar"); + assertEquals( + parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload("{ foo:\"bar\"}").build()), "bar"); } @SuppressWarnings("unchecked") public void testUnwrap3() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPut.class.getMethod("testUnwrap3")); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestPut.class).createRequest(method, ImmutableList.of()); assertResponseParserClassEquals(method, request, UnwrapOnlyJsonValue.class); - // now test that it works! + Function parser = transformer(TestPut.class).apply(request); - Function> parser = (Function>) TransformerForRequest - .createResponseParser(parserFactory, injector, request); - - assertEquals(parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload("{\"runit\":[\"0.7.0\",\"0.7.1\"]}").build()), - ImmutableSet.of("0.7.0", "0.7.1")); + assertEquals( + parser.apply(HttpResponse.builder().statusCode(200).message("ok") + .payload("{\"runit\":[\"0.7.0\",\"0.7.1\"]}").build()), ImmutableSet.of("0.7.0", "0.7.1")); } @SuppressWarnings("unchecked") public void testUnwrap4() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPut.class.getMethod("testUnwrap4")); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestPut.class).createRequest(method, ImmutableList.of()); assertResponseParserClassEquals(method, request, UnwrapOnlyJsonValue.class); - // now test that it works! + Function parser = transformer(TestPut.class).apply(request); - Function> parser = (Function>) TransformerForRequest - .createResponseParser(parserFactory, injector, request); - - assertEquals(parser.apply(HttpResponse.builder().statusCode(200).message("ok").payload("{\"runit\":[\"0.7.0\",\"0.7.1\"]}").build()), - ImmutableSet.of("0.7.0", "0.7.1")); + assertEquals( + parser.apply(HttpResponse.builder().statusCode(200).message("ok") + .payload("{\"runit\":[\"0.7.0\",\"0.7.1\"]}").build()), ImmutableSet.of("0.7.0", "0.7.1")); } @SuppressWarnings("unchecked") public void selectLong() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPut.class.getMethod("selectLong")); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestPut.class).createRequest(method, ImmutableList.of()); assertResponseParserClassEquals(method, request, ParseFirstJsonValueNamed.class); - // now test that it works! + Function parser = transformer(TestPut.class).apply(request); - Function> parser = (Function>) TransformerForRequest - .createResponseParser(parserFactory, injector, request); - - assertEquals(parser.apply(HttpResponse.builder().statusCode(200).message("ok") - .payload("{ \"destroyvirtualmachineresponse\" : {\"jobid\":4} }").build()), Long.valueOf(4)); + assertEquals( + parser.apply(HttpResponse.builder().statusCode(200).message("ok") + .payload("{ \"destroyvirtualmachineresponse\" : {\"jobid\":4} }").build()), Long.valueOf(4)); } @SuppressWarnings("unchecked") public void selectLongAddOne() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPut.class.getMethod("selectLongAddOne")); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestPut.class).createRequest(method, ImmutableList.of()); + Function parser = transformer(TestPut.class).apply(request); - Function> parser = (Function>) TransformerForRequest - .createResponseParser(parserFactory, injector, request); - - assertEquals(parser.apply(HttpResponse.builder().statusCode(200).message("ok") - .payload("{ \"destroyvirtualmachineresponse\" : {\"jobid\":4} }").build()), Long.valueOf(5)); + assertEquals( + parser.apply(HttpResponse.builder().statusCode(200).message("ok") + .payload("{ \"destroyvirtualmachineresponse\" : {\"jobid\":4} }").build()), Long.valueOf(5)); } - + static class TestRequestFilter1 implements HttpRequestFilter { public HttpRequest filter(HttpRequest request) throws HttpException { return request; @@ -1341,7 +1360,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testRequestFilter() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestRequestFilter.class.getMethod("get")); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestRequestFilter.class).createRequest(method, ImmutableList.of()); assertEquals(request.getFilters().size(), 2); assertEquals(request.getFilters().get(0).getClass(), TestRequestFilter1.class); assertEquals(request.getFilters().get(1).getClass(), TestRequestFilter2.class); @@ -1349,23 +1368,23 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testRequestFilterOverride() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestRequestFilter.class.getMethod("getOverride")); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList.of()); + GeneratedHttpRequest request = processor(TestRequestFilter.class).createRequest(method, ImmutableList.of()); assertEquals(request.getFilters().size(), 1); assertEquals(request.getFilters().get(0).getClass(), TestRequestFilter2.class); } public void testRequestFilterOverrideOnRequest() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestRequestFilter.class.getMethod("getOverride", HttpRequest.class)); - GeneratedHttpRequest request = processor.createRequest( - method, ImmutableList. of( - HttpRequest.builder().method("GET").endpoint("http://localhost") + GeneratedHttpRequest request = processor(TestRequestFilter.class).createRequest( + method, + ImmutableList. of(HttpRequest.builder().method("GET").endpoint("http://localhost") .addHeader("foo", "bar").build())); assertEquals(request.getFilters().size(), 1); assertEquals(request.getHeaders().size(), 1); assertEquals(request.getFilters().get(0).getClass(), TestRequestFilter2.class); } - public class TestEncoding { + public class TestEncoding { @GET @Path("/{path1}/{path2}") public void twoPaths(@PathParam("path1") String path, @PathParam("path2") String path2) { @@ -1375,7 +1394,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testSkipEncoding() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestEncoding.class.getMethod("twoPaths", String.class, String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("1", "localhost")); + GeneratedHttpRequest request = processor(TestEncoding.class).createRequest(method, + ImmutableList. of("1", "localhost")); assertEquals(request.getEndpoint().getPath(), "/1/localhost"); assertEquals(request.getMethod(), HttpMethod.GET); assertEquals(request.getHeaders().size(), 0); @@ -1384,13 +1404,14 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testEncodingPath() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestEncoding.class.getMethod("twoPaths", String.class, String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("/", "localhost" )); + GeneratedHttpRequest request = processor(TestEncoding.class).createRequest(method, + ImmutableList. of("/", "localhost")); assertEquals(request.getEndpoint().getPath(), "///localhost"); assertEquals(request.getMethod(), HttpMethod.GET); assertEquals(request.getHeaders().size(), 0); } - @Path("/v1/{identity}") + @Path("/v1/{identity}") public interface TestConstantPathParam { @Named("testidentity") @PathParam("identity") @@ -1403,8 +1424,9 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test(enabled = false) public void testConstantPathParam() throws SecurityException, NoSuchMethodException, IOException { - Invokable method = Invokable.from(TestConstantPathParam.class.getMethod("twoPaths", String.class, String.class)); - GeneratedHttpRequest request = processor.createRequest(method, + Invokable method = Invokable.from(TestConstantPathParam.class.getMethod("twoPaths", String.class, + String.class)); + GeneratedHttpRequest request = processor(TestConstantPathParam.class).createRequest(method, ImmutableList. of("1", "localhost")); assertRequestLineEquals(request, "GET http://localhost:9999/v1/ralphie/1/localhost HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); @@ -1416,7 +1438,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Path("/{path}") public void onePath(@PathParam("path") String path) { } - + @GET @Path("/{path}") public void onePathNullable(@Nullable @PathParam("path") String path) { @@ -1447,17 +1469,18 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void oneFormParamExtractor(@FormParam("one") @ParamParser(FirstCharacter.class) String one) { } } - + @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "param\\{path\\} for invocation TestPath.onePath") public void testNiceNPEPathParam() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPath.class.getMethod("onePath", String.class)); - processor.createRequest(method, Lists. newArrayList((String) null)); + processor(TestPath.class).createRequest(method, Lists. newArrayList((String) null)); } - + @Test public void testPathParamExtractor() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPath.class.getMethod("onePathParamExtractor", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("localhost")); + GeneratedHttpRequest request = processor(TestPath.class).createRequest(method, + ImmutableList. of("localhost")); assertRequestLineEquals(request, "GET http://localhost:9999/l HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); assertPayloadEquals(request, null, null, false); @@ -1466,25 +1489,27 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testQueryParamExtractor() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPath.class.getMethod("oneQueryParamExtractor", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("localhost")); + GeneratedHttpRequest request = processor(TestPath.class).createRequest(method, + ImmutableList. of("localhost")); assertRequestLineEquals(request, "GET http://localhost:9999/?one=l HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); assertPayloadEquals(request, null, null, false); } - + @Test public void testFormParamExtractor() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPath.class.getMethod("oneFormParamExtractor", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("localhost")); + GeneratedHttpRequest request = processor(TestPath.class).createRequest(method, + ImmutableList. of("localhost")); assertRequestLineEquals(request, "POST http://localhost:9999/ HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); assertPayloadEquals(request, "one=l", "application/x-www-form-urlencoded", false); } - + @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "param\\{one\\} for invocation TestPath.oneFormParamExtractor") public void testNiceNPEFormParam() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPath.class.getMethod("oneFormParamExtractor", String.class)); - processor.createRequest(method, Lists. newArrayList((String) null)); + processor(TestPath.class).createRequest(method, Lists. newArrayList((String) null)); } static class FirstCharacter implements Function { @@ -1508,7 +1533,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @GET @Path("/") - @Headers(keys = { "slash", "hyphen"}, values = { "/{bucket}", "-{bucket}"}) + @Headers(keys = { "slash", "hyphen" }, values = { "/{bucket}", "-{bucket}" }) public void twoHeader(@PathParam("bucket") String path) { } @@ -1527,9 +1552,9 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testBuildTwoHeader() throws SecurityException, NoSuchMethodException { - Invokable method = Invokable.from(TestHeader.class.getMethod("twoHeader", String.class)); - Multimap headers = processor.createRequest(method, ImmutableList. of("robot")) - .getHeaders(); + Invokable method = Invokable.from(TestHeader.class.getMethod("twoHeader", String.class)); + Multimap headers = processor(TestHeader.class).createRequest(method, + ImmutableList. of("robot")).getHeaders(); assertEquals(headers.size(), 2); assertEquals(headers.get("slash"), ImmutableList.of("/robot")); assertEquals(headers.get("hyphen"), ImmutableList.of("-robot")); @@ -1546,7 +1571,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testBuildOneClassHeader() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestClassHeader.class.getMethod("oneHeader", String.class)); - Multimap headers = processor.createRequest(method, + Multimap headers = processor(TestClassHeader.class).createRequest(method, ImmutableList. of("robot")).getHeaders(); assertEquals(headers.size(), 1); assertEquals(headers.get("x-amz-copy-source"), ImmutableList.of("/robot")); @@ -1555,8 +1580,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testBuildOneHeader() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestHeader.class.getMethod("oneHeader", String.class)); - Multimap headers = processor.createRequest(method, ImmutableList. of("robot")) - .getHeaders(); + Multimap headers = processor(TestHeader.class).createRequest(method, + ImmutableList. of("robot")).getHeaders(); assertEquals(headers.size(), 1); assertEquals(headers.get("x-amz-copy-source"), ImmutableList.of("/robot")); } @@ -1564,7 +1589,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testBuildTwoHeaders() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestHeader.class.getMethod("twoHeaders", String.class, String.class)); - Multimap headers = processor.createRequest(method, + Multimap headers = processor(TestHeader.class).createRequest(method, ImmutableList. of("robot", "eggs")).getHeaders(); assertEquals(headers.size(), 1); assertEquals(headers.get("x-amz-copy-source"), ImmutableList.of("/robot/eggs")); @@ -1572,8 +1597,9 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testBuildTwoHeadersOutOfOrder() throws SecurityException, NoSuchMethodException { - Invokable method = Invokable.from(TestHeader.class.getMethod("twoHeadersOutOfOrder", String.class, String.class)); - Multimap headers = processor.createRequest(method, + Invokable method = Invokable.from(TestHeader.class.getMethod("twoHeadersOutOfOrder", String.class, + String.class)); + Multimap headers = processor(TestHeader.class).createRequest(method, ImmutableList. of("robot", "eggs")).getHeaders(); assertEquals(headers.size(), 1); assertEquals(headers.get("x-amz-copy-source"), ImmutableList.of("/eggs/robot")); @@ -1587,13 +1613,15 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testQueryInOptions() throws SecurityException, NoSuchMethodException { - Invokable method = Invokable.from(TestQueryReplace.class.getMethod("queryInOptions", String.class, TestReplaceQueryOptions.class)); - String query = processor - .createRequest(method, ImmutableList. of("robot", new TestReplaceQueryOptions())).getEndpoint().getQuery(); + Invokable method = Invokable.from(TestQueryReplace.class.getMethod("queryInOptions", String.class, + TestReplaceQueryOptions.class)); + String query = processor(TestQueryReplace.class) + .createRequest(method, ImmutableList. of("robot", new TestReplaceQueryOptions())).getEndpoint() + .getQuery(); assertEquals(query, "x-amz-copy-source=/robot"); } - public class TestQueryReplace { + public class TestQueryReplace { @GET @Path("/") @@ -1608,7 +1636,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @GET @Path("/") - @QueryParams(keys = { "slash", "hyphen"}, values = { "/{bucket}", "-{bucket}"}) + @QueryParams(keys = { "slash", "hyphen" }, values = { "/{bucket}", "-{bucket}" }) public void twoQuery(@PathParam("bucket") String path) { } @@ -1628,8 +1656,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testBuildTwoQuery() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestQueryReplace.class.getMethod("twoQuery", String.class)); - String query = processor.createRequest(method, ImmutableList. of("robot")).getEndpoint() - .getQuery(); + String query = processor(TestQueryReplace.class).createRequest(method, ImmutableList. of("robot")) + .getEndpoint().getQuery(); assertEquals(query, "slash=/robot&hyphen=-robot"); } @@ -1644,31 +1672,33 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testBuildOneClassQuery() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestClassQuery.class.getMethod("oneQuery", String.class)); - String query = processor.createRequest(method, ImmutableList. of("robot")).getEndpoint() - .getQuery(); + String query = processor(TestClassQuery.class).createRequest(method, ImmutableList. of("robot")) + .getEndpoint().getQuery(); assertEquals(query, "x-amz-copy-source=/robot"); } @Test public void testBuildOneQuery() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestQueryReplace.class.getMethod("oneQuery", String.class)); - String query = processor.createRequest(method, ImmutableList. of("robot")).getEndpoint() - .getQuery(); + String query = processor(TestQueryReplace.class).createRequest(method, ImmutableList. of("robot")) + .getEndpoint().getQuery(); assertEquals(query, "x-amz-copy-source=/robot"); } @Test public void testBuildTwoQuerys() throws SecurityException, NoSuchMethodException { - Invokable method = Invokable.from(TestQueryReplace.class.getMethod("twoQuerys", String.class, String.class)); - String query = processor.createRequest(method, ImmutableList. of("robot", "eggs")) - .getEndpoint().getQuery(); + Invokable method = Invokable + .from(TestQueryReplace.class.getMethod("twoQuerys", String.class, String.class)); + String query = processor(TestQueryReplace.class) + .createRequest(method, ImmutableList. of("robot", "eggs")).getEndpoint().getQuery(); assertEquals(query, "x-amz-copy-source=/robot/eggs"); } @Test public void testBuildTwoQuerysOutOfOrder() throws SecurityException, NoSuchMethodException { - Invokable method = Invokable.from(TestQueryReplace.class.getMethod("twoQuerysOutOfOrder", String.class, String.class)); - String query = processor + Invokable method = Invokable.from(TestQueryReplace.class.getMethod("twoQuerysOutOfOrder", String.class, + String.class)); + String query = processor(TestQueryReplace.class) .createRequest(method, ImmutableList. of("robot", "eggs")).getEndpoint().getQuery(); assertEquals(query, "x-amz-copy-source=/eggs/robot"); } @@ -1704,8 +1734,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testPutPayloadEnclosing() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestTransformers.class.getMethod("put", PayloadEnclosing.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of( - new PayloadEnclosingImpl(newStringPayload("whoops")))); + GeneratedHttpRequest request = processor(TestTransformers.class).createRequest(method, + ImmutableList. of(new PayloadEnclosingImpl(newStringPayload("whoops")))); assertRequestLineEquals(request, "PUT http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); assertPayloadEquals(request, "whoops", "application/unknown", false); @@ -1715,7 +1745,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { Invokable method = Invokable.from(TestTransformers.class.getMethod("put", PayloadEnclosing.class)); PayloadEnclosing payloadEnclosing = new PayloadEnclosingImpl(newStringPayload("whoops")); calculateMD5(payloadEnclosing); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of(payloadEnclosing)); + GeneratedHttpRequest request = processor(TestTransformers.class).createRequest(method, + ImmutableList. of(payloadEnclosing)); assertRequestLineEquals(request, "PUT http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); @@ -1729,7 +1760,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { newInputStreamPayload(Strings2.toInputStream("whoops"))); calculateMD5(payloadEnclosing); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of(payloadEnclosing)); + GeneratedHttpRequest request = processor(TestTransformers.class).createRequest(method, + ImmutableList. of(payloadEnclosing)); assertRequestLineEquals(request, "PUT http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); @@ -1738,7 +1770,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testPutPayloadChunkedNoContentLength() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestTransformers.class.getMethod("putXfer", Payload.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of(newStringPayload("whoops"))); + GeneratedHttpRequest request = processor(TestTransformers.class).createRequest(method, + ImmutableList. of(newStringPayload("whoops"))); assertRequestLineEquals(request, "PUT http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, "Transfer-Encoding: chunked\n"); assertPayloadEquals(request, "whoops", "application/unknown", false); @@ -1746,7 +1779,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testPutPayload() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestTransformers.class.getMethod("put", Payload.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of(newStringPayload("whoops"))); + GeneratedHttpRequest request = processor(TestTransformers.class).createRequest(method, + ImmutableList. of(newStringPayload("whoops"))); assertRequestLineEquals(request, "PUT http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); assertPayloadEquals(request, "whoops", "application/unknown", false); @@ -1756,7 +1790,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { Invokable method = Invokable.from(TestTransformers.class.getMethod("put", Payload.class)); Payload payload = newStringPayload("whoops"); payload.getContentMetadata().setContentDisposition("attachment; filename=photo.jpg"); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of(payload)); + GeneratedHttpRequest request = processor(TestTransformers.class).createRequest(method, + ImmutableList. of(payload)); assertRequestLineEquals(request, "PUT http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); assertPayloadEquals(request, "whoops", "application/unknown", "attachment; filename=photo.jpg", null, null, false); @@ -1766,7 +1801,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { Invokable method = Invokable.from(TestTransformers.class.getMethod("put", Payload.class)); Payload payload = newStringPayload("whoops"); payload.getContentMetadata().setContentEncoding("gzip"); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of(payload)); + GeneratedHttpRequest request = processor(TestTransformers.class).createRequest(method, + ImmutableList. of(payload)); assertRequestLineEquals(request, "PUT http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); assertPayloadEquals(request, "whoops", "application/unknown", null, "gzip", null, false); @@ -1776,7 +1812,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { Invokable method = Invokable.from(TestTransformers.class.getMethod("put", Payload.class)); Payload payload = newStringPayload("whoops"); payload.getContentMetadata().setContentLanguage("en"); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of(payload)); + GeneratedHttpRequest request = processor(TestTransformers.class).createRequest(method, + ImmutableList. of(payload)); assertRequestLineEquals(request, "PUT http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); assertPayloadEquals(request, "whoops", "application/unknown", null, null, "en", false); @@ -1787,7 +1824,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { Payload payload = newStringPayload("whoops"); calculateMD5(payload); Invokable method = Invokable.from(TestTransformers.class.getMethod("put", Payload.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of(payload)); + GeneratedHttpRequest request = processor(TestTransformers.class).createRequest(method, + ImmutableList. of(payload)); assertRequestLineEquals(request, "PUT http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); assertPayloadEquals(request, "whoops", "application/unknown", true); @@ -1797,7 +1835,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { Payload payload = newInputStreamPayload(Strings2.toInputStream("whoops")); payload.getContentMetadata().setContentLength((long) "whoops".length()); Invokable method = Invokable.from(TestTransformers.class.getMethod("put", Payload.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of(payload)); + GeneratedHttpRequest request = processor(TestTransformers.class).createRequest(method, + ImmutableList. of(payload)); assertRequestLineEquals(request, "PUT http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); assertPayloadEquals(request, "whoops", "application/unknown", false); @@ -1808,7 +1847,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { Payload payload = newStringPayload("whoops"); calculateMD5(payload); Invokable method = Invokable.from(TestTransformers.class.getMethod("put", Payload.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of(payload)); + GeneratedHttpRequest request = processor(TestTransformers.class).createRequest(method, + ImmutableList. of(payload)); assertRequestLineEquals(request, "PUT http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); assertPayloadEquals(request, "whoops", "application/unknown", true); @@ -1816,19 +1856,19 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testInputStreamListenableFuture() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestTransformers.class.getMethod("futureInputStream")); - Class> transformer = unwrap(processor, method); + Class> transformer = unwrap(TestTransformers.class, method); assertEquals(transformer, ReturnInputStream.class); } @SuppressWarnings("unchecked") - public static Class> unwrap(RestAnnotationProcessor processor, Invokable method) { - return (Class>) TransformerForRequest + public Class> unwrap(Class type, Invokable method) { + return (Class>) transformer(type) .getParserOrThrowException(Invocation.create(method, ImmutableList.of())).getTypeLiteral().getRawType(); } public void testURIListenableFuture() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestTransformers.class.getMethod("futureUri")); - Class> transformer = unwrap(processor, method); + Class> transformer = unwrap(TestTransformers.class, method); assertEquals(transformer, ParseURIFromListOrLocationHeaderIf20x.class); } @@ -1844,30 +1884,28 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { } - @Test(expectedExceptions = { RuntimeException.class }) + @Test(expectedExceptions = RuntimeException.class) public void testNoTransformer() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestTransformers.class.getMethod("noTransformer")); - TransformerForRequest.getParserOrThrowException(Invocation.create(method, ImmutableList.of())); + unwrap(TestTransformers.class, method); } public void oneTransformerWithContext() throws SecurityException, NoSuchMethodException { GeneratedHttpRequest request = GeneratedHttpRequest - .builder() + .builder(TypeToken.of(TestTransformers.class)) .method("GET") .endpoint("http://localhost") .invocation( Invocation.create(Invokable.from(TestTransformers.class.getMethod("oneTransformerWithContext")), - ImmutableList.of())) - .build(); - Function transformer = TransformerForRequest.createResponseParser(parserFactory, injector, - request); + ImmutableList.of())).build(); + Function transformer = transformer(TestTransformers.class).apply(request); assertEquals(transformer.getClass(), ReturnStringIf200Context.class); assertEquals(((ReturnStringIf200Context) transformer).request, request); } public void testOneTransformer() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestTransformers.class.getMethod("oneTransformer")); - Class> transformer = unwrap(processor, method); + Class> transformer = unwrap(TestTransformers.class, method); assertEquals(transformer, ReturnStringIf2xx.class); } @@ -1923,8 +1961,10 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCreateGetVarArgOptionsThatProducesHeaders() throws SecurityException, NoSuchMethodException { Date date = new Date(); GetOptions options = GetOptions.Builder.ifModifiedSince(date); - Invokable method = Invokable.from(TestRequest.class.getMethod("get", String.class, HttpRequestOptions[].class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("1", options)); + Invokable method = Invokable.from(TestRequest.class.getMethod("get", String.class, + HttpRequestOptions[].class)); + GeneratedHttpRequest request = processor(TestRequest.class).createRequest(method, + ImmutableList. of("1", options)); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPath(), "/1"); assertEquals(request.getMethod(), HttpMethod.GET); @@ -1937,8 +1977,10 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCreateGetOptionsThatProducesHeaders() throws SecurityException, NoSuchMethodException { Date date = new Date(); GetOptions options = GetOptions.Builder.ifModifiedSince(date); - Invokable method = Invokable.from(TestRequest.class.getMethod("get", String.class, HttpRequestOptions.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("1", options)); + Invokable method = Invokable.from(TestRequest.class + .getMethod("get", String.class, HttpRequestOptions.class)); + GeneratedHttpRequest request = processor(TestRequest.class).createRequest(method, + ImmutableList. of("1", options)); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPath(), "/1"); assertEquals(request.getMethod(), HttpMethod.GET); @@ -1957,8 +1999,10 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCreateGetOptionsThatProducesQuery() throws SecurityException, NoSuchMethodException, IOException { PrefixOptions options = new PrefixOptions().withPrefix("1"); - Invokable method = Invokable.from(TestRequest.class.getMethod("get", String.class, HttpRequestOptions.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("1", options)); + Invokable method = Invokable.from(TestRequest.class + .getMethod("get", String.class, HttpRequestOptions.class)); + GeneratedHttpRequest request = processor(TestRequest.class).createRequest(method, + ImmutableList. of("1", options)); assertRequestLineEquals(request, "GET http://localhost:9999/1?prefix=1 HTTP/1.1"); assertNonPayloadHeadersEqual(request, "Host: localhost:9999\n"); assertPayloadEquals(request, null, null, false); @@ -1966,7 +2010,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCreateGetQuery() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestRequest.class.getMethod("getQuery", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("1")); + GeneratedHttpRequest request = processor(TestRequest.class).createRequest(method, ImmutableList. of("1")); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPath(), "/1"); assertEquals(request.getEndpoint().getQuery(), "max-keys=0"); @@ -1976,7 +2020,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCreateGetQueryNull() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestRequest.class.getMethod("getQueryNull", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("1")); + GeneratedHttpRequest request = processor(TestRequest.class).createRequest(method, ImmutableList. of("1")); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPath(), "/1"); assertEquals(request.getEndpoint().getQuery(), "acl"); @@ -1986,7 +2030,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCreateGetQueryEmpty() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestRequest.class.getMethod("getQueryEmpty", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("1")); + GeneratedHttpRequest request = processor(TestRequest.class).createRequest(method, ImmutableList. of("1")); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPath(), "/1"); assertEquals(request.getEndpoint().getQuery(), "acl="); @@ -2003,8 +2047,10 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCreateGetOptionsThatProducesPayload() throws SecurityException, NoSuchMethodException, IOException { PayloadOptions options = new PayloadOptions(); - Invokable method = Invokable.from(TestRequest.class.getMethod("putOptions", String.class, HttpRequestOptions.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("1", options)); + Invokable method = Invokable.from(TestRequest.class.getMethod("putOptions", String.class, + HttpRequestOptions.class)); + GeneratedHttpRequest request = processor(TestRequest.class).createRequest(method, + ImmutableList. of("1", options)); assertRequestLineEquals(request, "PUT http://localhost:9999/1 HTTP/1.1"); assertNonPayloadHeadersEqual(request, "Host: localhost:9999\n"); @@ -2020,7 +2066,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCreateGetRequest(String key) throws SecurityException, NoSuchMethodException, UnsupportedEncodingException { Invokable method = Invokable.from(TestRequest.class.getMethod("get", String.class, String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of(key, "localhost")); + GeneratedHttpRequest request = processor(TestRequest.class).createRequest(method, + ImmutableList. of(key, "localhost")); assertEquals(request.getEndpoint().getHost(), "localhost"); String expectedPath = "/" + URLEncoder.encode(key, "UTF-8").replaceAll("\\+", "%20"); assertEquals(request.getEndpoint().getRawPath(), expectedPath); @@ -2032,7 +2079,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCreatePutRequest() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestRequest.class.getMethod("put", String.class, String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("111", "data")); + GeneratedHttpRequest request = processor(TestRequest.class).createRequest(method, + ImmutableList. of("111", "data")); assertRequestLineEquals(request, "PUT http://localhost:9999/1 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); @@ -2041,7 +2089,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testCreatePutHeader() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestRequest.class.getMethod("putHeader", String.class, String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("1", "data")); + GeneratedHttpRequest request = processor(TestRequest.class).createRequest(method, + ImmutableList. of("1", "data")); assertRequestLineEquals(request, "PUT http://localhost:9999/1 HTTP/1.1"); assertNonPayloadHeadersEqual(request, "foo: --1--\n"); @@ -2060,7 +2109,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testVirtualHostMethod() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestVirtualHostMethod.class.getMethod("get", String.class, String.class)); - GeneratedHttpRequest request = processor.createRequest(method, + GeneratedHttpRequest request = processor(TestVirtualHostMethod.class).createRequest(method, ImmutableList. of("1", "localhost")); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPath(), "/1"); @@ -2084,7 +2133,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testVirtualHost() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestVirtualHost.class.getMethod("get", String.class, String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("1", "localhost")); + GeneratedHttpRequest request = processor(TestVirtualHost.class).createRequest(method, + ImmutableList. of("1", "localhost")); assertEquals(request.getEndpoint().getHost(), "localhost"); assertEquals(request.getEndpoint().getPath(), "/1"); assertEquals(request.getMethod(), HttpMethod.GET); @@ -2095,7 +2145,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testHostPrefix() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestVirtualHost.class.getMethod("getPrefix", String.class, String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("1", "holy")); + GeneratedHttpRequest request = processor(TestVirtualHost.class).createRequest(method, + ImmutableList. of("1", "holy")); assertEquals(request.getEndpoint().getHost(), "holy.localhost"); assertEquals(request.getEndpoint().getPath(), "/1"); assertEquals(request.getMethod(), HttpMethod.GET); @@ -2105,7 +2156,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test(expectedExceptions = IllegalArgumentException.class) public void testHostPrefixEmpty() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestVirtualHost.class.getMethod("getPrefix", String.class, String.class)); - processor.createRequest(method, ImmutableList. of("1", "")); + processor(TestVirtualHost.class).createRequest(method, ImmutableList. of("1", "")); } public interface TestHeaders { @@ -2125,7 +2176,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testOneHeader() throws SecurityException, NoSuchMethodException, ExecutionException { Invokable method = Invokable.from(TestHeaders.class.getMethod("oneHeader", String.class)); - Multimap headers = processor.createRequest(method, + Multimap headers = processor(TestHeaders.class).createRequest(method, ImmutableList. of("robot")).getHeaders(); assertEquals(headers.size(), 1); assertEquals(headers.get("header"), ImmutableList.of("robot")); @@ -2134,17 +2185,18 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testOneIntHeader() throws SecurityException, NoSuchMethodException, ExecutionException { Invokable method = Invokable.from(TestHeaders.class.getMethod("oneIntHeader", int.class)); - Multimap headers = processor.createRequest(method, - ImmutableList. of(1)).getHeaders(); + Multimap headers = processor(TestHeaders.class).createRequest(method, + ImmutableList. of(1)).getHeaders(); assertEquals(headers.size(), 1); assertEquals(headers.get("header"), ImmutableList.of("1")); } @Test public void testTwoDifferentHeaders() throws SecurityException, NoSuchMethodException, ExecutionException { - Invokable method = Invokable.from(TestHeaders.class.getMethod("twoDifferentHeaders", String.class, String.class)); - Multimap headers = processor.createRequest(method, - ImmutableList. of("robot", "egg")).getHeaders(); + Invokable method = Invokable.from(TestHeaders.class.getMethod("twoDifferentHeaders", String.class, + String.class)); + Multimap headers = processor(TestHeaders.class).createRequest(method, + ImmutableList. of("robot", "egg")).getHeaders(); assertEquals(headers.size(), 2); assertEquals(headers.get("header1"), ImmutableList.of("robot")); assertEquals(headers.get("header2"), ImmutableList.of("egg")); @@ -2152,9 +2204,10 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testTwoSameHeaders() throws SecurityException, NoSuchMethodException, ExecutionException { - Invokable method = Invokable.from(TestHeaders.class.getMethod("twoSameHeaders", String.class, String.class)); - Multimap headers = processor.createRequest(method, - ImmutableList. of("robot", "egg")).getHeaders(); + Invokable method = Invokable + .from(TestHeaders.class.getMethod("twoSameHeaders", String.class, String.class)); + Multimap headers = processor(TestHeaders.class).createRequest(method, + ImmutableList. of("robot", "egg")).getHeaders(); assertEquals(headers.size(), 2); Collection values = headers.get("header"); assert values.contains("robot"); @@ -2226,7 +2279,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testPut() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPayload.class.getMethod("put", String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("test")); + GeneratedHttpRequest request = processor(TestPayload.class).createRequest(method, + ImmutableList. of("test")); assertRequestLineEquals(request, "PUT http://localhost:9999 HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); @@ -2236,7 +2290,8 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void putWithPath() throws SecurityException, NoSuchMethodException, IOException { Invokable method = Invokable.from(TestPayload.class.getMethod("putWithPath", String.class, String.class)); - GeneratedHttpRequest request = processor.createRequest(method, ImmutableList. of("rabble", "test")); + GeneratedHttpRequest request = processor(TestPayload.class).createRequest(method, + ImmutableList. of("rabble", "test")); assertRequestLineEquals(request, "PUT http://localhost:9999/rabble HTTP/1.1"); assertNonPayloadHeadersEqual(request, ""); @@ -2249,7 +2304,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { } } - public class TestFormReplace { + public class TestFormReplace { @POST @Path("/") @@ -2264,7 +2319,7 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @POST @Path("/") - @FormParams(keys = { "slash", "hyphen"}, values = { "/{bucket}", "-{bucket}"}) + @FormParams(keys = { "slash", "hyphen" }, values = { "/{bucket}", "-{bucket}" }) public void twoForm(@PathParam("bucket") String path) { } @@ -2284,12 +2339,13 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Test public void testBuildTwoForm() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestFormReplace.class.getMethod("twoForm", String.class)); - Object form = processor.createRequest(method, ImmutableList. of("robot")).getPayload().getRawContent(); + Object form = processor(TestFormReplace.class).createRequest(method, ImmutableList. of("robot")) + .getPayload().getRawContent(); assertEquals(form, "slash=/robot&hyphen=-robot"); } @FormParams(keys = "x-amz-copy-source", values = "/{bucket}") - public interface TestClassForm { + public interface TestClassForm { @Provides Set set(); @@ -2304,13 +2360,16 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { @Named("NoSuchElementException") @Provides Set noSuchElementException(); - + @POST @Path("/") void oneForm(@PathParam("bucket") String path); } - static final Key> formKey = Key.get(new TypeLiteral>(){}); + static final Key> formKey = Key + .get(new TypeLiteral>() { + }); + @Test public void testProvidesWithGeneric() throws SecurityException, NoSuchMethodException { Set set = injector.getInstance(formKey).get().set(); @@ -2327,39 +2386,42 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { public void testProvidesWithGenericQualifiedAuthorizationException() throws SecurityException, NoSuchMethodException { injector.getInstance(formKey).get().exception(); } - + @Test(expectedExceptions = NoSuchElementException.class) public void testProvidesWithGenericQualifiedNoSuchElementException() throws SecurityException, NoSuchMethodException { injector.getInstance(formKey).get().noSuchElementException(); } - + @Test public void testBuildOneClassForm() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestClassForm.class.getMethod("oneForm", String.class)); - Object form = processor.createRequest(method, ImmutableList. of("robot")).getPayload().getRawContent(); + Object form = processor(TestClassForm.class).createRequest(method, ImmutableList. of("robot")) + .getPayload().getRawContent(); assertEquals(form, "x-amz-copy-source=/robot"); } @Test public void testBuildOneForm() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestFormReplace.class.getMethod("oneForm", String.class)); - Object form = processor.createRequest(method, ImmutableList. of("robot")).getPayload().getRawContent(); + Object form = processor(TestFormReplace.class).createRequest(method, ImmutableList. of("robot")) + .getPayload().getRawContent(); assertEquals(form, "x-amz-copy-source=/robot"); } @Test public void testBuildTwoForms() throws SecurityException, NoSuchMethodException { Invokable method = Invokable.from(TestFormReplace.class.getMethod("twoForms", String.class, String.class)); - Object form = processor.createRequest(method, ImmutableList. of("robot", "eggs")).getPayload() - .getRawContent(); + Object form = processor(TestFormReplace.class).createRequest(method, ImmutableList. of("robot", "eggs")) + .getPayload().getRawContent(); assertEquals(form, "x-amz-copy-source=/robot/eggs"); } @Test public void testBuildTwoFormsOutOfOrder() throws SecurityException, NoSuchMethodException { - Invokable method = Invokable.from(TestFormReplace.class.getMethod("twoFormsOutOfOrder", String.class, String.class)); - Object form = processor.createRequest(method, ImmutableList. of("robot", "eggs")).getPayload() - .getRawContent(); + Invokable method = Invokable.from(TestFormReplace.class.getMethod("twoFormsOutOfOrder", String.class, + String.class)); + Object form = processor(TestFormReplace.class).createRequest(method, ImmutableList. of("robot", "eggs")) + .getPayload().getRawContent(); assertEquals(form, "x-amz-copy-source=/eggs/robot"); } @@ -2393,11 +2455,10 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { } DateService dateService = new SimpleDateFormatDateService(); - RestAnnotationProcessor processor; - + @BeforeClass void setupFactory() { - injector = ContextBuilder + injector = ContextBuilder .newBuilder( AnonymousProviderMetadata.forClientMappedToAsyncClientOnEndpoint(Callee.class, AsyncCallee.class, "http://localhost:9999")) @@ -2419,16 +2480,14 @@ public class RestAnnotationProcessorTest extends BaseRestApiTest { Set exception() { throw new AuthorizationException(); } - + @Provides @Named("NoSuchElementException") Set noSuchElementException() { throw new NoSuchElementException(); } - + })).buildInjector(); parserFactory = injector.getInstance(ParseSax.Factory.class); - processor = injector.getInstance(RestAnnotationProcessor.class); } - } diff --git a/core/src/test/java/org/jclouds/util/Optionals2Test.java b/core/src/test/java/org/jclouds/util/Optionals2Test.java index 2f6fb4348c..5f156176f4 100644 --- a/core/src/test/java/org/jclouds/util/Optionals2Test.java +++ b/core/src/test/java/org/jclouds/util/Optionals2Test.java @@ -25,7 +25,7 @@ import static org.testng.Assert.assertTrue; import org.testng.annotations.Test; import com.google.common.base.Optional; -import org.jclouds.reflect.Invokable; +import com.google.common.reflect.Invokable; /** * @author Adrian Cole