public static <T> T awaitState(final long timeoutMillis, Object compareTo, final T object) {
        final Matcher matcher = toMatcher(compareTo);
        final Class<?> matcherType = Primitives.getRealClass(matcher.getType());
        return (T) ProxyUtil.newProxy(object.getClass(), new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] args) throws Throwable {
                if (!Primitives.getRealClass(method.getReturnType()).isAssignableFrom(matcherType)) {
                    throw new UsageError(method + " is not comparable with " + matcherType);
                }
                long t = System.currentTimeMillis();
                while (true) {
                    Object result = null;
                    Exception exception = null;
                    try {
                        result = method.invoke(object, args);
                        if (matcher.matches(result)) {
                            return result;
                        }
                    } catch (IllegalAccessException e) {
                        throw e;
                    } catch (IllegalArgumentException e) {
                        throw e;
                    } catch (InvocationTargetException e) {
                        exception = e;
                    }
                    Thread.sleep(20);
                    if (System.currentTimeMillis() - t > timeoutMillis) {
                        if (exception != null) {
                            throw new VerificationError("await state timed out. Got exception: " + exception.getMessage(), exception);
                        }
                        throw new VerificationError("await state timed out. Expected " + matcher + " but got " + result);
                    }
                }
            }
        });
    }