Выполните метод вызова InvocationHandler для каждого метода в моем прокси-классе - PullRequest
0 голосов
/ 30 апреля 2019

Я реализовал динамический прокси для выполнения некоторых операций до того, как мои методы начались. Теперь у меня есть проблема при вызове двух методов из класса прокси, вот код:

Динамический прокси-класс:

public class IPageProxy implements InvocationHandler {

    private Class <? extends IPage> screenClazz;

    public IPageProxy(final Class <? extends IPage> screenClazz) {
        this.screenClazz = screenClazz;
    }

    @SuppressWarnings("unchecked")
    public static <T extends IPage> T getInstance(final Class<? extends IPage> type)
            throws InstantiationException, IllegalAccessException {

        List<Class<?>> interfaces = new ArrayList<>();
        interfaces.addAll(Arrays.asList(type.getInterfaces()));

        return (T) Proxy.newProxyInstance(
                type.getClassLoader(),
                findInterfaces(type),
                new IPageProxy(type)
             );

    }


    static Class<?>[] findInterfaces(final Class<? extends IPage> type) {
        Class<?> current = type;

        do {
            final Class<?>[] interfaces = current.getInterfaces();

            if (interfaces.length != 0) {
                return interfaces;
            }
        } while ((current = current.getSuperclass()) != Object.class);

        throw new UnsupportedOperationException("The type does not implement any interface");
    }





    @Override
    public Object invoke(final Object proxy, final Method method, final Object[] args) throws InvocationTargetException,
            IllegalAccessException, IllegalArgumentException, InstantiationException, ParserConfigurationException, XPathExpressionException, NoSuchFieldException, SecurityException {

        // before method executed this code will be done
        System.out.println("*   Dynamic proxy invoke method executed for " +  method.getName());

        // Invoke original method
        return method.invoke(screenClazz.newInstance(), args);
    }
}

Основной класс:

