Динамический адаптер Java - PullRequest
1 голос
/ 24 июня 2011

Я использую некоторый код Java, который производит следующие интерфейсы. Этот код не подлежит изменению.

interface A1 {
    public void run();
}

interface A2 {
    public void run();
}

...

interface A24 {
    public void run();
}

У меня ошибка приведения класса к следующему коду. Как мне динамически построить адаптер для моего интерфейса?

interface ARunnable {
    public void run();
}

public void someMethod() {
    // getARunnables() returns a list of A1, A2, ... A24
    List<ARunnable> runnables = (List<ARunnable>)getARunnables(); 

    for (ARunnable a : runnables) {
        a.run();
    }
}

Ответы [ 2 ]

1 голос
/ 24 июня 2011

Поскольку интерфейсы не могут быть изменены для расширения java.lang.Runnable, можно использовать java.lang.reflect.Proxy для создания экземпляров Runnable, которые делегируют ваши интерфейсы A1, A2 ....

Это не тривиально, но посмотрите на этот пример, используя java.lang.reflect.Proxy.Пример просто делегирует объект делегата на основе имени метода.

public class ProxyTest
{
    public static void main(String... args)
    {
        List<?> instances = Arrays.asList(new A1());
        List<ARunnable> runnableInstances = new ArrayList<ARunnable>(instances.size());
        for (Object instance : instances)
        {
            ARunnable runnableInstance = (ARunnable)Proxy.newProxyInstance(
                                            ARunnable.class.getClassLoader(), 
                                            new Class<?>[] {ARunnable.class}, 
                                            new RunnableWrapper(instance));
            runnableInstances.add(runnableInstance);
        }

        //Now we have a list of ARunnables!
        //Use them for something
        for (ARunnable runnableInstance : runnableInstances)
        {
            runnableInstance.run();
        }
    }

    private static class RunnableWrapper implements InvocationHandler
    {
        private final Object instance;

        public RunnableWrapper(Object instance)
        {
            this.instance = instance;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable
        {
            //Ensure that your methods match exactly or you'll get NoSuchMethodExceptions here
            Method delegateMethod = instance.getClass().getMethod(method.getName(), method.getParameterTypes());
            return(delegateMethod.invoke(instance, args));
        }
    }

    public static class A1
    {
        public void run()
        {
            System.out.println("Something");
        }
    }

    public static interface ARunnable
    {
        public void run();
    }
}

Также я бы порекомендовал вам исправить строку

List<ARunnable> runnables = (List<ARunnable>)getARunnables(); 

Это предупреждение о безопасности типа, которое вы не должны игнорировать.Этот список объектов на самом деле не содержит ARunnables, следовательно, ClassCastException.

0 голосов
/ 24 июня 2011

Рассмотрим этот пример кода (не имеет цикла для простоты):

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;

    public class Main {

      interface Interface {
        public void run();
      }

      static class Hello /* does't implement Interface */{

        public void run() {
          System.out.println("Hello, world!!");
        }
      }

      static <T> T dirtyCast(Class<T> intrface, final Object target) {

        return intrface.cast(Proxy.newProxyInstance(
          intrface.getClassLoader(),
          new Class<?>[] { intrface }, new InvocationHandler() {

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

              Method targetMethod = target.getClass().getMethod(
                method.getName(), method.getParameterTypes());

              return targetMethod.invoke(target, args);
          }

        }));
      }

      public static void main(String[] args) {

        Interface proxy = dirtyCast(Interface.class, new Hello());

        proxy.run();

      }
    }

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

Также вы должны учитывать соображения безопасности. Загрузчики классов могут иметь разные (несовместимые) ограничения безопасности.

Если вы быстро столкнетесь с проблемами, я бы попробовал проект, разработанный для этого, например transloader .

Веселитесь.

...