Альтернативы java.ленг.отражать.Прокси для создания прокси абстрактных классов (а не интерфейсов)


по данным документация:

[java.lang.reflect.]Proxy предоставляет статические методы для создании динамических прокси-классов и экземпляры, и это также суперкласс всех динамических прокси классы, созданные этими методами.

The newProxyMethod метод (отвечающей за генерацию динамических прокси) имеет следующую сигнатуру:

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
                             throws IllegalArgumentException

к сожалению, это не позволяет генерировать динамический прокси, который выходит конкретный абстрактный класс (а не реализация специальные интерфейсы). Это имеет смысл, учитывая java.lang.reflect.Proxy является "суперклассом всех динамических прокси", тем самым предотвращая другой класс от суперкласса.

, есть ли какие-либо альтернативы java.lang.reflect.Proxy это может генерировать динамические прокси, которые наследование из определенного абстрактного класса, перенаправляя все вызовы на аннотация методы для обработчика вызова?

например, предположим, у меня есть абстрактный класс Dog:

public abstract class Dog {

    public void bark() {
        System.out.println("Woof!");
    }

    public abstract void fetch();

}

есть класс, который позволяет мне сделать следующее?

Dog dog = SomeOtherProxy.newProxyInstance(classLoader, Dog.class, h);

dog.fetch(); // Will be handled by the invocation handler
dog.bark();  // Will NOT be handled by the invocation handler
2 72

2 ответа:

Это можно сделать с помощью Javassist (см. ProxyFactory) или CGLIB.

пример Адама с помощью Javassist:

Я (Адам Пайнтер) написал этот код с помощью Javassist:

ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(Dog.class);
factory.setFilter(
    new MethodFilter() {
        @Override
        public boolean isHandled(Method method) {
            return Modifier.isAbstract(method.getModifiers());
        }
    }
);

MethodHandler handler = new MethodHandler() {
    @Override
    public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
        System.out.println("Handling " + thisMethod + " via the method handler");
        return null;
    }
};

Dog dog = (Dog) factory.create(new Class<?>[0], new Object[0], handler);
dog.bark();
dog.fetch();

который производит этот вывод:

Woof!
Handling public abstract void mock.Dog.fetch() via the method handler

что вы можете сделать в таком случае, это иметь прокси-обработчик, который будет перенаправлять вызовы существующих методов вашего абстрактного класса.

вам, конечно, придется кодировать его, однако это довольно просто. Для создания вашего прокси, вы должны будете дать ему InvocationHandler. Затем вам нужно будет только проверить тип метода в invoke(..) метод обработчик вызова. Но будьте осторожны : вам придется проверить тип метода против базового объекта, связанного с вашим обработчиком, а не против объявленного типа вашего абстрактного класса.

если я возьму в качестве примера ваш класс собаки, метод invoke вашего обработчика вызова мая выглядит так (с существующим связанным подклассом собаки называется .. что ж... dog)

public void invoke(Object proxy, Method method, Object[] args) {
    if(!Modifier.isAbstract(method.getModifiers())) {
        method.invoke(dog, args); // with the correct exception handling
    } else {
        // what can we do with abstract methods ?
    }
}

однако есть кое-что, что заставляет меня задуматься : я говорил о dog "объект". Но, поскольку класс Dog является абстрактным, вы не можете создавать экземпляры, поэтому у вас есть существующие подклассы. Кроме того, как строгий проверка исходного кода Прокси показывает, что вы можете обнаружить (на прокси.java: 362), что невозможно создать прокси для объекта класса, который не представляет интерфейс).

так, кроме реальность, то, что вы хотите сделать, вполне возможно.