1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.ex.variablespeed;
18
19import java.lang.reflect.InvocationHandler;
20import java.lang.reflect.InvocationTargetException;
21import java.lang.reflect.Method;
22import java.lang.reflect.Proxy;
23
24/**
25 * Contains a utility method for adapting a given interface against a real implementation.
26 * <p>
27 * This class is thead-safe.
28 */
29public class DynamicProxy {
30    /**
31     * Dynamically adapts a given interface against a delegate object.
32     * <p>
33     * For the given {@code clazz} object, which should be an interface, we return a new dynamic
34     * proxy object implementing that interface, which will forward all method calls made on the
35     * interface onto the delegate object.
36     * <p>
37     * In practice this means that you can make it appear as though {@code delegate} implements the
38     * {@code clazz} interface, without this in practice being the case. As an example, if you
39     * create an interface representing the {@link android.media.MediaPlayer}, you could pass this
40     * interface in as the first argument, and a real {@link android.media.MediaPlayer} in as the
41     * second argument, and now calls to the interface will be automatically sent on to the real
42     * media player. The reason you may be interested in doing this in the first place is that this
43     * allows you to test classes that have dependencies that are final or cannot be easily mocked.
44     */
45    // This is safe, because we know that proxy instance implements the interface.
46    @SuppressWarnings("unchecked")
47    public static <T> T dynamicProxy(Class<T> clazz, final Object delegate) {
48        InvocationHandler invoke = new InvocationHandler() {
49            @Override
50            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
51                try {
52                    return delegate.getClass()
53                            .getMethod(method.getName(), method.getParameterTypes())
54                            .invoke(delegate, args);
55                } catch (InvocationTargetException e) {
56                    throw e.getCause();
57                }
58            }
59        };
60        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class<?>[] { clazz }, invoke);
61    }
62}
63