How do I make a class, which I can't change, implement an interface?

adapter, instanceof, interface, java, proxy-classes

Solution

There are two approaches:

- Using an adapter pattern

- Using `Proxy`

The adapter approach will be simpler but less flexible, and the `Proxy` approach will be more complex but more flexible. Even though the `Proxy` approach is more complex, that complexity is all restricted to a couple of classes.

Adapter

The adapter pattern is simple. For your example, it would just be one class, like so:

public class QuietFooAdapter implements Foo {

    private QuietFoo quietFoo;

    public QuietFooAdapter(QuietFoo quietFoo) {
        this.quietFoo = quietFoo;
    }

    public void bar() {
        quietFoo.bar();
    }
}

Then to use it:

Foo foo = new QuietFooAdapter(new QuietFoo());
foo.bar();

This is good, but if you have more than one class to make an adapter for, this can be tedious since you'll need a new adapter for each class you have to wrap.

Java's `Proxy` Class

`Proxy` is a native Java class that's part of the reflection libraries that will allow you to create a more generic, reflective solution. It involves 3 parts:

- The interface (in this case, `Foo`)

- The `InvocationHandler`

- Creation of the proxy (`Proxy.newProxyInstance`)

We already have the interface, so we're fine there.

The `InvocationHandler` is where we do our "auto-adapting" via reflection:

public class AdapterInvocationHandler implements InvocationHandler {

    private Object target;
    private Class<?> targetClass;

    public AdapterInvocationHandler(Object target) {
        this.target = target;
        targetClass = target.getClass();
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            Method targetMethod = targetClass.getMethod(method.getName(), method.getParameterTypes());
            if (!method.getReturnType().isAssignableFrom(targetMethod.getReturnType()))
                throw new UnsupportedOperationException("Target (" + target.getClass().getName() + ") does not support: " + method.toGenericString());
            return targetMethod.invoke(target, args);
        } catch (NoSuchMethodException ex) {
            throw new UnsupportedOperationException("Target (" + target.getClass().getName() + ") does not support: " + method.toGenericString());
        } catch (IllegalAccessException ex) {
            throw new UnsupportedOperationException("Target (" + target.getClass().getName() + ") does not declare method to be public: " + method.toGenericString());
        } catch (InvocationTargetException ex) {
            // May throw a NullPointerException if there is no target exception
            throw ex.getTargetException();
        }
    }
}

The important code here is in the `try` block. This will handle the process of adapting any method calls that are called on the proxy to the inner `target` object. If a method is called on the interface that isn't supported (non-`public`, wrong return type, or just flat out doesn't exist), then we throw an `UnsupportedOperationException`. If we catch an `InvocationTargetException`, we rethrow the exception that caused it via `InvocationTargetException.getTargetException`. This occurs when the method we called reflectively throws an exception. Java wraps it in a new exception and throws that new exception.

Next, we need something to create the adapters:

public class AdapterFactory {

    public static <T> T createAdapter(Object target, Class<T> interfaceClass) {
        if (!interfaceClass.isInterface())
            throw new IllegalArgumentException("Must be an interface: " + interfaceClass.getName());
        return (T) Proxy.newProxyInstance(null, new Class<?>[] { interfaceClass }, new AdapterInvocationHandler(target));
    }
}

You could also nest the `AdapterInvocationHandler` class in the `AdapterFactory` class, if you like, so that everything is self-contained in `AdapterFactory`.

Then to use it:

Foo foo = AdapterFactory.createAdapter(new QuietFoo(), Foo.class);
foo.bar();

This approach requires more code than implementing a single adapter, but will be generic enough that it can be used to create auto-adapters for any class and interface pair, not just the `QuietFoo` and `Foo` example. Granted, this method uses reflection (the `Proxy` class uses reflection, as does our `InvocationHandler`), which can be slower, but recent improvements in the JVM have made reflection much faster than it used to be.

Problem

I have a class from another library that is closed-source, but I want to be able to use an interface for it. The reason being that I don't want to do `instanceof` checks or `null`-checks everywhere, but I also don't want to extend the existing class. For example, let's say I have this code: ``` public class Example { // QuietFoo is from another library that I can't change private static QuietFoo quietFoo; // LoudFoo is my own code and is meant to replace QuietFoo private static LoudFoo loudFoo; public static void main(String[] args) { handle(foo); } private static void handle(Object foo) { if (foo instanceof QuietFoo) ((QuietFoo) foo).bar(); else if (foo instanceof LoudFoo) ((LoudFoo) foo).bar(); } } ``` I can't change `QuietFoo`: ``` public class QuietFoo { public void bar() { System.out.println("bar"); } } ``` But I can change `LoudFoo`: ``` public class LoudFoo { public void bar() { System.out.println("BAR!!"); } } ``` The problem is, there may be many other implementations of `bar` in many classes, and there may be more methods than just `bar`, so not only would my `handle` method get slow and ugly with lots of `instanceof` statements, but I would have to write one of these handle methods for each method on `QuietFoo` and `LoudFoo`. Extending isn't a viable solution because it violates the whole is-a contract since `LoudFoo` is not a `QuietFoo`. Basically, given `Foo`: ``` public interface Foo { void bar(); } ``` How can I make `QuietFoo` implement `Foo` without changing its source so I don't have to do casting and `instanceof` calls everywhere in my code?

Original source