unwound a few stack traces by making DelegatesToInvocationFunction an invocation handler directly

This commit is contained in:
Adrian Cole 2013-01-13 22:41:06 -08:00
parent f18d3b433f
commit b07984435f
10 changed files with 136 additions and 160 deletions

View File

@ -32,8 +32,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.jclouds.reflect.Invocation.Result;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
import com.google.common.base.Objects;
@ -77,13 +75,13 @@ public final class FunctionalReflection {
* @see com.google.common.reflect.AbstractInvocationHandler#invoke(Object, Method, Object[])
* @see com.google.common.reflect.Reflection#newProxy(Class, java.lang.reflect.InvocationHandler)
*/
public static <T> T newProxy(TypeToken<T> enclosingType, Function<Invocation, Result> invocationFunction) {
public static <T> T newProxy(TypeToken<T> enclosingType, Function<Invocation, Object> invocationFunction) {
checkNotNull(enclosingType, "enclosingType");
checkNotNull(invocationFunction, "invocationFunction");
return newProxy(enclosingType.getRawType(), new FunctionalInvocationHandler<T>(enclosingType, invocationFunction));
}
public static <T> T newProxy(Class<T> enclosingType, Function<Invocation, Result> invocationFunction) {
public static <T> T newProxy(Class<T> enclosingType, Function<Invocation, Object> invocationFunction) {
checkNotNull(invocationFunction, "invocationFunction");
return newProxy(enclosingType,
new FunctionalInvocationHandler<T>(TypeToken.of(enclosingType), invocationFunction));
@ -100,9 +98,9 @@ public final class FunctionalReflection {
private static final class FunctionalInvocationHandler<T> extends
com.google.common.reflect.AbstractInvocationHandler {
private final TypeToken<T> enclosingType;
private final Function<Invocation, Result> invocationFunction;
private final Function<Invocation, Object> invocationFunction;
private FunctionalInvocationHandler(TypeToken<T> enclosingType, Function<Invocation, Result> invocationFunction) {
private FunctionalInvocationHandler(TypeToken<T> enclosingType, Function<Invocation, Object> invocationFunction) {
this.enclosingType = enclosingType;
this.invocationFunction = invocationFunction;
}
@ -117,17 +115,12 @@ public final class FunctionalReflection {
Invokable<?, Object> invokable = Invokable.from(invoked);
// not yet support the proxy arg
Invocation invocation = Invocation.create(invokable, args);
Result result;
try {
result = invocationFunction.apply(invocation);
return invocationFunction.apply(invocation);
} catch (RuntimeException e) {
result = Result.fail(e);
propagateIfPossible(e, invocation.getInvokable().getExceptionTypes());
throw propagate(e);
}
if (result.getThrowable().isPresent()) {
propagateIfPossible(result.getThrowable().get(), invocation.getInvokable().getExceptionTypes());
throw propagate(result.getThrowable().get());
}
return result.getResult().orNull();
}
@Override

View File

@ -23,11 +23,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
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;
/**
@ -90,63 +87,4 @@ public final class Invocation {
public String toString() {
return String.format("%s%s", invokable, args);
}
/**
* result of an invocation which is either successful or failed, but not both.
*/
@Beta
public final static class Result {
public static Result success(@Nullable Object result) {
return new Result(Optional.fromNullable(result), Optional.<Throwable> absent());
}
public static Result fail(Throwable throwable) {
return new Result(Optional.absent(), Optional.of(throwable));
}
private final Optional<Object> result;
private final Optional<Throwable> throwable;
private Result(Optional<Object> result, Optional<Throwable> throwable) {
this.result = checkNotNull(result, "result");
this.throwable = checkNotNull(throwable, "throwable");
}
/**
* result of{@link Invokable#invoke(Object, Object...)}
*/
public Optional<Object> getResult() {
return result;
}
/**
* throwable received during {@link Invokable#invoke(Object, Object...)}
*/
public Optional<Throwable> getThrowable() {
return throwable;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Result that = Result.class.cast(o);
return equal(this.result.orNull(), that.result.orNull())
&& equal(this.throwable.orNull(), that.throwable.orNull());
}
@Override
public int hashCode() {
return Objects.hashCode(result.orNull(), throwable.orNull());
}
@Override
public String toString() {
return Objects.toStringHelper("").omitNullValues().add("result", result.orNull())
.add("throwable", throwable.orNull()).toString();
}
}
}

View File

@ -18,11 +18,12 @@
*/
package org.jclouds.rest.config;
import java.lang.reflect.Proxy;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.reflect.FunctionalReflection;
import org.jclouds.rest.internal.DelegatingInvocationFunction;
import org.jclouds.rest.internal.DelegatesToInvocationFunction;
import org.jclouds.rest.internal.InvokeHttpMethod;
import com.google.inject.Provider;
@ -35,10 +36,10 @@ import com.google.inject.TypeLiteral;
@Singleton
public class AsyncHttpApiProvider<A> implements Provider<A> {
private final Class<? super A> asyncApiType;
private final DelegatingInvocationFunction<A, A, InvokeHttpMethod<A, A>> httpInvoker;
private final DelegatesToInvocationFunction<A, A, InvokeHttpMethod<A, A>> httpInvoker;
@Inject
private AsyncHttpApiProvider(DelegatingInvocationFunction<A, A, InvokeHttpMethod<A, A>> httpInvoker,
private AsyncHttpApiProvider(DelegatesToInvocationFunction<A, A, InvokeHttpMethod<A, A>> httpInvoker,
TypeLiteral<A> asyncApiType) {
this.httpInvoker = httpInvoker;
this.asyncApiType = asyncApiType.getRawType();
@ -47,7 +48,6 @@ public class AsyncHttpApiProvider<A> implements Provider<A> {
@SuppressWarnings("unchecked")
@Override
public A get() {
return (A) FunctionalReflection.newProxy(asyncApiType, httpInvoker);
return (A) Proxy.newProxyInstance(asyncApiType.getClassLoader(), new Class<?>[] { asyncApiType }, httpInvoker);
}
}

View File

@ -18,15 +18,16 @@
*/
package org.jclouds.rest.config;
import java.lang.reflect.Proxy;
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.DelegatesToInvocationFunction;
import org.jclouds.rest.internal.InvokeAndCallGetOnFutures;
import com.google.common.cache.Cache;
import com.google.common.reflect.Invokable;
import com.google.common.reflect.TypeToken;
import com.google.inject.Provider;
@ -37,11 +38,11 @@ import com.google.inject.Provider;
public class CallGetOnFuturesProvider<S, A> implements Provider<S> {
private final Class<? super S> apiType;
private final DelegatingInvocationFunction<S, A, InvokeAndCallGetOnFutures<A>> syncInvoker;
private final DelegatesToInvocationFunction<S, A, InvokeAndCallGetOnFutures<A>> syncInvoker;
@Inject
private CallGetOnFuturesProvider(Cache<Invokable<?, ?>, Invokable<?, ?>> invokables,
DelegatingInvocationFunction<S, A, InvokeAndCallGetOnFutures<A>> syncInvoker, Class<S> apiType,
DelegatesToInvocationFunction<S, A, InvokeAndCallGetOnFutures<A>> syncInvoker, Class<S> apiType,
Class<A> asyncApiType) {
this.syncInvoker = syncInvoker;
this.apiType = apiType;
@ -52,6 +53,6 @@ public class CallGetOnFuturesProvider<S, A> implements Provider<S> {
@Override
@Singleton
public S get() {
return (S) FunctionalReflection.newProxy(apiType, syncInvoker);
return (S) Proxy.newProxyInstance(apiType.getClassLoader(), new Class<?>[] { apiType }, syncInvoker);
}
}

View File

@ -18,15 +18,16 @@
*/
package org.jclouds.rest.config;
import java.lang.reflect.Proxy;
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.DelegatesToInvocationFunction;
import org.jclouds.rest.internal.InvokeHttpMethod;
import com.google.common.cache.Cache;
import com.google.common.reflect.Invokable;
import com.google.common.reflect.TypeToken;
import com.google.inject.Provider;
@ -37,11 +38,11 @@ import com.google.inject.Provider;
@Singleton
public class HttpApiProvider<S, A> implements Provider<S> {
private final Class<? super S> apiType;
private final DelegatingInvocationFunction<S, A, InvokeHttpMethod<S, A>> httpInvoker;
private final DelegatesToInvocationFunction<S, A, InvokeHttpMethod<S, A>> httpInvoker;
@Inject
private HttpApiProvider(Cache<Invokable<?, ?>, Invokable<?, ?>> invokables,
DelegatingInvocationFunction<S, A, InvokeHttpMethod<S, A>> httpInvoker, Class<S> apiType, Class<A> asyncApiType) {
DelegatesToInvocationFunction<S, A, InvokeHttpMethod<S, A>> httpInvoker, Class<S> apiType, Class<A> asyncApiType) {
this.httpInvoker = httpInvoker;
this.apiType = apiType;
RestModule.putInvokables(TypeToken.of(apiType), TypeToken.of(asyncApiType), invokables);
@ -51,7 +52,7 @@ public class HttpApiProvider<S, A> implements Provider<S> {
@Override
@Singleton
public S get() {
return (S) FunctionalReflection.newProxy(apiType, httpInvoker);
return (S) Proxy.newProxyInstance(apiType.getClassLoader(), new Class<?>[] { apiType }, httpInvoker);
}
}

View File

@ -34,7 +34,6 @@ import javax.inject.Named;
import org.jclouds.logging.Logger;
import org.jclouds.reflect.Invocation;
import org.jclouds.reflect.Invocation.Result;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
@ -46,7 +45,7 @@ import com.google.common.util.concurrent.UncheckedExecutionException;
import com.google.common.util.concurrent.UncheckedTimeoutException;
import com.google.inject.assistedinject.Assisted;
public class BlockOnFuture implements Function<ListenableFuture<?>, Result> {
public class BlockOnFuture implements Function<ListenableFuture<?>, Object> {
public static interface Factory {
/**
@ -73,19 +72,19 @@ public class BlockOnFuture implements Function<ListenableFuture<?>, Result> {
}
@Override
public Result apply(ListenableFuture<?> future) {
public Object apply(ListenableFuture<?> future) {
Optional<Long> timeoutNanos = timeoutInNanos(invocation.getInvokable(), timeouts);
return block(future, timeoutNanos);
}
private Result block(ListenableFuture<?> future, Optional<Long> timeoutNanos) {
private Object block(ListenableFuture<?> future, Optional<Long> timeoutNanos) {
try {
if (timeoutNanos.isPresent()) {
logger.debug(">> blocking on %s for %s", future, timeoutNanos);
return Result.success(getUninterruptibly(future, timeoutNanos.get(), NANOSECONDS));
return getUninterruptibly(future, timeoutNanos.get(), NANOSECONDS);
} else {
logger.debug(">> blocking on %s", future);
return Result.success(getUninterruptibly(future));
return getUninterruptibly(future);
}
} catch (ExecutionException e) {
throw propagateCause(e);

View File

@ -19,25 +19,33 @@
package org.jclouds.rest.internal;
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 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 static org.jclouds.util.Throwables2.propagateIfPossible;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Qualifier;
import org.jclouds.javax.annotation.Nullable;
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;
@ -49,6 +57,8 @@ 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.AbstractInvocationHandler;
import com.google.common.reflect.Invokable;
import com.google.common.reflect.TypeToken;
import com.google.inject.Binding;
import com.google.inject.ConfigurationException;
@ -60,7 +70,6 @@ import com.google.inject.TypeLiteral;
import com.google.inject.util.Types;
/**
*
* @param <S>
* The enclosing type of the interface that a dynamic proxy like this implements
* @param <A>
@ -69,8 +78,67 @@ import com.google.inject.util.Types;
* The function that implements this dynamic proxy
*/
@Beta
public final class DelegatingInvocationFunction<S, A, F extends Function<Invocation, Result>> implements
Function<Invocation, Result> {
public final class DelegatesToInvocationFunction<S, A, F extends Function<Invocation, Object>> implements
InvocationHandler {
private static final Object[] NO_ARGS = {};
/**
* {@inheritDoc}
*
* <p>
* <ul>
* <li>{@code proxy.hashCode()} delegates to {@link AbstractInvocationHandler#hashCode}
* <li>{@code proxy.toString()} delegates to {@link AbstractInvocationHandler#toString}
* <li>{@code proxy.equals(argument)} returns true if:
* <ul>
* <li>{@code proxy} and {@code argument} are of the same type
* <li>and {@link AbstractInvocationHandler#equals} returns true for the {@link InvocationHandler} of
* {@code argument}
* </ul>
* <li>other method calls are dispatched to {@link #handleInvocation}.
* </ul>
* @throws Throwable
*/
@Override
public final Object invoke(Object proxy, Method invoked, @Nullable Object[] argv) throws Throwable {
if (argv == null) {
argv = NO_ARGS;
}
if (argv.length == 0 && invoked.getName().equals("hashCode")) {
return hashCode();
}
if (argv.length == 1 && invoked.getName().equals("equals") && invoked.getParameterTypes()[0] == Object.class) {
Object arg = argv[0];
return proxy.getClass().isInstance(arg) && equals(Proxy.getInvocationHandler(arg));
}
if (argv.length == 0 && invoked.getName().equals("toString")) {
return toString();
}
List<Object> args = Arrays.asList(argv);
if (all(args, notNull()))
args = ImmutableList.copyOf(args);
else
args = Collections.unmodifiableList(args);
Invokable<?, Object> invokable = Invokable.from(invoked);
// not yet support the proxy arg
Invocation invocation = Invocation.create(invokable, args);
try {
return handle(invocation);
} catch (Throwable e) {
propagateIfPossible(e, invocation.getInvokable().getExceptionTypes());
throw e;
}
}
protected Object handle(Invocation invocation) {
if (invocation.getInvokable().isAnnotationPresent(Provides.class))
return lookupValueFromGuice(invocation.getInvokable());
else if (invocation.getInvokable().isAnnotationPresent(Delegate.class))
return propagateContextToDelegate(invocation);
return methodInvoker.apply(invocation);
}
private final Injector injector;
private final TypeToken<S> enclosingType;
private final SetCaller setCaller;
@ -80,7 +148,7 @@ public final class DelegatingInvocationFunction<S, A, F extends Function<Invocat
@SuppressWarnings("unchecked")
@Inject
DelegatingInvocationFunction(Injector injector, SetCaller setCaller, Map<Class<?>, Class<?>> syncToAsync,
DelegatesToInvocationFunction(Injector injector, SetCaller setCaller, Map<Class<?>, Class<?>> syncToAsync,
TypeLiteral<S> enclosingType, Function<InvocationSuccess, Optional<Object>> optionalConverter, F methodInvoker) {
this.injector = checkNotNull(injector, "injector");
this.enclosingType = (TypeToken<S>) TypeToken.of(checkNotNull(enclosingType, "enclosingType").getType());
@ -90,22 +158,13 @@ public final class DelegatingInvocationFunction<S, A, F extends Function<Invocat
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<Invocation, Result> delegate;
Function<Invocation, Object> delegate;
setCaller.enter(enclosingType, caller);
try {
@SuppressWarnings("unchecked")
Key<Function<Invocation, Result>> delegateType = (Key<Function<Invocation, Result>>) methodInvokerFor(returnType);
Key<Function<Invocation, Object>> delegateType = (Key<Function<Invocation, Object>>) methodInvokerFor(returnType);
delegate = injector.getInstance(delegateType);
} finally {
setCaller.exit();

View File

@ -19,6 +19,8 @@
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.util.concurrent.Futures.getUnchecked;
import java.lang.reflect.InvocationTargetException;
@ -27,20 +29,18 @@ 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.reflect.Invokable;
import com.google.common.util.concurrent.ListenableFuture;
/**
*
* @author Adrian Cole
*/
public final class InvokeAndCallGetOnFutures<R> implements Function<Invocation, Result> {
public final class InvokeAndCallGetOnFutures<R> implements Function<Invocation, Object> {
@Resource
private Logger logger = Logger.NULL;
@ -62,7 +62,7 @@ public final class InvokeAndCallGetOnFutures<R> implements Function<Invocation,
@SuppressWarnings("unchecked")
@Override
public Result apply(Invocation in) {
public Object apply(Invocation in) {
@SuppressWarnings("rawtypes")
Invokable target = checkNotNull(sync2AsyncInvokables.getIfPresent(in.getInvokable()), "invokable %s not in %s",
in.getInvokable(), sync2AsyncInvokables);
@ -70,13 +70,13 @@ public final class InvokeAndCallGetOnFutures<R> implements Function<Invocation,
try {
returnVal = target.invoke(receiver, in.getArgs().toArray());
} catch (InvocationTargetException e) {
return Result.fail(e);
throw propagate(e.getCause());
} catch (IllegalAccessException e) {
return Result.fail(e);
throw new Error("Method became inaccessible: " + toString(), e);
}
if (!isFuture(target))
return Result.success(returnVal);
return Result.success(Futures.getUnchecked(ListenableFuture.class.cast(returnVal)));
return returnVal;
return getUnchecked(ListenableFuture.class.cast(returnVal));
}
private boolean isFuture(Invokable<?, ?> target) {

View File

@ -35,7 +35,6 @@ import org.jclouds.http.HttpCommandExecutorService;
import org.jclouds.http.HttpResponse;
import org.jclouds.logging.Logger;
import org.jclouds.reflect.Invocation;
import org.jclouds.reflect.Invocation.Result;
import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.annotations.Fallback;
@ -53,7 +52,7 @@ import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.inject.Injector;
import com.google.inject.TypeLiteral;
public class InvokeHttpMethod<S, A> implements Function<Invocation, Result> {
public class InvokeHttpMethod<S, A> implements Function<Invocation, Object> {
@Resource
private Logger logger = Logger.NULL;
@ -98,9 +97,9 @@ public class InvokeHttpMethod<S, A> implements Function<Invocation, Result> {
});
@Override
public Result apply(Invocation in) {
public Object apply(Invocation in) {
if (isFuture(in.getInvokable())) {
return Result.success(createFuture(in));
return createFuture(in);
}
@SuppressWarnings("rawtypes")
Invokable async = checkNotNull(sync2AsyncInvokables.getIfPresent(in.getInvokable()), "invokable %s not in %s",

View File

@ -27,9 +27,7 @@ import static org.testng.Assert.assertTrue;
import java.io.Closeable;
import java.io.IOException;
import java.util.Set;
import java.util.concurrent.TimeoutException;
import org.jclouds.reflect.Invocation.Result;
import org.testng.annotations.Test;
import com.google.common.base.Function;
@ -45,8 +43,8 @@ public class FunctionalReflectionTest {
@SuppressWarnings("unchecked")
@Test(expectedExceptions = UnsupportedOperationException.class)
public void testNullArgsAreAllowedAndUnmodifiable() {
final Function<Invocation, Result> test = new Function<Invocation, Result>() {
public Result apply(Invocation e) {
final Function<Invocation, Object> test = new Function<Invocation, Object>() {
public Object apply(Invocation e) {
assertNotNull(e.getArgs());
assertNull(e.getArgs().get(0));
e.getArgs().add("foo");
@ -59,8 +57,8 @@ public class FunctionalReflectionTest {
@SuppressWarnings("unchecked")
@Test(expectedExceptions = UnsupportedOperationException.class)
public void testImmutableListWhenArgsAreNotNull() {
final Function<Invocation, Result> test = new Function<Invocation, Result>() {
public Result apply(Invocation e) {
final Function<Invocation, Object> test = new Function<Invocation, Object>() {
public Object apply(Invocation e) {
assertNotNull(e.getArgs());
assertTrue(e.getArgs() instanceof ImmutableList);
assertEquals(e.getArgs().get(0), "foo");
@ -73,9 +71,9 @@ public class FunctionalReflectionTest {
@Test(expectedExceptions = IOException.class, expectedExceptionsMessageRegExp = "io")
public void testPropagatesDeclaredException() throws IOException {
final Function<Invocation, Result> test = new Function<Invocation, Result>() {
public Result apply(Invocation e) {
return Result.fail(new IOException("io"));
final Function<Invocation, Object> test = new Function<Invocation, Object>() {
public Object apply(Invocation e) {
throw new RuntimeException(new IOException("io"));
}
};
Closeable closeable = FunctionalReflection.newProxy(Closeable.class, test);
@ -87,21 +85,9 @@ public class FunctionalReflectionTest {
*/
@Test(expectedExceptions = AssertionError.class, expectedExceptionsMessageRegExp = "assert")
public void testPropagatesError() throws IOException {
final Function<Invocation, Result> test = new Function<Invocation, Result>() {
public Result apply(Invocation e) {
return Result.fail(new AssertionError("assert"));
}
};
Closeable closeable = FunctionalReflection.newProxy(Closeable.class, test);
closeable.close();
}
// TODO: coerce things like this to UncheckedTimeoutException and friends
@Test(expectedExceptions = RuntimeException.class, expectedExceptionsMessageRegExp = ".*timeout")
public void testWrapsDeclaredException() throws IOException {
final Function<Invocation, Result> test = new Function<Invocation, Result>() {
public Result apply(Invocation e) {
return Result.fail(new TimeoutException("timeout"));
final Function<Invocation, Object> test = new Function<Invocation, Object>() {
public Object apply(Invocation e) {
throw new AssertionError("assert");
}
};
Closeable closeable = FunctionalReflection.newProxy(Closeable.class, test);
@ -109,9 +95,9 @@ public class FunctionalReflectionTest {
}
public void testToStringEqualsFunction() {
final Function<Invocation, Result> test = new Function<Invocation, Result>() {
public Result apply(Invocation e) {
return Result.success("foo");
final Function<Invocation, Object> test = new Function<Invocation, Object>() {
public Object apply(Invocation e) {
return "foo";
}
public String toString() {
@ -123,9 +109,9 @@ public class FunctionalReflectionTest {
}
public void testHashCodeDifferentiatesOnInterface() {
final Function<Invocation, Result> test = new Function<Invocation, Result>() {
public Result apply(Invocation e) {
return Result.success(null);
final Function<Invocation, Object> test = new Function<Invocation, Object>() {
public Object apply(Invocation e) {
return null;
}
public int hashCode() {