centralize construction of invokables

This commit is contained in:
Adrian Cole 2013-01-19 17:17:06 -08:00
parent fe220e5105
commit 58f0f577d0
28 changed files with 631 additions and 346 deletions

View File

@ -42,7 +42,7 @@ import static org.jclouds.Constants.PROPERTY_ENDPOINT;
import static org.jclouds.Constants.PROPERTY_IDENTITY;
import static org.jclouds.Constants.PROPERTY_ISO3166_CODES;
import static org.jclouds.Constants.PROPERTY_PROVIDER;
import static org.jclouds.reflect.Reflection2.typeTokenOf;
import static org.jclouds.reflect.Reflection2.typeToken;
import static org.jclouds.util.Throwables2.propagateAuthorizationOrOriginalException;
import java.util.List;
@ -491,7 +491,7 @@ public class ContextBuilder {
// TODO: move this up
if (apiMetadata instanceof RestApiMetadata) {
RestApiMetadata rest = RestApiMetadata.class.cast(apiMetadata);
modules.add(new RestClientModule(typeTokenOf(rest.getApi()), typeTokenOf(rest.getAsyncApi())));
modules.add(new RestClientModule(typeToken(rest.getApi()), typeToken(rest.getAsyncApi())));
} else {
modules.add(new RestModule());
}
@ -568,7 +568,7 @@ public class ContextBuilder {
* @see #buildView(TypeToken)
*/
public <V extends View> V buildView(Class<V> viewType) {
return buildView(typeTokenOf(viewType));
return buildView(typeToken(viewType));
}
/**

View File

@ -21,7 +21,7 @@ package org.jclouds.apis;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.find;
import static org.jclouds.reflect.Reflection2.typeTokenOf;
import static org.jclouds.reflect.Reflection2.typeToken;
import java.util.NoSuchElementException;
import java.util.ServiceLoader;
@ -116,7 +116,7 @@ public class Apis {
}
public static Iterable<ApiMetadata> viewableAs(Class<? extends View> type) {
return filter(all(), ApiPredicates.viewableAs(typeTokenOf(type)));
return filter(all(), ApiPredicates.viewableAs(typeToken(type)));
}
/**

View File

@ -32,7 +32,7 @@ import static org.jclouds.Constants.PROPERTY_SCHEDULER_THREADS;
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
import static org.jclouds.Constants.PROPERTY_SO_TIMEOUT;
import static org.jclouds.Constants.PROPERTY_USER_THREADS;
import static org.jclouds.reflect.Reflection2.typeTokenOf;
import static org.jclouds.reflect.Reflection2.typeToken;
import java.net.URI;
import java.util.Properties;
@ -93,7 +93,7 @@ public abstract class BaseApiMetadata implements ApiMetadata {
private Optional<String> defaultCredential = Optional.absent();
private Properties defaultProperties = BaseApiMetadata.defaultProperties();
private URI documentation;
private TypeToken<? extends Context> context = typeTokenOf(Context.class);
private TypeToken<? extends Context> context = typeToken(Context.class);
private Set<Class<? extends Module>> defaultModules = ImmutableSet.of();
/**
@ -119,7 +119,7 @@ public abstract class BaseApiMetadata implements ApiMetadata {
*/
@Override
public T view(Class<? extends View> view) {
return view(typeTokenOf(checkNotNull(view, "view")));
return view(typeToken(checkNotNull(view, "view")));
}
/**

View File

@ -17,10 +17,9 @@
* under the License.
*/
package org.jclouds.config;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.reflect.Reflection2.typeTokenOf;
import static org.jclouds.reflect.Reflection2.typeToken;
import org.jclouds.rest.RestApiMetadata;
import org.jclouds.rest.RestContext;
@ -50,8 +49,8 @@ public class BindRestContextWithWildcardExtendsExplicitAndRawType extends Abstra
@SuppressWarnings("unchecked")
@Override
protected void configure() {
TypeToken<?> concreteType = BaseRestApiMetadata.contextToken(typeTokenOf(restApiMetadata.getApi()), TypeToken
.of(restApiMetadata.getAsyncApi()));
TypeToken<?> concreteType = BaseRestApiMetadata.contextToken(typeToken(restApiMetadata.getApi()),
typeToken(restApiMetadata.getAsyncApi()));
// bind explicit type
bind(TypeLiteral.get(concreteType.getType())).to(
TypeLiteral.class.cast(TypeLiteral.get(Types.newParameterizedType(RestContextImpl.class,

View File

@ -17,10 +17,9 @@
* under the License.
*/
package org.jclouds.providers;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.find;
import static org.jclouds.reflect.Reflection2.typeTokenOf;
import static org.jclouds.reflect.Reflection2.typeToken;
import java.util.NoSuchElementException;
import java.util.ServiceLoader;
@ -117,7 +116,7 @@ public class Providers {
}
public static Iterable<ProviderMetadata> viewableAs(Class<? extends View> viewableAs) {
return filter(all(), ProviderPredicates.viewableAs(typeTokenOf(viewableAs)));
return filter(all(), ProviderPredicates.viewableAs(typeToken(viewableAs)));
}
/**
@ -179,7 +178,7 @@ public class Providers {
public static Iterable<ProviderMetadata> boundedByIso3166Code(String iso3166Code,
Class<? extends View> viewableAs) {
return boundedByIso3166Code(iso3166Code, typeTokenOf(viewableAs));
return boundedByIso3166Code(iso3166Code, typeToken(viewableAs));
}
/**
@ -215,6 +214,6 @@ public class Providers {
public static Iterable<ProviderMetadata> collocatedWith(ProviderMetadata providerMetadata,
Class<? extends View> viewableAs) {
return collocatedWith(providerMetadata, typeTokenOf(viewableAs));
return collocatedWith(providerMetadata, typeToken(viewableAs));
}
}

View File

@ -24,7 +24,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.notNull;
import static com.google.common.base.Throwables.propagate;
import static com.google.common.collect.Iterables.all;
import static org.jclouds.reflect.Reflection2.typeTokenOf;
import static org.jclouds.reflect.Reflection2.method;
import static org.jclouds.reflect.Reflection2.typeToken;
import static org.jclouds.util.Throwables2.propagateIfPossible;
import java.lang.reflect.Method;
@ -84,8 +85,7 @@ public final class FunctionalReflection {
public static <T> T newProxy(Class<T> enclosingType, Function<Invocation, Object> invocationFunction) {
checkNotNull(invocationFunction, "invocationFunction");
return newProxy(enclosingType,
new FunctionalInvocationHandler<T>(typeTokenOf(enclosingType), invocationFunction));
return newProxy(enclosingType, new FunctionalInvocationHandler<T>(typeToken(enclosingType), invocationFunction));
}
@SuppressWarnings("unchecked")
@ -113,7 +113,7 @@ public final class FunctionalReflection {
args = ImmutableList.copyOf(args);
else
args = Collections.unmodifiableList(args);
Invokable<?, Object> invokable = enclosingType.method(invoked);
Invokable<T, Object> invokable = method(enclosingType, invoked);
Invocation invocation = Invocation.create(invokable, args);
try {
return invocationFunction.apply(invocation);

View File

@ -19,65 +19,196 @@
package org.jclouds.reflect;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.toArray;
import java.lang.reflect.Type;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.reflect.Invokable;
import com.google.common.reflect.TypeToken;
/**
* Invokable utilities
* Utilities that allow access to {@link Invokable}s with {@link Invokable#getOwnerType() owner types}.
*
* @since 1.6
*/
@Beta
public final class Reflection2 {
private static final LoadingCache<Class<?>, TypeToken<?>> typeTokenForClass = CacheBuilder.newBuilder().build(
new CacheLoader<Class<?>, TypeToken<?>>() {
public TypeToken<?> load(final Class<?> key) throws Exception {
return TypeToken.of(key);
}
});
/**
* Cache of type tokens for the supplied class.
*/
public static Function<Class<?>, TypeToken<?>> typeTokenForClass() {
return typeTokenForClass;
}
/**
* Cache of type tokens for the supplied class.
* gets a {@link TypeToken} for the given class.
*/
@SuppressWarnings("unchecked")
public static <T> TypeToken<T> typeTokenOf(Class<T> in) {
public static <T> TypeToken<T> typeToken(Class<T> in) {
return (TypeToken<T>) typeTokenForClass.apply(checkNotNull(in, "class"));
}
private static final LoadingCache<Type, TypeToken<?>> typeTokenForType = CacheBuilder.newBuilder().build(
new CacheLoader<Type, TypeToken<?>>() {
public TypeToken<?> load(final Type key) throws Exception {
/**
* returns an {@link Invokable} object that links the {@code method} to its owner.
*
* @param ownerType
* corresponds to {@link Invokable#getOwnerType()}
* @param method
* present in {@code ownerType}
*/
@SuppressWarnings("unchecked")
public static <T, R> Invokable<T, R> method(TypeToken<T> ownerType, Method method) {
return (Invokable<T, R>) methods.apply(new TypeTokenAndMethod(ownerType, method));
}
/**
* returns an {@link Invokable} object that reflects a method present in the {@link TypeToken} type.
*
* @param ownerType
* corresponds to {@link Invokable#getOwnerType()}
* @param parameterTypes
* corresponds to {@link Method#getParameterTypes()}
*
* @throws IllegalArgumentException
* if the method doesn't exist or a security exception occurred
*/
@SuppressWarnings("unchecked")
public static <T, R> Invokable<T, R> method(Class<T> ownerType, String name, Class<?>... parameterTypes) {
return (Invokable<T, R>) methodForArgs.apply(new TypeTokenNameAndParameterTypes(typeToken(ownerType), name,
parameterTypes));
}
/**
* return all methods present in the class as {@link Invokable}s.
*
* @param ownerType
* corresponds to {@link Invokable#getOwnerType()}
*/
@SuppressWarnings("unchecked")
public static <T> Collection<Invokable<T, Object>> methods(Class<T> ownerType) {
return Collection.class.cast(methodsForTypeToken.apply(typeToken(ownerType)).values());
}
private static final LoadingCache<TypeTokenAndMethod, Invokable<?, ?>> methods = CacheBuilder.newBuilder().build(
new CacheLoader<TypeTokenAndMethod, Invokable<?, ?>>() {
public Invokable<?, ?> load(TypeTokenAndMethod key) {
return key.type.method(key.method);
}
});
private static class TypeTokenAndMethod {
protected final TypeToken<?> type;
protected final Method method;
public TypeTokenAndMethod(TypeToken<?> type, Method method) {
this.type = checkNotNull(type, "type");
this.method = checkNotNull(method, "method");
}
public int hashCode() {
return Objects.hashCode(type, method);
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
TypeTokenAndMethod that = TypeTokenAndMethod.class.cast(obj);
return Objects.equal(this.type, that.type) && Objects.equal(this.method, that.method);
}
}
private static final LoadingCache<Class<?>, TypeToken<?>> typeTokenForClass = CacheBuilder.newBuilder().build(
new CacheLoader<Class<?>, TypeToken<?>>() {
public TypeToken<?> load(final Class<?> key) {
return TypeToken.of(key);
}
});
/**
* Cache of type tokens for the supplied class.
*/
public static Function<Type, TypeToken<?>> typeTokenForType() {
return typeTokenForType;
private static class TypeTokenAndParameterTypes {
protected final TypeToken<?> type;
protected final List<Class<?>> parameterTypes;
public TypeTokenAndParameterTypes(TypeToken<?> type, Class<?>... parameterTypes) {
this.type = checkNotNull(type, "type");
this.parameterTypes = Arrays.asList(checkNotNull(parameterTypes, "parameterTypes"));
}
public int hashCode() {
return Objects.hashCode(type, parameterTypes);
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
TypeTokenAndParameterTypes that = TypeTokenAndParameterTypes.class.cast(obj);
return Objects.equal(this.type, that.type) && Objects.equal(this.parameterTypes, that.parameterTypes);
}
public String toString() {
return Objects.toStringHelper("").add("type", type).add("parameterTypes", parameterTypes).toString();
}
}
/**
* Cache of type tokens for the supplied type.
*/
@SuppressWarnings("unchecked")
public static <T> TypeToken<T> typeTokenOf(Type in) {
return (TypeToken<T>) typeTokenForType.apply(checkNotNull(in, "class"));
private static final LoadingCache<TypeTokenNameAndParameterTypes, Invokable<?, ?>> methodForArgs = CacheBuilder
.newBuilder().build(new CacheLoader<TypeTokenNameAndParameterTypes, Invokable<?, ?>>() {
public Invokable<?, ?> load(final TypeTokenNameAndParameterTypes key) {
try {
Method method = key.type.getRawType().getMethod(key.name, toArray(key.parameterTypes, Class.class));
return methods.apply(new TypeTokenAndMethod(key.type, method));
} catch (SecurityException e) {
throw new IllegalArgumentException(e.getMessage() + " getting method " + key.toString(), e);
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException("no such method " + key.toString(), e);
}
}
});
private static class TypeTokenNameAndParameterTypes extends TypeTokenAndParameterTypes {
private final String name;
public TypeTokenNameAndParameterTypes(TypeToken<?> type, String name, Class<?>... parameterTypes) {
super(type, parameterTypes);
this.name = checkNotNull(name, "name");
}
public int hashCode() {
return Objects.hashCode(super.hashCode(), name);
}
public boolean equals(Object obj) {
if (super.equals(obj)) {
TypeTokenNameAndParameterTypes that = TypeTokenNameAndParameterTypes.class.cast(obj);
return name.equals(that.name);
}
return false;
}
public String toString() {
return Objects.toStringHelper("").add("type", type).add("name", name).add("parameterTypes", parameterTypes)
.toString();
}
}
private static final LoadingCache<TypeToken<?>, Map<Method, Invokable<?, ?>>> methodsForTypeToken = CacheBuilder
.newBuilder().build(new CacheLoader<TypeToken<?>, Map<Method, Invokable<?, ?>>>() {
public Map<Method, Invokable<?, ?>> load(final TypeToken<?> key) {
Builder<Method, Invokable<?, ?>> builder = ImmutableMap.<Method, Invokable<?, ?>> builder();
for (Method method : key.getRawType().getMethods())
builder.put(method, method(key, method));
return builder.build();
}
});
}

View File

@ -18,7 +18,6 @@
*/
package org.jclouds.rest.config;
import static org.jclouds.reflect.Reflection2.typeTokenOf;
import java.lang.reflect.Proxy;
@ -47,7 +46,7 @@ public class CallGetOnFuturesProvider<S, A> implements Provider<S> {
Class<A> asyncApiType) {
this.syncInvoker = syncInvoker;
this.apiType = apiType;
RestModule.putInvokables(typeTokenOf(apiType), typeTokenOf(asyncApiType), invokables);
RestModule.putInvokables(apiType, asyncApiType, invokables);
}
@SuppressWarnings("unchecked")

View File

@ -18,7 +18,6 @@
*/
package org.jclouds.rest.config;
import static org.jclouds.reflect.Reflection2.typeTokenOf;
import java.lang.reflect.Proxy;
@ -46,7 +45,7 @@ public class HttpApiProvider<S, A> implements Provider<S> {
DelegatesToInvocationFunction<S, InvokeHttpMethod> httpInvoker, Class<S> apiType, Class<A> asyncApiType) {
this.httpInvoker = httpInvoker;
this.apiType = apiType;
RestModule.putInvokables(typeTokenOf(apiType), typeTokenOf(asyncApiType), invokables);
RestModule.putInvokables(apiType, asyncApiType, invokables);
}
@SuppressWarnings("unchecked")

View File

@ -19,18 +19,21 @@
package org.jclouds.rest.config;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Throwables.propagate;
import static com.google.common.collect.Iterables.toArray;
import static com.google.common.collect.Iterables.transform;
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.reflect.Reflection2.typeTokenOf;
import static org.jclouds.reflect.Reflection2.method;
import static org.jclouds.reflect.Reflection2.methods;
import static org.jclouds.rest.config.BinderUtils.bindHttpApi;
import static org.jclouds.util.Maps2.transformKeys;
import static org.jclouds.util.Predicates2.startsWith;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
@ -57,7 +60,7 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.Invokable;
import com.google.common.reflect.TypeToken;
import com.google.common.reflect.Parameter;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
@ -80,7 +83,7 @@ public class RestModule extends AbstractModule {
public RestModule(Map<Class<?>, Class<?>> sync2Async) {
this.sync2Async = sync2Async;
}
/**
* seeds well-known invokables.
*/
@ -88,33 +91,42 @@ public class RestModule extends AbstractModule {
@Singleton
protected Cache<Invokable<?, ?>, Invokable<?, ?>> seedKnownSync2AsyncInvokables() {
Cache<Invokable<?, ?>, Invokable<?, ?>> sync2AsyncBuilder = CacheBuilder.newBuilder().build();
putInvokables(typeTokenOf(HttpClient.class), typeTokenOf(HttpAsyncClient.class), sync2AsyncBuilder);
putInvokables(HttpClient.class, HttpAsyncClient.class, sync2AsyncBuilder);
for (Class<?> s : sync2Async.keySet()) {
putInvokables(typeTokenOf(s), typeTokenOf(sync2Async.get(s)), sync2AsyncBuilder);
putInvokables(s, sync2Async.get(s), sync2AsyncBuilder);
}
return sync2AsyncBuilder;
}
// accessible for ClientProvider
public static void putInvokables(TypeToken<?> sync, TypeToken<?> async, Cache<Invokable<?, ?>, Invokable<?, ?>> cache) {
for (Method invoked : sync.getRawType().getMethods()) {
public static void putInvokables(Class<?> sync, Class<?> async, Cache<Invokable<?, ?>, Invokable<?, ?>> cache) {
for (Invokable<?, ?> invoked : methods(sync)) {
if (!objectMethods.contains(invoked)) {
try {
Method delegatedMethod = async.getRawType().getMethod(invoked.getName(), invoked.getParameterTypes());
checkArgument(Arrays.equals(delegatedMethod.getExceptionTypes(), invoked.getExceptionTypes()),
Invokable<?, ?> delegatedMethod = method(async, invoked.getName(), getParameterTypes(invoked));
checkArgument(delegatedMethod.getExceptionTypes().equals(invoked.getExceptionTypes()),
"invoked %s has different typed exceptions than delegated invoked %s", invoked, delegatedMethod);
invoked.setAccessible(true);
delegatedMethod.setAccessible(true);
cache.put(sync.method(invoked), async.method(delegatedMethod));
cache.put(invoked, delegatedMethod);
} catch (SecurityException e) {
throw propagate(e);
} catch (NoSuchMethodException e) {
throw propagate(e);
}
}
}
}
/**
* for portability with {@link Class#getMethod(String, Class...)}
*/
private static Class<?>[] getParameterTypes(Invokable<?, ?> in) {
return toArray(transform(checkNotNull(in, "invokable").getParameters(), new Function<Parameter, Class<?>>() {
public Class<?> apply(Parameter input) {
return input.getType().getRawType();
}
}), Class.class);
}
protected void installLocations() {
install(new LocationModule());
}

View File

@ -19,7 +19,7 @@
package org.jclouds.rest.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.reflect.Reflection2.typeTokenOf;
import static org.jclouds.reflect.Reflection2.typeToken;
import java.util.Properties;
@ -72,7 +72,7 @@ public abstract class BaseRestApiMetadata extends BaseApiMetadata implements Res
checkNotNull(asyncApi, "asyncApi");
javaApi(api, asyncApi)
.name(String.format("%s->%s", api.getSimpleName(), asyncApi.getSimpleName()))
.context(contextToken(typeTokenOf(api), typeTokenOf(asyncApi)))
.context(contextToken(typeToken(api), typeToken(asyncApi)))
.defaultProperties(BaseRestApiMetadata.defaultProperties());
}

View File

@ -23,7 +23,8 @@ import static com.google.common.base.Throwables.propagate;
import static com.google.common.collect.Iterables.all;
import static com.google.common.collect.Iterables.find;
import static com.google.inject.util.Types.newParameterizedType;
import static org.jclouds.reflect.Reflection2.typeTokenOf;
import static org.jclouds.reflect.Reflection2.method;
import static org.jclouds.reflect.Reflection2.typeToken;
import static org.jclouds.util.Optionals2.isReturnTypeOptional;
import static org.jclouds.util.Optionals2.unwrapIfOptional;
import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
@ -66,7 +67,6 @@ 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;
/**
@ -96,10 +96,11 @@ public final class DelegatesToInvocationFunction<S, F extends Function<Invocatio
* </ul>
* <li>other method calls are dispatched to {@link #handleInvocation}.
* </ul>
* @throws Throwable
*
* @throws Throwable
*/
@Override
public final Object invoke(Object proxy, Method invoked, @Nullable Object[] argv) throws Throwable {
public final Object invoke(Object proxy, Method invoked, @Nullable Object[] argv) throws Throwable {
if (argv == null) {
argv = NO_ARGS;
}
@ -118,7 +119,7 @@ public final class DelegatesToInvocationFunction<S, F extends Function<Invocatio
args = ImmutableList.copyOf(args);
else
args = Collections.unmodifiableList(args);
Invokable<?, Object> invokable = enclosingType.method(invoked);
Invokable<?, Object> invokable = method(ownerType, invoked);
Invocation invocation = Invocation.create(invokable, args);
try {
return handle(invocation);
@ -135,20 +136,19 @@ public final class DelegatesToInvocationFunction<S, F extends Function<Invocatio
return propagateContextToDelegate(invocation);
return methodInvoker.apply(invocation);
}
private final Injector injector;
private final TypeToken<S> enclosingType;
private final TypeToken<S> ownerType;
private final SetCaller setCaller;
private final Map<Class<?>, Class<?>> syncToAsync;
private final Function<InvocationSuccess, Optional<Object>> optionalConverter;
private final F methodInvoker;
@SuppressWarnings("unchecked")
@Inject
DelegatesToInvocationFunction(Injector injector, SetCaller setCaller, Map<Class<?>, Class<?>> syncToAsync,
TypeLiteral<S> enclosingType, Function<InvocationSuccess, Optional<Object>> optionalConverter, F methodInvoker) {
Class<S> ownerType, Function<InvocationSuccess, Optional<Object>> optionalConverter, F methodInvoker) {
this.injector = checkNotNull(injector, "injector");
this.enclosingType = (TypeToken<S>) typeTokenOf(checkNotNull(enclosingType, "enclosingType").getType());
this.ownerType = typeToken(checkNotNull(ownerType, "ownerType"));
this.setCaller = checkNotNull(setCaller, "setCaller");
this.syncToAsync = checkNotNull(syncToAsync, "syncToAsync");
this.optionalConverter = checkNotNull(optionalConverter, "optionalConverter");
@ -174,7 +174,7 @@ public final class DelegatesToInvocationFunction<S, F extends Function<Invocatio
}
/**
* attempts to guess the generic type params for the delegate's invocation function based on the supplied type
* 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) {
@ -256,8 +256,7 @@ public final class DelegatesToInvocationFunction<S, F extends Function<Invocatio
@Override
public String toString() {
return Objects.toStringHelper("").omitNullValues()
.add("enclosingType", enclosingType.getRawType().getSimpleName()).add("methodInvoker", methodInvoker)
.toString();
return Objects.toStringHelper("").omitNullValues().add("ownerType", ownerType.getRawType().getSimpleName())
.add("methodInvoker", methodInvoker).toString();
}
}

View File

@ -18,7 +18,7 @@
*/
package org.jclouds.apis;
import static org.jclouds.reflect.Reflection2.typeTokenOf;
import static org.jclouds.reflect.Reflection2.typeToken;
import java.util.Properties;
@ -48,7 +48,7 @@ public abstract class BaseViewLiveTest<V extends View> extends BaseContextLiveTe
@Override
protected TypeToken<Context> contextType() {
return typeTokenOf(Context.class);
return typeToken(Context.class);
}
protected V createView(Properties props, Iterable<Module> modules) {

View File

@ -19,6 +19,7 @@
package org.jclouds.http.functions;
import static com.google.common.base.Throwables.propagate;
import static org.jclouds.reflect.Reflection2.method;
import java.util.List;
@ -29,7 +30,6 @@ import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import com.google.common.collect.ImmutableList;
import com.google.common.reflect.Invokable;
import com.google.inject.Guice;
import com.google.inject.Injector;
@ -54,11 +54,9 @@ public class BaseHandlerTest {
@BeforeTest
protected void setUpRequest() {
try {
toString = Invocation.create(Invokable.from(String.class.getDeclaredMethod("toString")), ImmutableList.of());
toString = Invocation.create(method(String.class, "toString"), ImmutableList.of());
} catch (SecurityException e) {
throw propagate(e);
} catch (NoSuchMethodException e) {
throw propagate(e);
}
request = GeneratedHttpRequest.builder().method("POST").endpoint("http://localhost/key").invocation(toString)
.build();

View File

@ -17,7 +17,7 @@
* under the License.
*/
package org.jclouds.http.handlers;
import static org.jclouds.reflect.Reflection2.method;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
@ -125,7 +125,7 @@ public class BackoffLimitedRetryHandlerTest {
.getInstance(RestAnnotationProcessor.class);
private HttpCommand createCommand() throws SecurityException, NoSuchMethodException {
Invokable<?, Object> method = Invokable.from(IntegrationTestAsyncClient.class.getMethod("download", String.class));
Invokable<IntegrationTestAsyncClient, String> method = method(IntegrationTestAsyncClient.class, "download", String.class);
return new HttpCommand(processor.createRequest(method, ImmutableList.<Object> of("1")));
}

View File

@ -19,7 +19,7 @@
package org.jclouds.internal;
import static org.easymock.EasyMock.createMock;
import static org.jclouds.reflect.Reflection2.typeTokenOf;
import static org.jclouds.reflect.Reflection2.typeToken;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotEquals;
import static org.testng.Assert.fail;
@ -64,22 +64,22 @@ public class BaseViewTest {
private static class Wine extends BaseView {
protected Wine() {
super(new Water(), typeTokenOf(Water.class));
super(new Water(), typeToken(Water.class));
}
}
public void testWaterTurnedIntoWine() {
Wine wine = new Wine();
assertEquals(wine.getBackendType(), typeTokenOf(Water.class));
assertEquals(wine.unwrap(typeTokenOf(Water.class)).getClass(), Water.class);
assertEquals(wine.getBackendType(), typeToken(Water.class));
assertEquals(wine.unwrap(typeToken(Water.class)).getClass(), Water.class);
assertEquals(wine.unwrap().getClass(), Water.class);
}
public void testPeanutButterDidntTurnIntoWine() {
Wine wine = new Wine();
assertNotEquals(wine.getBackendType(), typeTokenOf(PeanutButter.class));
assertNotEquals(wine.getBackendType(), typeToken(PeanutButter.class));
try {
wine.unwrap(typeTokenOf(PeanutButter.class));
wine.unwrap(typeToken(PeanutButter.class));
fail();
} catch (IllegalArgumentException e) {
assertEquals(e.getMessage(), "backend type: org.jclouds.internal.BaseViewTest$Water not assignable from org.jclouds.internal.BaseViewTest$PeanutButter");

View File

@ -18,6 +18,7 @@
*/
package org.jclouds.json;
import static org.jclouds.reflect.Reflection2.method;
import static org.testng.Assert.assertEquals;
import java.lang.annotation.ElementType;
@ -39,7 +40,6 @@ import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.reflect.Invokable;
import com.google.inject.Guice;
import com.google.inject.Injector;
@ -62,8 +62,7 @@ public abstract class BaseParserTest<T, G> {
return (Function<HttpResponse, T>) i
.createChildInjector(new SaxParserModule())
.getInstance(TransformerForRequest.class)
.getTransformerForMethod(
Invocation.create(Invokable.from(getClass().getMethod("expected")), ImmutableList.of()), i);
.getTransformerForMethod(Invocation.create(method(getClass(), "expected"), ImmutableList.of()), i);
} catch (Exception e) {
throw Throwables.propagate(e);
}

View File

@ -19,7 +19,7 @@
package org.jclouds.providers.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.reflect.Reflection2.typeTokenOf;
import static org.jclouds.reflect.Reflection2.typeToken;
import static org.testng.Assert.assertEquals;
import java.util.Set;
@ -63,7 +63,7 @@ public abstract class BaseProviderMetadataTest {
public void testOfApiContains() {
if (expectedApi == null)
Logger.getAnonymousLogger().warning("please update your test class");
ImmutableSet<ProviderMetadata> ofApi = ImmutableSet.copyOf(Providers.apiMetadataAssignableFrom(typeTokenOf(expectedApi.getClass())));
ImmutableSet<ProviderMetadata> ofApi = ImmutableSet.copyOf(Providers.apiMetadataAssignableFrom(typeToken(expectedApi.getClass())));
assert ofApi.contains(toTest) : String.format("%s not found in %s", toTest, ofApi);
}

View File

@ -0,0 +1,79 @@
/**
* 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.Functions.toStringFunction;
import static org.jclouds.reflect.Reflection2.method;
import static org.jclouds.reflect.Reflection2.methods;
import static org.jclouds.reflect.Reflection2.typeToken;
import static org.testng.Assert.assertEquals;
import java.util.Set;
import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.Invokable;
import com.google.common.reflect.TypeToken;
/**
*
* @author Adrian Cole
*/
@Test
public class Reflection2Test {
public void testTypeToken() {
assertEquals(typeToken(String.class), TypeToken.of(String.class));
}
public void testMethodFromJavaMethod() throws SecurityException, NoSuchMethodException {
assertEquals(method(typeToken(String.class), String.class.getMethod("toString")), TypeToken.of(String.class)
.method(String.class.getMethod("toString")).returning(String.class));
}
public void testMethodFromClassAndNoParams() {
@SuppressWarnings("rawtypes")
Invokable<Set, Object> methodInSuper = method(Set.class, "iterator");
assertEquals(methodInSuper.getOwnerType(), typeToken(Set.class));
}
public void testMethodFromClassAndParams() {
@SuppressWarnings("rawtypes")
Invokable<Set, Object> methodInSuper = method(Set.class, "equals", Object.class);
assertEquals(methodInSuper.getOwnerType(), typeToken(Set.class));
assertEquals(methodInSuper.getParameters().get(0).getType().getRawType(), Object.class);
}
public void testMethods() {
Set<String> methodNames = FluentIterable.from(methods(Set.class))
.transform(new Function<Invokable<?, ?>, String>() {
public String apply(Invokable<?, ?> input) {
return input.getName();
}
}).transform(toStringFunction()).toSet();
assertEquals(methodNames, ImmutableSet.of("add", "equals", "hashCode", "clear", "isEmpty", "contains", "addAll",
"size", "toArray", "iterator", "remove", "removeAll", "containsAll", "retainAll"));
}
}

View File

@ -18,6 +18,8 @@
*/
package org.jclouds.rest;
import static org.jclouds.reflect.Reflection2.method;
import javax.ws.rs.POST;
import javax.ws.rs.PathParam;
@ -36,7 +38,6 @@ import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.reflect.Invokable;
import com.google.inject.Injector;
@Test(groups = "unit")
public class InputParamValidatorTest {
@ -59,10 +60,10 @@ public class InputParamValidatorTest {
*/
@Test
public void testInputParamsValidation() throws Exception {
Invokable<?, ?> allParamsValidatedMethod = Invokable.from(InputParamValidatorForm.class.getMethod(
"allParamsValidated", String.class, String.class));
Invokable<?, ?> oneParamValidatedMethod = Invokable.from(InputParamValidatorForm.class.getMethod(
"oneParamValidated", String.class, String.class));
Invokable<?, ?> allParamsValidatedMethod = method(InputParamValidatorForm.class, "allParamsValidated",
String.class, String.class);
Invokable<?, ?> oneParamValidatedMethod = method(InputParamValidatorForm.class, "oneParamValidated",
String.class, String.class);
restAnnotationProcessor.createRequest(allParamsValidatedMethod, ImmutableList.<Object> of("blah", "blah"));
restAnnotationProcessor.createRequest(oneParamValidatedMethod, ImmutableList.<Object> of("blah", "blah"));
@ -98,7 +99,7 @@ public class InputParamValidatorTest {
@Test(expectedExceptions = ClassCastException.class)
public void testWrongPredicateTypeLiteral() throws Exception {
Invocation invocation = Invocation.create(Invokable.from(WrongValidator.class.getMethod("method", Integer.class)),
Invocation invocation = Invocation.create(method(WrongValidator.class, "method", Integer.class),
ImmutableList.<Object> of(55));
new InputParamValidator(injector).validateMethodParametersOrThrow(invocation);
}

View File

@ -0,0 +1,148 @@
/**
* 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.annotationparsing;
import static org.jclouds.providers.AnonymousProviderMetadata.forClientMappedToAsyncClientOnEndpoint;
import static org.testng.Assert.assertEquals;
import java.util.NoSuchElementException;
import java.util.Set;
import javax.inject.Named;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.providers.ProviderMetadata;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.config.RestClientModule;
import org.jclouds.rest.internal.BaseRestClientExpectTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Names;
/**
* Tests that we can add {@link Provides} methods on interfaces
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ProvidesAnnotationExpectTest")
public class ProvidesAnnotationExpectTest extends BaseRestClientExpectTest<ProvidesAnnotationExpectTest.ProvidingApi> {
static interface ProvidingApi {
@Provides
Set<String> set();
@Named("bar")
@Provides
Set<String> foo();
@Named("exception")
@Provides
Set<String> exception();
@Named("NoSuchElementException")
@Provides
Set<String> noSuchElementException();
}
static interface ProvidingAsyncApi {
@Provides
Set<String> set();
@Named("bar")
@Provides
Set<String> foo();
@Named("exception")
@Provides
Set<String> exception();
@Named("NoSuchElementException")
@Provides
Set<String> noSuchElementException();
}
@Test
public void testProvidesWithGeneric(){
ProvidingApi client = requestsSendResponses(ImmutableMap.<HttpRequest, HttpResponse> of());
assertEquals(client.set(), ImmutableSet.of("foo"));
}
@Test
public void testProvidesWithGenericQualified(){
ProvidingApi client = requestsSendResponses(ImmutableMap.<HttpRequest, HttpResponse> of());
assertEquals(client.foo(), ImmutableSet.of("bar"));
}
@Test(expectedExceptions = AuthorizationException.class)
public void testProvidesWithGenericQualifiedAuthorizationException(){
ProvidingApi client = requestsSendResponses(ImmutableMap.<HttpRequest, HttpResponse> of());
client.exception();
}
@Test(expectedExceptions = NoSuchElementException.class)
public void testProvidesWithGenericQualifiedNoSuchElementException(){
ProvidingApi client = requestsSendResponses(ImmutableMap.<HttpRequest, HttpResponse> of());
client.noSuchElementException();
}
// crufty junk until we inspect delegating api classes for all their client
// mappings and make a test helper for random classes.
@Override
public ProviderMetadata createProviderMetadata() {
return forClientMappedToAsyncClientOnEndpoint(ProvidingApi.class, ProvidingAsyncApi.class, "http://mock");
}
@Override
protected Module createModule() {
return new ProvidingRestClientModule();
}
@ConfiguresRestClient
static class ProvidingRestClientModule extends RestClientModule<ProvidingApi, ProvidingAsyncApi> {
@Override
protected void configure() {
super.configure();
bind(new TypeLiteral<Set<String>>() {
}).toInstance(ImmutableSet.of("foo"));
bind(new TypeLiteral<Set<String>>() {
}).annotatedWith(Names.named("bar")).toInstance(ImmutableSet.of("bar"));
}
@Provides
@Named("exception")
Set<String> exception() {
throw new AuthorizationException();
}
@Provides
@Named("NoSuchElementException")
Set<String> noSuchElementException() {
throw new NoSuchElementException();
}
}
}

View File

@ -18,6 +18,7 @@
*/
package org.jclouds.rest.binders;
import static org.jclouds.reflect.Reflection2.method;
import static org.testng.Assert.assertEquals;
import java.io.File;
@ -33,10 +34,7 @@ import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.reflect.TypeToken;
import com.google.common.reflect.Invokable;
/**
* Tests behavior of {@code BindMapToStringPayload}
*
@ -56,7 +54,7 @@ public class BindMapToStringPayloadTest {
@Test
public void testCorrect() throws SecurityException, NoSuchMethodException {
Invokable<?, Object> testPayload = Invokable.from(TestPayload.class.getMethod("testPayload", String.class));
Invokable<?, Object> testPayload = method(TestPayload.class, "testPayload", String.class);
GeneratedHttpRequest request = GeneratedHttpRequest.builder()
.invocation(Invocation.create(testPayload, ImmutableList.<Object> of("robot")))
.method("POST").endpoint("http://localhost").build();
@ -70,7 +68,7 @@ public class BindMapToStringPayloadTest {
@Test
public void testDecodes() throws SecurityException, NoSuchMethodException {
Invokable<?, Object> testPayload = Invokable.from(TestPayload.class.getMethod("changeAdminPass", String.class));
Invokable<?, Object> testPayload = method(TestPayload.class, "changeAdminPass", String.class);
GeneratedHttpRequest request = GeneratedHttpRequest.builder()
.invocation(Invocation.create(testPayload, ImmutableList.<Object> of("foo")))
.method("POST").endpoint("http://localhost").build();
@ -84,7 +82,7 @@ public class BindMapToStringPayloadTest {
@Test(expectedExceptions = IllegalArgumentException.class)
public void testMustHavePayloadAnnotation() throws SecurityException, NoSuchMethodException {
Invokable<?, Object> noPayload = Invokable.from(TestPayload.class.getMethod("noPayload", String.class));
Invokable<?, Object> noPayload = method(TestPayload.class, "noPayload", String.class);
GeneratedHttpRequest request = GeneratedHttpRequest.builder()
.invocation(Invocation.create(noPayload, ImmutableList.<Object> of("robot")))
.method("POST").endpoint("http://localhost").build();

View File

@ -19,6 +19,7 @@
package org.jclouds.rest.functions;
import static com.google.common.base.Throwables.propagate;
import static org.jclouds.reflect.Reflection2.method;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
@ -35,7 +36,6 @@ import org.testng.annotations.Test;
import com.google.common.base.Optional;
import com.google.common.base.Stopwatch;
import com.google.common.collect.ImmutableList;
import com.google.common.reflect.Invokable;
/**
* Allows you to use simple api version comparison to determine if a feature is
@ -165,9 +165,9 @@ public class PresentWhenApiVersionLexicographicallyAtOrAfterSinceApiVersionTest
InvocationSuccess getApi(String name, Class<?> target) {
try {
return InvocationSuccess.create(Invocation.create(
Invokable.from(EC2AsyncApi.class.getDeclaredMethod("get" + name + "ApiForRegion", String.class)),
ImmutableList.<Object> of("region")), "present");
return InvocationSuccess.create(
Invocation.create(method(EC2AsyncApi.class, "get" + name + "ApiForRegion", String.class),
ImmutableList.<Object> of("region")), "present");
} catch (Exception e) {
throw propagate(e);
}

View File

@ -17,8 +17,7 @@
* under the License.
*/
package org.jclouds.rest.internal;
import static org.jclouds.reflect.Reflection2.typeTokenOf;
import static org.jclouds.reflect.Reflection2.typeToken;
import java.util.Set;
@ -46,7 +45,7 @@ public abstract class BaseRestApiMetadataTest extends BaseApiMetadataTest {
@Test
public void testContextAssignableFromRestContext() {
Set<ApiMetadata> all = ImmutableSet.copyOf(Apis.contextAssignableFrom(typeTokenOf(RestContext.class)));
Set<ApiMetadata> all = ImmutableSet.copyOf(Apis.contextAssignableFrom(typeToken(RestContext.class)));
assert all.contains(toTest) : String.format("%s not found in %s", toTest, all);
}

View File

@ -22,7 +22,7 @@ import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.jclouds.reflect.Reflection2.typeTokenOf;
import static org.jclouds.reflect.Reflection2.method;
import static org.testng.Assert.assertEquals;
import java.util.concurrent.ExecutionException;
@ -39,7 +39,6 @@ import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.reflect.TypeToken;
import com.google.common.util.concurrent.ListenableFuture;
/**
@ -62,16 +61,13 @@ public class BlockOnFutureTest {
}
}
private TypeToken<ThingAsyncApi> enclosingType;
private Invocation get;
private Invocation namedGet;
@BeforeClass
void setupInvocations() throws SecurityException, NoSuchMethodException {
enclosingType = typeTokenOf(ThingAsyncApi.class);
get = Invocation.create(enclosingType.method(ThingAsyncApi.class.getDeclaredMethod("get")), ImmutableList.of());
namedGet = Invocation.create(enclosingType.method(ThingAsyncApi.class.getDeclaredMethod("namedGet")),
ImmutableList.of());
get = Invocation.create(method(ThingAsyncApi.class, "get"), ImmutableList.of());
namedGet = Invocation.create(method(ThingAsyncApi.class, "namedGet"), ImmutableList.of());
}
@SuppressWarnings("unchecked")

View File

@ -17,7 +17,7 @@
* under the License.
*/
package org.jclouds.util;
import static org.jclouds.reflect.Reflection2.method;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
@ -40,25 +40,25 @@ public class Optionals2Test {
}
public void testReturnTypeOrTypeOfOptionalWhenOptional() throws SecurityException, NoSuchMethodException {
Invokable<?, ?> invoked = Invokable.from(Test.class.getMethod("getOptional"));
Invokable<?, ?> invoked = method(Test.class, "getOptional");
assertEquals(Optionals2.unwrapIfOptional(invoked.getReturnType()), String.class);
}
public void testReturnTypeOrTypeOfOptionalWhenNotOptional() throws SecurityException, NoSuchMethodException {
Invokable<?, ?> invoked = Invokable.from(Test.class.getMethod("getNotOptional"));
Invokable<?, ?> invoked = method(Test.class, "getNotOptional");
assertEquals(Optionals2.unwrapIfOptional(invoked.getReturnType()), String.class);
}
public void testIsReturnTypeOptionalWhenOptional() throws SecurityException, NoSuchMethodException {
Invokable<?, ?> invoked = Invokable.from(Test.class.getMethod("getOptional"));
Invokable<?, ?> invoked = method(Test.class, "getOptional");
assertTrue(Optionals2.isReturnTypeOptional(invoked));
}
public void testIsReturnTypeOptionalWhenNotOptional() throws SecurityException, NoSuchMethodException {
Invokable<?, ?> invoked = Invokable.from(Test.class.getMethod("getNotOptional"));
Invokable<?, ?> invoked = method(Test.class, "getNotOptional");
assertFalse(Optionals2.isReturnTypeOptional(invoked));
}

View File

@ -20,7 +20,7 @@ package org.jclouds.util;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.createNiceMock;
import static org.jclouds.reflect.Reflection2.typeTokenOf;
import static org.jclouds.reflect.Reflection2.typeToken;
import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
import static org.jclouds.util.Throwables2.propagateIfPossible;
import static org.testng.Assert.assertEquals;
@ -148,14 +148,14 @@ public class Throwables2Test {
@Test(expectedExceptions = TestException.class)
public void testPropagateExceptionThatsInList() throws Throwable {
Exception e = new TestException();
propagateIfPossible(e, ImmutableSet.<TypeToken<? extends Throwable>> of(typeTokenOf(TestException.class)));
propagateIfPossible(e, ImmutableSet.<TypeToken<? extends Throwable>> of(typeToken(TestException.class)));
}
@Test(expectedExceptions = TestException.class)
public void testPropagateWrappedExceptionThatsInList() throws Throwable {
Exception e = new TestException();
propagateIfPossible(new RuntimeException(e),
ImmutableSet.<TypeToken<? extends Throwable>> of(typeTokenOf(TestException.class)));
ImmutableSet.<TypeToken<? extends Throwable>> of(typeToken(TestException.class)));
}
public void testPropagateIfPossibleDoesnThrowExceptionNotInList() throws Throwable {