Voici un petit exemple montrant comment utiliser les annotations et l’aop avec Spring pour ajouter des fonctionnalités supplémentaires à vos applications.
L’objectif est de pouvoir crypter et decrypter des arguments ou des objets retournés d’un service. Cette fonctionnalité pourra être activable ou désactivable en fonction du cadre d’utilisation sans que cela ai d’impact sur le code. C’est à dire par de la configuration.

Le service

Ici nous souhaitons encypter la String de retour et décrypter le firstname passé en paramètre.

package com.fullsix.demo.service;

/**
 *
 * @author Damien Viel
 * @version $Id$
 *
 */
public interface IDemoService {

   @Crypt(mode=Mode.CRYPT)
    public String myDemoMethod(@Crypt(mode=Mode.DECRYPT) String firstname,
             String lastname );

}

Son implémentation :

package com.fullsix.demo.service;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author Damien Viel
 * @version $Id$
 *
 */
public class DemoService implements IDemoService {

    private static final Log logger = LogFactory.getLog(DemoService.class);

    public String myDemoMethod(String firstname, String lastname) {
        logger.info(”myParam value :” + firstname);
        // Here your business code
        // myOtherService.doSomeThing(firstname, lastname);
        return “Hello ” + firstname + ” ” + lastname;
    }
}

Annotation

Cette annotation pourra être positionnée soit sur une méthode soit sur un argument d’une méthode.

package com.fullsix.demo.crypt;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 *
 * @author Damien Viel
 * @version $Id$
 *
 */
@Target({ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface Crypt {
    public enum Mode {
        CRYPT{
            @Override
            public String execute(String input) {
                return CryptUtils.crypt(input);
            }
        },
        DECRYPT{
            @Override
            public String execute(String input) {
                return CryptUtils.deCrypt(input);
            }

        };
        public abstract String execute(String input);
    };

    Mode mode() default Mode.CRYPT;
}

Exemple de classe “Utils” pour l’encryption

package com.fullsix.demo.crypt;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;

/**
 *
 * @author Damien Viel
 * @version $Id$
 *
 */
public class CryptUtils {

    public static String crypt(String text) {
        if (StringUtils.isEmpty(text))
            throw new IllegalArgumentException(”Text is null or empty”);
      byte[] encoded = Base64.encodeBase64(text.getBytes());
      return new String(encoded);
    }

  public static String deCrypt(String text) {
      if (StringUtils.isEmpty(text))
          throw new IllegalArgumentException(”Text is null or empty”);
      byte[] decoded = Base64.decodeBase64(text.getBytes());
      return new String(decoded);
   }
}

L’intercepteur

package com.fullsix.demo.crypt;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Required;

/**
 * @author Damien Viel
 * @version $Id$
 *
 */
@SuppressWarnings(”all”)
public class CryptInterceptor implements MethodInterceptor {
    private static final Log logger = LogFactory.getLog(CryptInterceptor.class);

    public Object invoke(final MethodInvocation invocation) throws Throwable {

        Method method = invocation.getMethod();
        Annotation[][] annotations = method.getParameterAnnotations();
        Object[] args = invocation.getArguments();

        if (args != null && args.length > 0) {
            Annotation[][] parameterAnnotations = method.getParameterAnnotations();
            for (int i = 0; i < args.length; i++) {
                Annotation[] paramAnnos = parameterAnnotations[i];
                for (int j = 0; j < paramAnnos.length; j++) {
                    Annotation paramAnno = paramAnnos[j];
                    if (paramAnno instanceof Crypt && args[i] instanceof String) {
                        Crypt crypt = (Crypt)paramAnno;
                        args[i] = crypt.mode().execute((String)args[i]);
                    }
                }
            }
        }

        Object returnObject =  invocation.proceed();
        Crypt crypt = null;
        if (invocation.getMethod().isAnnotationPresent(Crypt.class)){
            logger.debug(invocation.getMethod().getName());
            Crypt cryptMethode = invocation.getMethod().getAnnotation(Crypt.class);
            if (returnObject instanceof String){
                return cryptMethode.mode().execute((String)returnObject);
            }
        }
        return returnObject;
    }
}

La config Spring




    

    

    

     

            
        


                .*.*
            
        
    

     

    

    

            com.fullsix.demo.service.IDemoService
        

            
        


                cryptPointCut
            
        
    

La classe de Test

/**
 *  Copyrights Fullsix 2008
 *
 */
package com.fullsix.demo.test;

import org.junit.Test;
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;

import com.fullsix.demo.crypt.CryptUtils;
import com.fullsix.demo.service.IDemoService;

/**
 * @author Damien Viel
 * @version $Id$
 *
 */
public class DemoTest extends AbstractDependencyInjectionSpringContextTests {

    private IDemoService demoService;
    private String fname = “Bernard”;
    private String lname = “Morin”;
    private String text2 = “Hello”;

    @Override
    protected void injectDependencies() throws Exception {
        super.injectDependencies();
        this.demoService = (IDemoService)this.applicationContext.getBean(”demoService”);
    }

    @Override
    protected String[] getConfigLocations() {
        return new String[] {”classpath:application-context.xml”};
    }

    @Test
    public void testDemo(){
        fname = CryptUtils.crypt(fname);
        String ret = demoService.myDemoMethod(fname, lname);
        System.err.println(ret);
        assertEquals(text2+” “+CryptUtils.deCrypt(fname)+” “+lname, CryptUtils.deCrypt(ret));
        assertTrue(true);
    }
}