81 votes

Alternatives à java.lang.reflect.Proxy pour créer des proxies de classes abstraites (plutôt que d'interfaces)

Selon la documentation :

[ java.lang.reflect. ] Proxy fournit des méthodes statiques pour créer des classes et des instances de proxy et c'est également le superclasse de toutes les classes créées par ces méthodes.

El newProxyMethod méthode) (responsable de la génération des proxies dynamiques) a la signature suivante :

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

Malheureusement, cela empêche la génération d'un proxy dynamique qui étend une classe abstraite spécifique (plutôt que mise en œuvre de interfaces spécifiques). Cela est logique, étant donné que java.lang.reflect.Proxy est "la superclasse de toutes les proxies dynamiques", ce qui empêche une autre classe d'être la superclasse.

Par conséquent, existe-t-il des alternatives à java.lang.reflect.Proxy qui peut générer des proxies dynamiques qui hériter de à partir d'une classe abstraite spécifique, en redirigeant tous les appels vers la classe abstrait au gestionnaire d'invocation ?

Par exemple, supposons que j'ai une classe abstraite Dog :

public abstract class Dog {

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

    public abstract void fetch();

}

Existe-t-il une classe qui me permette de faire ce qui suit ?

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

112voto

axtavt Points 126632

Cela peut être fait en utilisant Javassist (voir ProxyFactory ) ou CGLIB .

L'exemple d'Adam utilisant Javassist :

J'ai (Adam Paynter) écrit ce code en utilisant 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();

Ce qui produit cette sortie :

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

-7voto

Riduidel Points 13456

Ce que vous pouvez faire dans un tel cas est d'avoir un gestionnaire de proxy qui redirigera les appels aux méthodes existantes de votre classe abstraite.

Vous devrez bien sûr le coder, mais c'est assez simple. Pour créer votre Proxy, il vous faudra lui donner un [InvocationHandler](http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/InvocationHandler.html) . Vous n'aurez alors qu'à vérifier le type de méthode dans le champ [invoke(..)](http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/InvocationHandler.html#invoke(java.lang.Object,%20java.lang.reflect.Method,%20java.lang.Object[])) de votre gestionnaire d'invocation. Mais attention : vous devrez vérifier le type de la méthode par rapport à l'objet sous-jacent associé à votre gestionnaire, et non par rapport au type déclaré de votre classe abstraite.

Si je prends comme exemple votre classe de chien, la méthode invoke de votre gestionnaire d'invocation mai ressemble à ceci (avec une sous-classe de chien associée existante appelée ... eh bien ... 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 ?
    }
}

Cependant, il y a quelque chose qui me turlupine : j'ai parlé d'un dog objet. Mais, comme la classe Dog est abstraite, vous ne pouvez pas créer d'instances, vous avez donc des sous-classes existantes. En outre, comme le révèle une inspection rigoureuse du code source de Proxy, vous pouvez découvrir (à Proxy.java:362) qu'il n'est pas possible de créer un Proxy pour un objet Class qui ne représente pas une interface).

Donc, en dehors de la réalité ce que vous voulez faire est parfaitement possible.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X