public static void main(String[] args) {
        try {
            //IEventDesignDialog a = new EventDesignDialog();
            IEventDesignDialog a  = (IEventDesignDialog)getInstance(EventDesignDialog.class);
            a.getEventType().getShow();

        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }


    @SuppressWarnings("unchecked")
    public static <T extends IPage> T getInstance(final Class<? extends IPage> type) throws InstantiationException, IllegalAccessException {
        return (T) IPageProxy.getInstance(type);
    }

Прокси-класс:

public class EventDesignDialog implements IEventDesignDialog{


        private String show;


        private String dateAndTimeDisplayFormat;
        private String eventType;


        @Entity(visibileName = "Show")
        public IEventDesignDialog getShow() {
            System.out.println("get show method invokde successfully");
            return this;
        }

        @Entity(visibileName = "Date And Time display format")
        public IEventDesignDialog getDateAndTimeDisplayFormat() {
            System.out.println("get date and time display format method invokde successfully");
            return this;
        }

        @Entity(visibileName = "Event Type")
        public IEventDesignDialog getEventType() {
            System.out.println("get event type method invokde successfully");
            return this;
        }



}

Фактическая выработка:

***   Dynamic proxy invoke method executed for getEventType
get event type method invokde successfully
get show method invokde successfully**

как показано, метод вызова выполняется только при первом вызове метода после инициализации прокси, второй метод вызывается напрямую, без функции прокси.

Моя цель - выполнять метод invoke каждый раз, когда вызывается метод из моей коллекции, ожидаемый результат должен быть таким, как показано ниже.

Ожидаемый результат:

***   Dynamic proxy invoke method executed for getEventType
get event type method invokde successfully
*   Dynamic proxy invoke method executed for getShow
get show method invokde successfully**

пожалуйста, дайте мне знать, если понадобятся дополнительные объяснения.

Ответы [ 2 ]

0 голосов
/ 01 мая 2019

Происходит следующее: сначала вы проксируете только первый вызов, а затем вызываете getShow () для класса без использования прокси, и именно поэтому вы получаете результат, который вы упомянули.Если вы хотите достичь цели, которую вы упомянули, вам нужно создать другой прокси на основе созданного экземпляра, а не только на классе.

Обновление: я приведу пример кода, вы можете вставить в любой файл Java и выполнитьЭто.Там, где вы видите TODO, вы можете разместить свою собственную логику в зависимости от того, как вы хотите предоставить прокси.Смотрите ПРИМЕЧАНИЕ для важных моментов.Я поместил все классы в один файл для простоты демонстрации.

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.List;

class Scratch {
    public static void main(String[] args) {
        try {
            IEventDesignDialog a  = proxy(EventDesignDialog.class);
            a.getEventType().getShow();
            a.getDateAndTimeDisplayFormat().getShow();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }


    @SuppressWarnings("unchecked")
    private static <T extends IPage> T proxy(final Class<? extends IPage> type) throws InstantiationException, IllegalAccessException {
        return (T) IPageProxy.proxy(type);
    }
}
interface IPage{}
interface IEventDesignDialog extends IPage{
    IEventDesignDialog getShow();
    IEventDesignDialog getEventType();
    IEventDesignDialog getDateAndTimeDisplayFormat();
}
class EventDesignDialog implements IEventDesignDialog{

    public IEventDesignDialog getShow() {
        System.out.println("get show method invoked successfully");

        //NOTE: this will be treated as same proxy but not this
        return this;
    }

    public IEventDesignDialog getDateAndTimeDisplayFormat() {
        System.out.println("get date and time display format method invoked successfully");

        // NOTE: we supply some iinstance which will be proxied
        return new MyIEventDesignDialog();
    }

    public IEventDesignDialog getEventType() {
        System.out.println("get event type method invoked successfully");

        //NOTE: this will be treated as same proxy but not this
        return this;
    }

}
class IPageProxy implements InvocationHandler {

    private IPage instance;
    private List<Class<?>> interfaces;


    public IPageProxy(IPage instance, List<Class<?>> interfaces) {
        this.instance = instance;
        this.interfaces = interfaces;
    }

    @SuppressWarnings("unchecked")
    public static <T extends IPage> T proxy(final Class<? extends IPage> type)
            throws InstantiationException, IllegalAccessException {

        List<Class<?>> interfaces = Arrays.asList(type.getInterfaces());


        //TODO: get interfaces properly recursively
        return (T) Proxy.newProxyInstance(
                type.getClassLoader(),
                type.getInterfaces(),
                new IPageProxy(type.newInstance(), interfaces)
        );

    }

    @SuppressWarnings("unchecked")
    public static <T extends IPage> T proxy(T object) {

        //TODO: get interfaces properly recursively
        List<Class<?>> interfaces = Arrays.asList(object.getClass().getInterfaces());

        return (T) Proxy.newProxyInstance(
                object.getClass().getClassLoader(),
                object.getClass().getInterfaces(),
                new IPageProxy(object, interfaces)
        );

    }




    @Override
    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Exception {

        // before method executed this code will be done
        System.out.println("*   Dynamic proxy invoke method executed for " +  method.getName());

        // Invoke original method
        Object invoke = method.invoke(instance, args);
        if (invoke == null) {
            return null;
        }

        //If some of the method returns the original object
        //we swap the returned object by our proxy
        if (invoke == instance) {
            return proxy;
        }

        //TODO: check if you want to swap in place
        //other interfaces
        if (interfaces.contains(method.getReturnType())) {
            return IPageProxy.proxy((IPage)invoke);
        }
        return invoke;
    }
}

class MyIEventDesignDialog implements IEventDesignDialog {
    @Override
    public IEventDesignDialog getShow() {
        return null;
    }

    @Override
    public IEventDesignDialog getEventType() {
        return null;
    }

    @Override
    public IEventDesignDialog getDateAndTimeDisplayFormat() {
        return null;
    }
}

Вывод:

*   Dynamic proxy invoke method executed for getEventType
get event type method invoked successfully
*   Dynamic proxy invoke method executed for getShow
get show method invoked successfully
*   Dynamic proxy invoke method executed for getDateAndTimeDisplayFormat
get date and time display format method invoked successfully
*   Dynamic proxy invoke method executed for getShow

Вы можете получить идеи о том, как работает Mockito.Пожалуйста, проверьте эту страницу: https://static.javadoc.io/org.mockito/mockito-core/2.27.0/org/mockito/Mockito.html#spy-T-

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

0 голосов
/ 01 мая 2019

Я решил эту проблему, создав интерфейс с методом по умолчанию, который возвращает экземпляр прокси, а затем возвратил его после выполнения функциональности вызванного метода:

обновленный код:

public interface IPage {
    default <T extends IPage> T getProxyInstance() {
        try {
            return (T) IPageProxy.getInstance(this.getClass());
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
}

Моя страницаИнтерфейс:

@Page(path = "MyPath")
public interface IEventDesignDialog extends IPage{
    @Entity(visibileName = "Show")
    public IEventDesignDialog getShow();

    @Entity(visibileName = "Date And Time display format")
    public IEventDesignDialog getDateAndTimeDisplayFormat();

    @Entity(visibileName = "Event Type")
    public IEventDesignDialog getEventType();    
}

Класс моей страницы:

@Page(path = "MyPath")
public class EventDesignDialog implements IEventDesignDialog{
        @Entity(visibileName = "Show")
        public IEventDesignDialog getShow() {
            System.out.println("get show method invokde successfully");
            return getProxyInstance();
        }

        @Entity(visibileName = "Date And Time display format")
        public IEventDesignDialog getDateAndTimeDisplayFormat() {
            System.out.println("get date and time display format method invokde successfully");
            return getProxyInstance();
        }

        @Entity(visibileName = "Event Type")
        public IEventDesignDialog getEventType() {
            System.out.println("get event type method invokde successfully");
            return getProxyInstance();
        }
}

Основной класс:

public class Main {

    public static void main(String[] args) {
        try {
            IEventDesignDialog a  = ((IEventDesignDialog)getInstance(EventDesignDialog.class)).getEventType().getShow();

            ((IShowDesignDialog)getInstance(ShowDesignDialog.class)).getShowName().getShowType();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }


    @SuppressWarnings("unchecked")
    public static <T extends IPage> T getInstance(final Class<? extends IPage> type) throws InstantiationException, IllegalAccessException {
        return (T) IPageProxy.getInstance(type);
    }

}

Страница IProxy остается без изменений.

...