Proxy Dynamique en Golo

Golo est fait pour utiliser des classes Java. Si vous manipulez des classes qui implĂ©mentent des interfaces, il est tout Ă  fait possible de “greffer” des comportements Ă  vos mĂ©thodes de classes (celles dĂ©clarĂ©es dans une interface) grĂące Ă  import java.lang.reflect.Proxy. Voyons donc comment faire:

Imaginez une interface java “Toon”:

package org.k33g;

public interface Toon {
    public String hello(String message);
    public String speak(String message);
}

Imaginez une classe java qui implémente Toon :

package org.k33g;

public class TinyToon implements Toon {

    private String name = null;

    public TinyToon(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String hello(String message) {
        return "HELLO I'M "+this.name+" : "+ message;
    }

    @Override
    public String speak(String message) {
        return "BLABLA BY "+this.name+" : "+ message;
    }
}

Proxy dynamique

Il est possible de créer un proxy de TinyToon, implémentant donc Toon et ce dynamiquement :

Ce peut ĂȘtre trĂšs pratique, si vous avez des traitements (mĂ©thodes) qui “attendent” des objets de type Toon, et que vous souhaitez ajouter des comportements aux mĂ©thodes (ce n’est possible que pour les mĂ©thodes dĂ©clarĂ©es dans l’interface implĂ©mentĂ©e par la classe) :

Dans un 1er temps, si nous utilisons tout simplement TinyToon :

import org.k33g.TinyToon

function main = |args| {

	let toon = TinyToon("Babs")

    println(toon:hello("HI !!!"))
    println(toon:speak("IT'S SO CUTE"))

}

Nous obtiendrons Ă  l’exĂ©cution la sortie suivante :

HELLO I'M Babs : HI !!!
BLABLA BY Babs : IT'S SO CUTE

Maintenant, nous allons créer notre proxy de TinyToon :

Nous allons maintenant utiliser Proxy.newProxyInstance() :

import java.lang.reflect.InvocationHandler
import java.lang.reflect.Proxy

import org.k33g.TinyToon

function main = |args| {

	let toon = TinyToon("Babs")

	let toonProxy = Proxy.newProxyInstance(
        toon:getClass():getClassLoader(),
        toon:getClass():getInterfaces(),
        (|proxy, method, args...| {
	
        	println("You've called : " + method:getName())
        	
        	let result = null

        	if method:getName() is "hello" {
                println("hello from proxy")
        		result = toon:hello(args:get(0))
        	}

        	if method:getName() is "speak" {
                println("speak from proxy")
        		result = toon:speak(args:get(0))
        	}

        	return result

        }):to(InvocationHandler.class))

	println(toonProxy:hello("HI !!!"))
	println(toonProxy:speak("IT'S SO CUTE"))

}

Remarquez que nous “castons” notre closure |proxy, method, args...| { ... } en InvocationHandler, en utilisant ():to(InvocationHandler.class).

Nous obtiendrons Ă  l’exĂ©cution la sortie suivante :

You've called : hello
hello from proxy
HELLO I'M Babs : HI !!!
You've called : speak
speak from proxy
BLABLA BY Babs : IT'S SO CUTE

Et voilĂ , vous venez de faire de l’AOP avec Golo. Ce qui vous dĂ©montre une fois de plus la puissance de ce langage.

Vous trouverez ici une version “gĂ©nĂ©rique” rĂ©utilisable d’un proxy dynamique : https://github.com/k33g/DynoGolo.

42. ;)

Ă  venir : comment modifier directement Golo. Stay tuned

blog comments powered by Disqus

Related posts