ldapbeans.bean.LdapBeanClassManager.java Source code

Java tutorial

Introduction

Here is the source code for ldapbeans.bean.LdapBeanClassManager.java

Source

/*
 * This file is part of ldapbeans
 *
 * Released under LGPL
 *
 * ldapbeans is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * ldapbeans is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with ldapbeans.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright 2010 Bruno Macherel
 */
package ldapbeans.bean;

import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;
import static org.objectweb.asm.ClassWriter.COMPUTE_MAXS;
import static org.objectweb.asm.Opcodes.AALOAD;
import static org.objectweb.asm.Opcodes.AASTORE;
import static org.objectweb.asm.Opcodes.ACC_FINAL;
import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.ACONST_NULL;
import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.ANEWARRAY;
import static org.objectweb.asm.Opcodes.ARETURN;
import static org.objectweb.asm.Opcodes.ARRAYLENGTH;
import static org.objectweb.asm.Opcodes.ASTORE;
import static org.objectweb.asm.Opcodes.ATHROW;
import static org.objectweb.asm.Opcodes.BIPUSH;
import static org.objectweb.asm.Opcodes.CHECKCAST;
import static org.objectweb.asm.Opcodes.DLOAD;
import static org.objectweb.asm.Opcodes.DSTORE;
import static org.objectweb.asm.Opcodes.DUP;
import static org.objectweb.asm.Opcodes.FCONST_0;
import static org.objectweb.asm.Opcodes.FLOAD;
import static org.objectweb.asm.Opcodes.FSTORE;
import static org.objectweb.asm.Opcodes.GETFIELD;
import static org.objectweb.asm.Opcodes.GETSTATIC;
import static org.objectweb.asm.Opcodes.GOTO;
import static org.objectweb.asm.Opcodes.IADD;
import static org.objectweb.asm.Opcodes.ICONST_0;
import static org.objectweb.asm.Opcodes.ICONST_1;
import static org.objectweb.asm.Opcodes.IFEQ;
import static org.objectweb.asm.Opcodes.IFNE;
import static org.objectweb.asm.Opcodes.IFNONNULL;
import static org.objectweb.asm.Opcodes.IFNULL;
import static org.objectweb.asm.Opcodes.IF_ICMPGE;
import static org.objectweb.asm.Opcodes.IF_ICMPLT;
import static org.objectweb.asm.Opcodes.ILOAD;
import static org.objectweb.asm.Opcodes.INSTANCEOF;
import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
import static org.objectweb.asm.Opcodes.IRETURN;
import static org.objectweb.asm.Opcodes.ISTORE;
import static org.objectweb.asm.Opcodes.LCONST_0;
import static org.objectweb.asm.Opcodes.LLOAD;
import static org.objectweb.asm.Opcodes.LSTORE;
import static org.objectweb.asm.Opcodes.NEW;
import static org.objectweb.asm.Opcodes.POP;
import static org.objectweb.asm.Opcodes.PUTFIELD;
import static org.objectweb.asm.Opcodes.RETURN;
import static org.objectweb.asm.Opcodes.V1_5;

import java.io.File;
import java.io.FileOutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;

import ldapbeans.annotation.ConvertAttribute;
import ldapbeans.annotation.LdapAttribute;
import ldapbeans.config.LdapbeansConfiguration;
import ldapbeans.config.LdapbeansMessageManager;
import ldapbeans.util.cache.GenericKey;
import ldapbeans.util.i18n.Logger;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

public final class LdapBeanClassManager {

    private static class LdapBeanClassLoaderManager {

        private final Map<ClassLoader, LdapBeanClassLoader> m_Classloaders;

        /**
         * The default constructor to initialize attributes
         */
        public LdapBeanClassLoaderManager() {
            m_Classloaders = new HashMap<ClassLoader, LdapBeanClassLoader>();
        }

        /**
         * Return a {@link LdapBeanClassLoader} depending the context
         * ClassLoader (i.e. Thread.currentThread().getContextClassLoader())
         * 
         * @return a {@link LdapBeanClassLoader} depending the context
         *         ClassLoader (i.e.
         *         Thread.currentThread().getContextClassLoader())
         * @see Thread#getContextClassLoader()
         */
        public LdapBeanClassLoader get() {
            LdapBeanClassLoader result;
            ClassLoader parent = Thread.currentThread().getContextClassLoader();
            synchronized (m_Classloaders) {
                result = m_Classloaders.get(parent);
                if (result == null) {
                    result = new LdapBeanClassLoader();
                    m_Classloaders.put(parent, result);
                }
            }
            return result;
        }
    }

    /** package name of the generated classes */
    private final static String GENERATED_PACKAGE = "ldapbeans.bean.generated";

    /** Internal name of the generated classes package */
    private final static String INTERNAL_PACKAGE_NAME = GENERATED_PACKAGE.replace('.', '/');

    /** Instance of the logger for this class */
    private final static Logger LOG = Logger.getLogger();

    /** Singleton instance of this class */
    private final static LdapBeanClassManager INSTANCE;

    /** Message manager instance */
    private final static LdapbeansMessageManager MESSAGE;

    /** the configuration */
    private final static LdapbeansConfiguration CONFIG;

    static {
        INSTANCE = new LdapBeanClassManager();
        MESSAGE = LdapbeansMessageManager.getInstance();
        CONFIG = LdapbeansConfiguration.getInstance();
    }

    /**
     * Return the singleton instance of this class
     * 
     * @return The singleton instance of this class
     */
    public static LdapBeanClassManager getInstance() {
        return INSTANCE;
    }

    /** Counter of generated classes */
    private int m_Count;

    private final Map<GenericKey, Class<?>> m_GeneratedClasses;

    private final LdapBeanClassLoaderManager m_ClassLoader;

    /**
     * Default constructor. This class can not be instantiated.
     */
    private LdapBeanClassManager() {
        m_Count = 0;
        m_GeneratedClasses = new HashMap<GenericKey, Class<?>>();
        m_ClassLoader = new LdapBeanClassLoaderManager();
    }

    /**
     * Return generated LdapBean class that implements interfaces passed in
     * parameter.
     * 
     * @param p_Interfaces
     *            Interfaces that the generated class have to implement
     * @return A generated class
     */
    public Class<?> getClass(Class<?>[] p_Interfaces) {

        Class<?> result;
        GenericKey key = new GenericKey((Object[]) p_Interfaces);
        // String key = getClassKey(p_Interfaces);

        synchronized (m_GeneratedClasses) {
            result = m_GeneratedClasses.get(key);
            if (result == null) {
                result = generateClass(p_Interfaces);
                m_GeneratedClasses.put(key, result);
            }
        }
        return result;
    }

    /**
     * Generate new class that implements all interfaces
     * 
     * @param p_Interfaces
     *            The interfaces to implement
     * @return The new Class
     */
    private Class<?> generateClass(Class<?>[] p_Interfaces) {

        String className = "LdapBeanGenerated" + m_Count++;

        String superClass = Object.class.getName().replace('.', '/');
        String[] interfaces = new String[p_Interfaces.length];
        for (int i = 0; i < p_Interfaces.length; i++) {
            interfaces[i] = p_Interfaces[i].getName().replace('.', '/');
        }

        ClassWriter cw = new ClassWriter(COMPUTE_MAXS + COMPUTE_FRAMES);
        cw.visit(V1_5, ACC_PUBLIC, INTERNAL_PACKAGE_NAME + '/' + className, null, superClass, interfaces);
        // Create fields
        generateField(cw);
        // create constructor
        generateConstructor(cw, className);
        // Create methods
        Set<String> generatedMethod = new HashSet<String>();
        for (Class<?> clazz : p_Interfaces) {
            for (Method method : clazz.getMethods()) {
                generateMethod(cw, className, method, generatedMethod);
            }
        }
        // Generate other method
        try {
            generateMethod(cw, className, Object.class.getMethod("toString"), generatedMethod);
            generateMethod(cw, className, Object.class.getMethod("equals", Object.class), generatedMethod);
        } catch (Exception e) {
            // Do nothing, Object's method will be used
        }
        cw.visitEnd();

        byte[] datas = cw.toByteArray();

        String generatedClassPath = CONFIG.getGeneratedClassPath();
        if (generatedClassPath != null) {
            String filename = className + ".class";
            File parent = new File(generatedClassPath, INTERNAL_PACKAGE_NAME);
            if (!parent.exists()) {
                parent.mkdirs();
            }
            File file = new File(parent, filename);
            LOG.debug(MESSAGE.getGeneratedClassWriteMessage(className, file.getAbsolutePath()));
            try {
                FileOutputStream fos = new FileOutputStream(file);
                fos.write(datas);
            } catch (Exception e) {
                LOG.error(MESSAGE.getGeneratedClassWriteErrorMessage(className, file.getAbsolutePath()), e);
            }
        } else {
            LOG.debug(MESSAGE.getGeneratedClassWriteMessage(className, generatedClassPath));
        }

        return m_ClassLoader.get().defineClass(GENERATED_PACKAGE + '.' + className, datas);
    }

    /**
     * Generate Fields of the generated class
     * 
     * @param p_ClassWriter
     *            The {@link ClassWriter} of the generated class
     */
    private void generateField(ClassWriter p_ClassWriter) {
        FieldVisitor fv;
        // generate "LdapBeanManager m_LdapBeanManager;"
        {
            fv = p_ClassWriter.visitField(ACC_PRIVATE + ACC_FINAL, "m_LdapBeanManager",
                    "Lldapbeans/bean/LdapBeanManager;", null, null);
            fv.visitEnd();
        }
        // generate "LdapObjectManager m_LdapObjectManager;"
        {
            fv = p_ClassWriter.visitField(ACC_PRIVATE + ACC_FINAL, "m_LdapObjectManager",
                    "Lldapbeans/bean/LdapObjectManager;", null, null);
            fv.visitEnd();
        }
        // generate "LdapObject m_LdapObject;"
        {
            fv = p_ClassWriter.visitField(ACC_PRIVATE + ACC_FINAL, "m_LdapObject", "Lldapbeans/bean/LdapObject;",
                    null, null);
            fv.visitEnd();
        }
    }

    /**
     * Generate constructor of the generated class
     * 
     * @param p_ClassWriter
     *            The {@link ClassWriter} of the generated class
     * @param p_ClassName
     *            The name of the class
     */
    private void generateConstructor(ClassWriter p_ClassWriter, String p_ClassName) {
        MethodVisitor mv;
        // Generate "<init>(LdapBeanManager, LdapObjectManager, LdapObject)"
        mv = p_ClassWriter.visitMethod(ACC_PUBLIC, "<init>", "(Lldapbeans/bean/LdapBeanManager;"
                + "Lldapbeans/bean/LdapObjectManager;" + "Lldapbeans/bean/LdapObject;)V", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitFieldInsn(PUTFIELD, INTERNAL_PACKAGE_NAME + '/' + p_ClassName, "m_LdapBeanManager",
                "Lldapbeans/bean/LdapBeanManager;");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(ALOAD, 2);
        mv.visitFieldInsn(PUTFIELD, INTERNAL_PACKAGE_NAME + '/' + p_ClassName, "m_LdapObjectManager",
                "Lldapbeans/bean/LdapObjectManager;");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(ALOAD, 3);
        mv.visitFieldInsn(PUTFIELD, INTERNAL_PACKAGE_NAME + '/' + p_ClassName, "m_LdapObject",
                "Lldapbeans/bean/LdapObject;");
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Generate a method of the generated class
     * 
     * @param p_ClassWriter
     *            The {@link ClassWriter} of the generated class
     * @param p_ClassName
     *            The name of the class
     * @param p_Method
     *            the method to generate
     * @param p_GeneratedMethod
     *            Set of already generated methods
     */
    private void generateMethod(ClassWriter p_ClassWriter, String p_ClassName, Method p_Method,
            Set<String> p_GeneratedMethod) {

        LOG.debug(MESSAGE.getGeneratedMethodMessage(p_ClassName, p_Method));
        String methodDescriptor = Type.getMethodDescriptor(p_Method);
        String key = p_Method.getName() + methodDescriptor;
        if (!p_GeneratedMethod.contains(key)) {
            try {
                if (p_Method.equals(LdapBean.class.getMethod("getDN"))) {
                    generateMethodGetDn(p_ClassWriter, p_ClassName, p_Method, methodDescriptor);
                } else if (p_Method.equals(LdapBean.class.getMethod("store"))) {
                    generateMethodStore(p_ClassWriter, p_ClassName, p_Method, methodDescriptor);
                } else if (p_Method.equals(LdapBean.class.getMethod("restore"))) {
                    generateMethodRestore(p_ClassWriter, p_ClassName, p_Method, methodDescriptor);
                } else if (p_Method.equals(LdapBean.class.getMethod("move", String.class))) {
                    generateMethodMove(p_ClassWriter, p_ClassName, p_Method, methodDescriptor);
                } else if (p_Method.equals(LdapBean.class.getMethod("remove"))) {
                    generateMethodRemove(p_ClassWriter, p_ClassName, p_Method, methodDescriptor);
                } else if (p_Method.equals(Object.class.getMethod("toString"))) {
                    generateMethodToString(p_ClassWriter, p_ClassName, p_Method, methodDescriptor);
                } else if (p_Method.equals(Object.class.getMethod("equals", Object.class))) {
                    generateMethodEquals(p_ClassWriter, p_ClassName, p_Method, methodDescriptor);
                } else {
                    generateMethod(p_ClassWriter, p_ClassName, p_Method, methodDescriptor,
                            p_GeneratedMethod.size() * 100);
                }
                p_GeneratedMethod.add(key);
            } catch (Exception e) {
                // Should not happen
                // Nothing to do, the method should not be generated
                LOG.error(MESSAGE.getGeneratedClassErrorMessage(p_ClassName, p_Method), e);
            }
        } else {
            LOG.warn(MESSAGE.getGeneratedMethodExistsMessage(p_ClassName, p_Method));
        }
    }

    /**
     * Generate a method of the generated class
     * 
     * @param p_ClassWriter
     *            The {@link ClassWriter} of the generated class
     * @param p_ClassName
     *            The name of the class
     * @param p_Method
     *            the method to generate
     * @param p_MethodDescriptor
     *            The method descriptor
     */
    private void generateMethodGetDn(ClassWriter p_ClassWriter, String p_ClassName, Method p_Method,
            String p_MethodDescriptor) {
        MethodVisitor mv = p_ClassWriter.visitMethod(ACC_PUBLIC, p_Method.getName(), p_MethodDescriptor, null,
                null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, INTERNAL_PACKAGE_NAME + '/' + p_ClassName, "m_LdapObject",
                "Lldapbeans/bean/LdapObject;");
        mv.visitMethodInsn(INVOKEVIRTUAL, "ldapbeans/bean/LdapObject", "getDn", "()Ljava/lang/String;");
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Generate a method of the generated class
     * 
     * @param p_ClassWriter
     *            The {@link ClassWriter} of the generated class
     * @param p_ClassName
     *            The name of the class
     * @param p_Method
     *            the method to generate
     * @param p_MethodDescriptor
     *            The method descriptor
     */
    private void generateMethodStore(ClassWriter p_ClassWriter, String p_ClassName, Method p_Method,
            String p_MethodDescriptor) {
        MethodVisitor mv = p_ClassWriter.visitMethod(ACC_PUBLIC, "store", "()V", null,
                new String[] { "javax/naming/NamingException" });
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, INTERNAL_PACKAGE_NAME + '/' + p_ClassName, "m_LdapObjectManager",
                "Lldapbeans/bean/LdapObjectManager;");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, INTERNAL_PACKAGE_NAME + '/' + p_ClassName, "m_LdapObject",
                "Lldapbeans/bean/LdapObject;");
        mv.visitMethodInsn(INVOKEVIRTUAL, "ldapbeans/bean/LdapObjectManager", "storeLdapObject",
                "(Lldapbeans/bean/LdapObject;)V");
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Generate a method of the generated class
     * 
     * @param p_ClassWriter
     *            The {@link ClassWriter} of the generated class
     * @param p_ClassName
     *            The name of the class
     * @param p_Method
     *            the method to generate
     * @param p_MethodDescriptor
     *            The method descriptor
     */
    private void generateMethodRestore(ClassWriter p_ClassWriter, String p_ClassName, Method p_Method,
            String p_MethodDescriptor) {
        MethodVisitor mv = p_ClassWriter.visitMethod(ACC_PUBLIC, "restore", "()V", null,
                new String[] { "javax/naming/NamingException" });
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, INTERNAL_PACKAGE_NAME + '/' + p_ClassName, "m_LdapObjectManager",
                "Lldapbeans/bean/LdapObjectManager;");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, INTERNAL_PACKAGE_NAME + '/' + p_ClassName, "m_LdapObject",
                "Lldapbeans/bean/LdapObject;");
        mv.visitMethodInsn(INVOKEVIRTUAL, "ldapbeans/bean/LdapObjectManager", "restoreLdapObject",
                "(Lldapbeans/bean/LdapObject;)V");
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Generate a method of the generated class
     * 
     * @param p_ClassWriter
     *            The {@link ClassWriter} of the generated class
     * @param p_ClassName
     *            The name of the class
     * @param p_Method
     *            the method to generate
     * @param p_MethodDescriptor
     *            The method descriptor
     */
    private void generateMethodMove(ClassWriter p_ClassWriter, String p_ClassName, Method p_Method,
            String p_MethodDescriptor) {
        MethodVisitor mv = p_ClassWriter.visitMethod(ACC_PUBLIC, "move", "(Ljava/lang/String;)V", null,
                new String[] { "javax/naming/NamingException" });
        mv.visitCode();
        // this.m_LdapObjectManager.moveLdapObject(this.m_LdapObject, p_Dn);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, INTERNAL_PACKAGE_NAME + '/' + p_ClassName, "m_LdapObjectManager",
                "Lldapbeans/bean/LdapObjectManager;");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, INTERNAL_PACKAGE_NAME + '/' + p_ClassName, "m_LdapObject",
                "Lldapbeans/bean/LdapObject;");
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(INVOKEVIRTUAL, "ldapbeans/bean/LdapObjectManager", "moveLdapObject",
                "(Lldapbeans/bean/LdapObject;Ljava/lang/String;)V");
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Generate a method of the generated class
     * 
     * @param p_ClassWriter
     *            The {@link ClassWriter} of the generated class
     * @param p_ClassName
     *            The name of the class
     * @param p_Method
     *            the method to generate
     * @param p_MethodDescriptor
     *            The method descriptor
     */
    private void generateMethodRemove(ClassWriter p_ClassWriter, String p_ClassName, Method p_Method,
            String p_MethodDescriptor) {
        MethodVisitor mv = p_ClassWriter.visitMethod(ACC_PUBLIC, "remove", "()V", null,
                new String[] { "javax/naming/NamingException" });
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, INTERNAL_PACKAGE_NAME + '/' + p_ClassName, "m_LdapObjectManager",
                "Lldapbeans/bean/LdapObjectManager;");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, INTERNAL_PACKAGE_NAME + '/' + p_ClassName, "m_LdapObject",
                "Lldapbeans/bean/LdapObject;");
        mv.visitMethodInsn(INVOKEVIRTUAL, "ldapbeans/bean/LdapObjectManager", "removeLdapObject",
                "(Lldapbeans/bean/LdapObject;)V");
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Generate a method of the generated class
     * 
     * @param p_ClassWriter
     *            The {@link ClassWriter} of the generated class
     * @param p_ClassName
     *            The name of the class
     * @param p_Method
     *            the method to generate
     * @param p_MethodDescriptor
     *            The method descriptor
     */
    private void generateMethodToString(ClassWriter p_ClassWriter, String p_ClassName, Method p_Method,
            String p_MethodDescriptor) {
        MethodVisitor mv = p_ClassWriter.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, INTERNAL_PACKAGE_NAME + '/' + p_ClassName, "m_LdapObject",
                "Lldapbeans/bean/LdapObject;");
        mv.visitMethodInsn(INVOKEVIRTUAL, "ldapbeans/bean/LdapObject", "toString", "()Ljava/lang/String;");
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Generate a method of the generated class
     * 
     * @param p_ClassWriter
     *            The {@link ClassWriter} of the generated class
     * @param p_ClassName
     *            The name of the class
     * @param p_Method
     *            the method to generate
     * @param p_MethodDescriptor
     *            The method descriptor
     */
    private void generateMethodEquals(ClassWriter p_ClassWriter, String p_ClassName, Method p_Method,
            String p_MethodDescriptor) {
        MethodVisitor mv = p_ClassWriter.visitMethod(ACC_PUBLIC, "equals", "(Ljava/lang/Object;)Z", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 1);
        mv.visitTypeInsn(INSTANCEOF, "ldapbeans/bean/LdapBean");
        Label l0 = new Label();
        mv.visitJumpInsn(IFEQ, l0);
        mv.visitVarInsn(ALOAD, 1);
        Label l1 = new Label();
        mv.visitJumpInsn(IFNULL, l1);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKEINTERFACE, "ldapbeans/bean/LdapBean", "getDN", "()Ljava/lang/String;");
        mv.visitVarInsn(ALOAD, 1);
        mv.visitTypeInsn(CHECKCAST, "ldapbeans/bean/LdapBean");
        mv.visitMethodInsn(INVOKEINTERFACE, "ldapbeans/bean/LdapBean", "getDN", "()Ljava/lang/String;");
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z");
        mv.visitJumpInsn(IFEQ, l1);
        mv.visitInsn(ICONST_1);
        mv.visitInsn(IRETURN);
        mv.visitLabel(l1);
        mv.visitInsn(ICONST_0);
        mv.visitInsn(IRETURN);
        mv.visitLabel(l0);
        mv.visitInsn(ICONST_0);
        mv.visitInsn(IRETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Generate a method of the generated class
     * 
     * @param p_ClassWriter
     *            The {@link ClassWriter} of the generated class
     * @param p_ClassName
     *            The name of the class
     * @param p_Method
     *            the method to generate
     * @param p_MethodDescriptor
     *            The method descriptor
     * @param p_LineNumber
     *            Line number of the method (used for debug)
     */
    private void generateMethod(ClassWriter p_ClassWriter, String p_ClassName, Method p_Method,
            String p_MethodDescriptor, final int p_LineNumber) {
        Class<?> returnType = p_Method.getReturnType();
        Class<?>[] parameterTypes = p_Method.getParameterTypes();
        LdapAttribute ldapAttribute = LdapBeanHelper.getInstance().getLdapAttribute(p_Method);

        MethodVisitor mv = p_ClassWriter.visitMethod(ACC_PUBLIC, p_Method.getName(), p_MethodDescriptor, null,
                null);
        if (CONFIG.isDebugLineNumberEnabled()) {
            // Add line number debug information
            mv = new MethodAdapter(mv) {
                private int m_LineNumber = p_LineNumber;

                public void visitLineNumber(int p_Line, Label p_Start) {
                }

                public void visitLabel(Label p_Label) {
                    Label l0 = new Label();
                    super.visitLabel(l0);
                    super.visitLineNumber(m_LineNumber++, l0);
                    super.visitLabel(p_Label);
                };

                public void visitVarInsn(int p_Opcode, int p_Var) {
                    Label l0 = new Label();
                    super.visitLabel(l0);
                    super.visitLineNumber(m_LineNumber++, l0);
                    super.visitVarInsn(p_Opcode, p_Var);
                }
            };
        }
        mv.visitCode();
        if (void.class.equals(returnType) && (parameterTypes.length > 0)) {
            // It must be a setter
            generateMethodSetter(mv, p_ClassName, p_Method, ldapAttribute, parameterTypes);
        } else if ((!void.class.equals(returnType)) && (parameterTypes.length == 0)) {
            // It must be a getter
            generateMethodGetter(mv, p_ClassName, ldapAttribute, returnType);
        } else {
            throw new UnsupportedOperationException();
        }
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Generate a method of the generated class
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            The name of the class
     * @param p_Method
     *            the generated method
     * @param p_LdapAttribute
     *            The LdapAttribute that will be used for generating the method
     * @param p_ParameterTypes
     *            The type of the generated method parameters
     */
    private void generateMethodSetter(MethodVisitor p_MethodVisitor, String p_ClassName, Method p_Method,
            LdapAttribute p_LdapAttribute, Class<?>[] p_ParameterTypes) {
        MethodVisitor mv = p_MethodVisitor;
        int startIndex = getStackIndexOfParameter(p_Method, p_ParameterTypes.length);
        generateMethodSetterInitializeAttribute(mv, p_ClassName, p_Method, startIndex, p_LdapAttribute);
        initializeTempResult(mv, startIndex, p_Method);
        for (int i = 0; i < p_ParameterTypes.length; i++) {
            generateMethodSetterAssignValue(mv, p_ClassName, p_Method, i, startIndex, p_LdapAttribute,
                    p_ParameterTypes[i]);
        }
        generateMethodSetterAssignResult(mv, p_ClassName, p_Method, startIndex, p_LdapAttribute);
        // return;
        mv.visitInsn(RETURN);
    }

    /**
     * Generate a method of the generated class
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            The name of the class
     * @param p_Method
     *            the generated method
     * @param p_StartIndex
     *            First index of the stack after parameters
     * @param p_LdapAttribute
     *            The LdapAttribute that will be used for generating the method
     */
    private void generateMethodSetterInitializeAttribute(MethodVisitor p_MethodVisitor, String p_ClassName,
            Method p_Method, int p_StartIndex, LdapAttribute p_LdapAttribute) {
        MethodVisitor mv = p_MethodVisitor;
        String attributeName = p_LdapAttribute.value();
        // Attributes attributes = m_LdapObject.getAttributes();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, INTERNAL_PACKAGE_NAME + '/' + p_ClassName, "m_LdapObject",
                "Lldapbeans/bean/LdapObject;");
        mv.visitMethodInsn(INVOKEVIRTUAL, "ldapbeans/bean/LdapObject", "getAttributes",
                "()Ljavax/naming/directory/Attributes;");
        mv.visitVarInsn(ASTORE, p_StartIndex + 2);
        // Attribute attribute = attributes.get("attributeName");
        mv.visitVarInsn(ALOAD, p_StartIndex + 2);
        mv.visitLdcInsn(attributeName);
        mv.visitMethodInsn(INVOKEINTERFACE, "javax/naming/directory/Attributes", "get",
                "(Ljava/lang/String;)Ljavax/naming/directory/Attribute;");
        mv.visitVarInsn(ASTORE, p_StartIndex + 3);
        // if (attribute == null) {
        mv.visitVarInsn(ALOAD, p_StartIndex + 3);
        Label l0 = new Label();
        mv.visitJumpInsn(IFNONNULL, l0);
        // attribute = new BasicAttribute("attributeName");
        mv.visitTypeInsn(NEW, "javax/naming/directory/BasicAttribute");
        mv.visitInsn(DUP);
        mv.visitLdcInsn(attributeName);
        mv.visitMethodInsn(INVOKESPECIAL, "javax/naming/directory/BasicAttribute", "<init>",
                "(Ljava/lang/String;)V");
        mv.visitVarInsn(ASTORE, p_StartIndex + 3);
        // attributes.put(attribute);
        mv.visitVarInsn(ALOAD, p_StartIndex + 2);
        mv.visitVarInsn(ALOAD, p_StartIndex + 3);
        mv.visitMethodInsn(INVOKEINTERFACE, "javax/naming/directory/Attributes", "put",
                "(Ljavax/naming/directory/Attribute;)" + "Ljavax/naming/directory/Attribute;");
        mv.visitInsn(POP);
        if (!p_Method.getName().startsWith("add")) {
            /*
             * If method is not an adder (but a simple setter), attribute has to
             * be cleared
             */
            // } else {
            Label l1 = new Label();
            mv.visitJumpInsn(GOTO, l1);
            mv.visitLabel(l0);
            // attribute.clear();
            mv.visitVarInsn(ALOAD, p_StartIndex + 3);
            mv.visitMethodInsn(INVOKEINTERFACE, "javax/naming/directory/Attribute", "clear", "()V");
            // }
            mv.visitLabel(l1);
        } else {
            // }
            mv.visitLabel(l0);
        }
    }

    /**
     * generate code that initialize variable corresponding to temporary result
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_Method
     *            the generated method
     * @param p_StartStack
     *            First index of the stack after parameters
     */
    private void initializeTempResult(MethodVisitor p_MethodVisitor, int p_StartStack, Method p_Method) {
        MethodVisitor mv = p_MethodVisitor;
        mv.visitInsn(ICONST_0);
        mv.visitVarInsn(ISTORE, p_StartStack + 1);

        Class<?>[] parameterTypes = p_Method.getParameterTypes();
        ConvertAttribute[] annotations = getConvertAttributeAnnotation(p_Method);
        int nbArray = 0;
        for (int i = 0; i < parameterTypes.length; i++) {
            if ((parameterTypes[i].isArray() || Collection.class.isAssignableFrom(parameterTypes[i]))
                    && annotations[i] == null) {
                int paramStackIndex = getStackIndexOfParameter(p_Method, i);
                mv.visitVarInsn(ILOAD, p_StartStack + 1);
                mv.visitVarInsn(ALOAD, paramStackIndex);
                if (parameterTypes[i].isArray()) {
                    mv.visitInsn(ARRAYLENGTH);
                } else if (Collection.class.isAssignableFrom(parameterTypes[i])) {
                    mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Collection", "size", "()I");
                }
                mv.visitInsn(IADD);
                mv.visitVarInsn(ISTORE, p_StartStack + 1);
                nbArray++;
            }
        }
        if (nbArray != 0) {
            mv.visitVarInsn(ILOAD, p_StartStack + 1);
        }
        if (parameterTypes.length != nbArray) {
            mv.visitIntInsn(BIPUSH, parameterTypes.length - nbArray);
        }
        if (nbArray != 0 && parameterTypes.length != nbArray) {
            mv.visitInsn(IADD);
        }
        mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
        mv.visitVarInsn(ASTORE, p_StartStack);
        mv.visitInsn(ICONST_0);
        mv.visitVarInsn(ISTORE, p_StartStack + 1);
    }

    /**
     * Generate a portion of a method of the generated class
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            The name of the class
     * @param p_Method
     *            the generated method
     * @param p_ParamIndex
     *            index of the parameter to convert
     * @param p_StartIndex
     *            first index of the stack after parameters
     * @param p_LdapAttribute
     *            The LdapAttribute that will be used for generating the method
     * @param p_ParameterType
     *            The type of the parameter
     */
    private void generateMethodSetterAssignValue(MethodVisitor p_MethodVisitor, String p_ClassName, Method p_Method,
            int p_ParamIndex, int p_StartIndex, LdapAttribute p_LdapAttribute, Class<?> p_ParameterType) {
        MethodVisitor mv = p_MethodVisitor;
        int paramStackIndex = getStackIndexOfParameter(p_Method, p_ParamIndex);
        ConvertAttribute annotation = getConvertAttributeAnnotation(p_Method)[p_ParamIndex];

        if (Collection.class.isAssignableFrom(p_ParameterType)) {
            /*
             * The parameter is a collection, each element of the collection
             * will be added
             */
            // Iterator it = p_AttributeValue.iterator();
            mv.visitVarInsn(ALOAD, paramStackIndex);
            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Collection", "iterator", "()Ljava/util/Iterator;");
            mv.visitVarInsn(ASTORE, p_StartIndex + 5);
            // while(it.hasNext()) {
            Label l2 = new Label();
            mv.visitLabel(l2);
            mv.visitVarInsn(ALOAD, p_StartIndex + 5);
            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "hasNext", "()Z");
            Label l3 = new Label();
            mv.visitJumpInsn(IFEQ, l3);

            // Object value = it.next();
            mv.visitVarInsn(ALOAD, p_StartIndex + 5);
            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Iterator", "next", "()Ljava/lang/Object;");
            mv.visitVarInsn(ASTORE, p_StartIndex + 4);
            // convert value to String
            // TODO : Find another way to convert object
            generateMethodSetterAssignValueConvert(mv, p_ClassName, p_Method, p_StartIndex + 4, p_StartIndex,
                    p_LdapAttribute, annotation, Object.class);
            generateMethodSetterAssignValueToTempArray(mv, p_ClassName, p_Method, p_StartIndex + 4, p_StartIndex);
            // }
            mv.visitJumpInsn(GOTO, l2);
            mv.visitLabel(l3);
        } else if (p_ParameterType.isArray()) {
            // TODO
            // int i=0;
            mv.visitInsn(ICONST_0);
            mv.visitVarInsn(ISTORE, p_StartIndex + 5);
            // while(i<values.length) {
            Label l0 = new Label();
            Label l1 = new Label();
            mv.visitLabel(l0);
            mv.visitVarInsn(ILOAD, p_StartIndex + 5);
            mv.visitVarInsn(ALOAD, paramStackIndex);
            mv.visitInsn(ARRAYLENGTH);
            mv.visitJumpInsn(IF_ICMPGE, l1);
            // value = values[i];
            mv.visitVarInsn(ALOAD, paramStackIndex);
            mv.visitVarInsn(ILOAD, p_StartIndex + 1);
            mv.visitInsn(AALOAD);
            mv.visitVarInsn(ASTORE, p_StartIndex + 4);
            // convert value to String
            generateMethodSetterAssignValueConvert(mv, p_ClassName, p_Method, p_StartIndex + 4, p_StartIndex,
                    p_LdapAttribute, annotation, p_ParameterType.getComponentType());
            generateMethodSetterAssignValueToTempArray(mv, p_ClassName, p_Method, p_StartIndex + 4, p_StartIndex);
            // i++;
            mv.visitIincInsn(p_StartIndex + 5, 1);
            // }
            mv.visitJumpInsn(GOTO, l0);
            mv.visitLabel(l1);
        } else {
            generateMethodSetterAssignValueConvert(mv, p_ClassName, p_Method, paramStackIndex, p_StartIndex,
                    p_LdapAttribute, annotation, p_ParameterType);
            generateMethodSetterAssignValueToTempArray(mv, p_ClassName, p_Method, p_StartIndex + 4, p_StartIndex);
        }
    }

    /**
     * Generate a method of the generated class
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            The name of the class
     * @param p_Method
     *            the generated method
     * @param p_ObjectIndex
     *            Index in the stack of the object to add to the temporary
     *            result array
     * @param p_StartIndex
     *            First index of the stack after parameters
     */
    private void generateMethodSetterAssignValueToTempArray(MethodVisitor p_MethodVisitor, String p_ClassName,
            Method p_Method, int p_ObjectIndex, int p_StartIndex) {
        MethodVisitor mv = p_MethodVisitor;
        mv.visitVarInsn(ALOAD, p_StartIndex);
        mv.visitVarInsn(ILOAD, p_StartIndex + 1);
        mv.visitIincInsn(p_StartIndex + 1, 1);
        mv.visitVarInsn(ALOAD, p_ObjectIndex);
        mv.visitInsn(AASTORE);
    }

    /**
     * Generate a method of the generated class
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            The name of the class
     * @param p_Method
     *            the generated method
     * @param p_StartIndex
     *            First index of the stack after parameters
     * @param p_LdapAttribute
     *            LdapAttribute of the generated method
     */
    private void generateMethodSetterAssignResult(MethodVisitor p_MethodVisitor, String p_ClassName,
            Method p_Method, int p_StartIndex, LdapAttribute p_LdapAttribute) {
        MethodVisitor mv = p_MethodVisitor;
        if (p_LdapAttribute.pattern().length() == 0) {
            // int i=0;
            mv.visitInsn(ICONST_0);
            mv.visitVarInsn(ISTORE, p_StartIndex + 1);
            // {
            Label l0 = new Label();
            mv.visitJumpInsn(GOTO, l0);
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitVarInsn(ALOAD, p_StartIndex + 3);
            // value = tempValues[i];
            mv.visitVarInsn(ALOAD, p_StartIndex);
            mv.visitVarInsn(ILOAD, p_StartIndex + 1);
            mv.visitInsn(AALOAD);
            // attribute.add(value);
            mv.visitMethodInsn(INVOKEINTERFACE, "javax/naming/directory/Attribute", "add", "(Ljava/lang/Object;)Z");
            mv.visitInsn(POP);
            // i++
            mv.visitIincInsn(p_StartIndex + 1, 1);
            // }
            mv.visitLabel(l0);
            // i < tempValues.length
            mv.visitVarInsn(ILOAD, p_StartIndex + 1);
            mv.visitVarInsn(ALOAD, p_StartIndex);
            mv.visitInsn(ARRAYLENGTH);
            mv.visitJumpInsn(IF_ICMPLT, l1);
        } else {
            mv.visitVarInsn(ALOAD, p_StartIndex + 3);
            mv.visitLdcInsn(p_LdapAttribute.pattern());
            mv.visitVarInsn(ALOAD, p_StartIndex);
            mv.visitMethodInsn(INVOKESTATIC, "ldapbeans/util/StringUtil", "format",
                    "(Ljava/lang/String;[Ljava/lang/Object;)" + "Ljava/lang/String;");
            // attribute.add(value);
            mv.visitMethodInsn(INVOKEINTERFACE, "javax/naming/directory/Attribute", "add", "(Ljava/lang/Object;)Z");
            mv.visitInsn(POP);
        }

    }

    /**
     * Generate a portion of a method of the generated class
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            The name of the class
     * @param p_Method
     *            the generated method
     * @param p_ObjectStackIndex
     *            index of the object to convert in the stack
     * @param p_StartIndex
     *            first index of the stack after parameters
     * @param p_LdapAttribute
     *            The LdapAttribute that will be used for generating the method
     * @param p_Annotation
     *            Annotation of the used parameter
     * @param p_OriginalType
     *            The type before conversion
     */
    private void generateMethodSetterAssignValueConvert(MethodVisitor p_MethodVisitor, String p_ClassName,
            Method p_Method, int p_ObjectStackIndex, int p_StartIndex, LdapAttribute p_LdapAttribute,
            ConvertAttribute p_Annotation, Class<?> p_OriginalType) {
        MethodVisitor mv = p_MethodVisitor;
        /* the parameter is a simple type, it is simply added */
        if ((Boolean.class.equals(p_OriginalType) || boolean.class.equals(p_OriginalType))) {
            // String value = p_AttributeValue?"true":"false";
            generateMethodSetterAssignValueConvertBoolean(p_MethodVisitor, p_ObjectStackIndex, p_StartIndex,
                    p_LdapAttribute, p_OriginalType);
        } else if (Number.class.isAssignableFrom(p_OriginalType)) {
            // String value = String.valueOf(p_AttributeValue);
            generateMethodSetterAssignValueConvertNumber(p_MethodVisitor, p_ObjectStackIndex, p_StartIndex,
                    p_OriginalType);
        } else if (p_OriginalType.isPrimitive()) {
            // String value = String.valueOf(p_AttributeValue);
            generateMethodSetterAssignValueConvertPrimitive(p_MethodVisitor, p_ObjectStackIndex, p_StartIndex,
                    p_OriginalType);
        } else if (String.class.isAssignableFrom(p_OriginalType)) {
            // String value = p_AttributeValue;
            generateMethodSetterAssignValueConvertString(p_MethodVisitor, p_ObjectStackIndex, p_StartIndex,
                    p_OriginalType);
        } else if (LdapBean.class.isAssignableFrom(p_OriginalType)) {
            // String value = p_AttributeValue.getDN();
            generateMethodSetterAssignValueConvertLdapBean(p_MethodVisitor, p_ClassName, p_Method,
                    p_ObjectStackIndex, p_StartIndex, p_Annotation, p_OriginalType);
        } else {
            // String value = String.valueOf(p_AttributeValue);
            mv.visitVarInsn(ALOAD, p_ObjectStackIndex);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf",
                    "(Ljava/lang/Object;)Ljava/lang/String;");
            mv.visitVarInsn(ASTORE, p_StartIndex + 4);
        }
    }

    /**
     * Generate a portion of a method of the generated class
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ObjectStackIndex
     *            index of the object to convert in the stack
     * @param p_StartIndex
     *            first index of the stack after parameters
     * @param p_LdapAttribute
     *            The LdapAttribute that will be used for generating the method
     * @param p_OriginalType
     *            The type before conversion
     */
    private void generateMethodSetterAssignValueConvertBoolean(MethodVisitor p_MethodVisitor,
            int p_ObjectStackIndex, int p_StartIndex, LdapAttribute p_LdapAttribute, Class<?> p_OriginalType) {
        MethodVisitor mv = p_MethodVisitor;
        if (Boolean.class.equals(p_OriginalType)) {
            mv.visitVarInsn(ALOAD, p_ObjectStackIndex);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
        } else {
            mv.visitVarInsn(ILOAD, p_ObjectStackIndex);
        }
        Label l2 = new Label();
        mv.visitJumpInsn(IFEQ, l2);
        mv.visitLdcInsn(p_LdapAttribute.trueValue()[0]);
        Label l3 = new Label();
        mv.visitJumpInsn(GOTO, l3);
        mv.visitLabel(l2);
        mv.visitLdcInsn(p_LdapAttribute.falseValue()[0]);
        mv.visitLabel(l3);
        mv.visitVarInsn(ASTORE, p_StartIndex + 4);
    }

    /**
     * Generate a portion of a method of the generated class
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ObjectStackIndex
     *            index of the object to convert in the stack
     * @param p_StartIndex
     *            first index of the stack after parameters
     * @param p_OriginalType
     *            The type before conversion
     */
    private void generateMethodSetterAssignValueConvertNumber(MethodVisitor p_MethodVisitor, int p_ObjectStackIndex,
            int p_StartIndex, Class<?> p_OriginalType) {
        MethodVisitor mv = p_MethodVisitor;
        mv.visitVarInsn(ALOAD, p_ObjectStackIndex);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
        mv.visitVarInsn(ASTORE, p_StartIndex + 4);
    }

    /**
     * Generate a portion of a method of the generated class
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ObjectStackIndex
     *            index of the object to convert in the stack
     * @param p_StartIndex
     *            first index of the stack after parameters
     * @param p_OriginalType
     *            The type before conversion
     */
    private void generateMethodSetterAssignValueConvertPrimitive(MethodVisitor p_MethodVisitor,
            int p_ObjectStackIndex, int p_StartIndex, Class<?> p_OriginalType) {
        MethodVisitor mv = p_MethodVisitor;
        if (true == double.class.equals(p_OriginalType)) {
            mv.visitVarInsn(DLOAD, p_ObjectStackIndex);
        } else if (true == long.class.equals(p_OriginalType)) {
            mv.visitVarInsn(LLOAD, p_ObjectStackIndex);
        } else if (true == float.class.equals(p_OriginalType)) {
            mv.visitVarInsn(FLOAD, p_ObjectStackIndex);
        } else {
            mv.visitVarInsn(ILOAD, p_ObjectStackIndex);
        }
        if (short.class.equals(p_OriginalType)) {
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "toString", "(S)Ljava/lang/String;");
        } else {
            Type type = Type.getType(p_OriginalType);

            mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf",
                    "(" + type.toString() + ")Ljava/lang/String;");
        }
        mv.visitVarInsn(ASTORE, p_StartIndex + 4);
    }

    /**
     * Generate a portion of a method of the generated class
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ObjectStackIndex
     *            index of the object to convert in the stack
     * @param p_StartIndex
     *            first index of the stack after parameters
     * @param p_OriginalType
     *            The type before conversion
     */
    private void generateMethodSetterAssignValueConvertString(MethodVisitor p_MethodVisitor, int p_ObjectStackIndex,
            int p_StartIndex, Class<?> p_OriginalType) {
        MethodVisitor mv = p_MethodVisitor;
        mv.visitVarInsn(ALOAD, p_ObjectStackIndex);
        mv.visitVarInsn(ASTORE, p_StartIndex + 4);
    }

    /**
     * Generate a portion of a method of the generated class
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            The name of the class
     * @param p_Method
     *            the generated method
     * @param p_ObjectStackIndex
     *            index of the object to convert in the stack
     * @param p_StartIndex
     *            first index of the stack after parameters
     * @param p_Annotation
     *            Annotation of the parameter to convert
     * @param p_OriginalType
     *            The type before conversion
     */
    private void generateMethodSetterAssignValueConvertLdapBean(MethodVisitor p_MethodVisitor, String p_ClassName,
            Method p_Method, int p_ObjectStackIndex, int p_StartIndex, ConvertAttribute p_Annotation,
            Class<?> p_OriginalType) {
        MethodVisitor mv = p_MethodVisitor;
        String methodName = "getDN";
        if (p_Annotation != null) {
            methodName = p_Annotation.method();
        }
        mv.visitVarInsn(ALOAD, p_ObjectStackIndex);
        mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(p_OriginalType), methodName,
                "()Ljava/lang/String;");
        mv.visitVarInsn(ASTORE, p_StartIndex + 4);
    }

    /**
     * Generate a method of the generated class
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            the name of the generated class
     * @param p_LdapAttribute
     *            The LdapAttribute that will be used for generating the method
     * @param p_ReturnType
     *            The type of the generated method result
     */
    private void generateMethodGetter(MethodVisitor p_MethodVisitor, String p_ClassName,
            LdapAttribute p_LdapAttribute, Class<?> p_ReturnType) {
        MethodVisitor mv = p_MethodVisitor;
        // Object result = null;
        generateDefaultValue(p_MethodVisitor, p_ReturnType, 1);
        generateMethodGetterLdapValue(mv, p_ClassName, p_LdapAttribute, p_ReturnType);
        if ((true == boolean.class.equals(p_ReturnType)) || (true == byte.class.equals(p_ReturnType))
                || (true == short.class.equals(p_ReturnType)) || (true == int.class.equals(p_ReturnType))
                || (true == char.class.equals(p_ReturnType))) {
            mv.visitVarInsn(ILOAD, 1);
            mv.visitInsn(IRETURN);
        } else if (long.class.equals(p_ReturnType)) {
            mv.visitVarInsn(LLOAD, 1);
            mv.visitInsn(Opcodes.LRETURN);
        } else if (double.class.equals(p_ReturnType)) {
            mv.visitVarInsn(DLOAD, 1);
            mv.visitInsn(Opcodes.DRETURN);
        } else if (float.class.equals(p_ReturnType)) {
            mv.visitVarInsn(FLOAD, 1);
            mv.visitInsn(Opcodes.FRETURN);
        } else {
            // return result;
            mv.visitVarInsn(ALOAD, 1);
            mv.visitInsn(ARETURN);
        }
    }

    /**
     * Generate a method of the generated class
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            The name of the class
     * @param p_LdapAttribute
     *            The LdapAttribute that will be used for generating the method
     * @param p_ReturnType
     *            The type of the result
     */
    private void generateMethodGetterLdapValue(MethodVisitor p_MethodVisitor, String p_ClassName,
            LdapAttribute p_LdapAttribute, Class<?> p_ReturnType) {
        MethodVisitor mv = p_MethodVisitor;
        String attributeName = p_LdapAttribute.value();
        Label l0 = new Label();
        Label l1 = new Label();
        Label l2 = new Label();
        mv.visitTryCatchBlock(l0, l1, l2, "javax/naming/NamingException");
        // Attributes attributes = m_LdapObject.getAttributes();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, INTERNAL_PACKAGE_NAME + '/' + p_ClassName, "m_LdapObject",
                "Lldapbeans/bean/LdapObject;");
        mv.visitMethodInsn(INVOKEVIRTUAL, "ldapbeans/bean/LdapObject", "getAttributes",
                "()Ljavax/naming/directory/Attributes;");
        mv.visitVarInsn(ASTORE, 3);
        // Attribute attribute = attributes.get("attributeName");
        mv.visitVarInsn(ALOAD, 3);
        mv.visitLdcInsn(attributeName);
        mv.visitMethodInsn(INVOKEINTERFACE, "javax/naming/directory/Attributes", "get",
                "(Ljava/lang/String;)Ljavax/naming/directory/Attribute;");
        mv.visitVarInsn(ASTORE, 4);
        // try {
        mv.visitLabel(l0);
        // if (attribute != null) {
        Label l3 = new Label();
        mv.visitVarInsn(ALOAD, 4);
        mv.visitJumpInsn(IFNULL, l3);
        generateMethodGetterAssignResult(mv, p_ClassName, p_LdapAttribute, p_ReturnType);
        // }
        mv.visitLabel(l1);
        mv.visitJumpInsn(GOTO, l3);
        // } catch(NamingException e) {
        mv.visitLabel(l2);
        mv.visitVarInsn(ASTORE, 5);
        // throw new IllegalArgumentException()
        // TODO: change the message
        generateThrowingIllegalArgumentException(p_MethodVisitor, "Error when trying to get value");
        // }
        mv.visitLabel(l3);
    }

    /**
     * Generate a portion of a method of the generated class
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            Name of the generated class
     * @param p_LdapAttribute
     *            The LdapAttribute that will be used for generating the method
     * @param p_ReturnType
     *            The type of the result
     */
    private void generateMethodGetterAssignResult(MethodVisitor p_MethodVisitor, String p_ClassName,
            LdapAttribute p_LdapAttribute, Class<?> p_ReturnType) {
        MethodVisitor mv = p_MethodVisitor;
        if (Collection.class.isAssignableFrom(p_ReturnType)) {
            generateMethodGetterAssignResultCollection(p_MethodVisitor, p_ClassName, p_LdapAttribute, p_ReturnType);
        } else if (true == p_ReturnType.isArray()) {
            generateMethodGetterAssignResultArray(p_MethodVisitor, p_ClassName, p_LdapAttribute, p_ReturnType);
        } else {
            generateMethodGetterAssignResultSimple(mv, p_ClassName, p_LdapAttribute, p_ReturnType);
        }
    }

    /**
     * Generate a portion of a method of the generated class
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            Name of the generated class
     * @param p_LdapAttribute
     *            The LdapAttribute that will be used for generating the method
     * @param p_ReturnType
     *            The type of the result
     */
    private void generateMethodGetterAssignResultSimple(MethodVisitor p_MethodVisitor, String p_ClassName,
            LdapAttribute p_LdapAttribute, Class<?> p_ReturnType) {
        MethodVisitor mv = p_MethodVisitor;
        // Object value = attribute.get();
        mv.visitVarInsn(ALOAD, 4);
        mv.visitMethodInsn(INVOKEINTERFACE, "javax/naming/directory/Attribute", "get", "()Ljava/lang/Object;");
        mv.visitVarInsn(ASTORE, 5);
        generateConvert(p_MethodVisitor, p_ClassName, p_LdapAttribute, p_ReturnType, 5, 1);
    }

    /**
     * Generate a portion of a method of the generated class
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            Name of the generated class
     * @param p_LdapAttribute
     *            The LdapAttribute that will be used for generating the method
     * @param p_ReturnType
     *            The type of the result
     */
    private void generateMethodGetterAssignResultCollection(MethodVisitor p_MethodVisitor, String p_ClassName,
            LdapAttribute p_LdapAttribute, Class<?> p_ReturnType) {
        MethodVisitor mv = p_MethodVisitor;
        // NamingEnumeration<?> enumeration = attribute.getAll();
        mv.visitVarInsn(ALOAD, 4);
        mv.visitMethodInsn(INVOKEINTERFACE, "javax/naming/directory/Attribute", "getAll",
                "()Ljavax/naming/NamingEnumeration;");
        mv.visitVarInsn(ASTORE, 5);
        // result = new [Collection](attribute.size());
        generateMethodGetterInitializeResult(p_MethodVisitor, p_ReturnType);
        // while (enumeration.hasMoreElements()) {
        Label l4 = new Label();
        mv.visitLabel(l4);
        mv.visitVarInsn(ALOAD, 5);
        mv.visitMethodInsn(INVOKEINTERFACE, "javax/naming/NamingEnumeration", "hasMoreElements", "()Z");
        Label l5 = new Label();
        mv.visitJumpInsn(IFEQ, l5);
        // result.add(enumeration.nextElement());
        mv.visitVarInsn(ALOAD, 5);
        mv.visitMethodInsn(INVOKEINTERFACE, "javax/naming/NamingEnumeration", "nextElement",
                "()Ljava/lang/Object;");
        mv.visitVarInsn(ASTORE, 6);
        generateConvert(p_MethodVisitor, p_ClassName, p_LdapAttribute, p_LdapAttribute.componentType(), 6, 7);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitVarInsn(ALOAD, 7);
        mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Collection", "add", "(Ljava/lang/Object;)Z");
        mv.visitInsn(POP);
        // }
        mv.visitJumpInsn(GOTO, l4);
        mv.visitLabel(l5);
        // enumeration.close();
        mv.visitVarInsn(ALOAD, 5);
        mv.visitMethodInsn(INVOKEINTERFACE, "javax/naming/NamingEnumeration", "close", "()V");
    }

    /**
     * Generate a portion of a method of the generated class
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            Name of the generated class
     * @param p_LdapAttribute
     *            The LdapAttribute that will be used for generating the method
     * @param p_ReturnType
     *            The type of the result
     */
    private void generateMethodGetterAssignResultArray(MethodVisitor p_MethodVisitor, String p_ClassName,
            LdapAttribute p_LdapAttribute, Class<?> p_ReturnType) {
        MethodVisitor mv = p_MethodVisitor;
        // NamingEnumeration<?> enumeration = attribute.getAll();
        mv.visitVarInsn(ALOAD, 4);
        mv.visitMethodInsn(INVOKEINTERFACE, "javax/naming/directory/Attribute", "getAll",
                "()Ljavax/naming/NamingEnumeration;");
        mv.visitVarInsn(ASTORE, 5);
        // result = new Object[attribute.size()];
        generateMethodGetterInitializeResult(p_MethodVisitor, p_ReturnType);
        // int i = 0;
        mv.visitInsn(ICONST_0);
        mv.visitVarInsn(ISTORE, 6);
        // while (enumeration.hasMoreElements()) {
        Label l4 = new Label();
        mv.visitLabel(l4);
        mv.visitVarInsn(ALOAD, 5);
        mv.visitMethodInsn(INVOKEINTERFACE, "javax/naming/NamingEnumeration", "hasMoreElements", "()Z");
        Label l5 = new Label();
        mv.visitJumpInsn(IFEQ, l5);
        // tmp = enumeration.nextElement();
        mv.visitVarInsn(ALOAD, 5);
        mv.visitMethodInsn(INVOKEINTERFACE, "javax/naming/NamingEnumeration", "nextElement",
                "()Ljava/lang/Object;");
        mv.visitVarInsn(ASTORE, 7);
        generateConvert(p_MethodVisitor, p_ClassName, p_LdapAttribute, p_ReturnType.getComponentType(), 7, 8);
        // result[i++] = tmp;
        mv.visitVarInsn(ALOAD, 1);
        mv.visitVarInsn(ILOAD, 6);
        mv.visitIincInsn(6, 1);
        mv.visitVarInsn(ALOAD, 8);
        mv.visitInsn(AASTORE);
        // }
        mv.visitJumpInsn(GOTO, l4);
        mv.visitLabel(l5);
        // enumeration.close();
        mv.visitVarInsn(ALOAD, 5);
        mv.visitMethodInsn(INVOKEINTERFACE, "javax/naming/NamingEnumeration", "close", "()V");
    }

    /**
     * Generate a portion of a method of the generated class
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ReturnType
     *            The type of the result
     */
    private void generateMethodGetterInitializeResult(MethodVisitor p_MethodVisitor, Class<?> p_ReturnType) {
        MethodVisitor mv = p_MethodVisitor;
        // result = new ArrayList<Object>(attribute.size());
        if (p_ReturnType.isArray()) {
            mv.visitVarInsn(ALOAD, 4);
            mv.visitMethodInsn(INVOKEINTERFACE, "javax/naming/directory/Attribute", "size", "()I");
            mv.visitTypeInsn(ANEWARRAY, p_ReturnType.getComponentType().getName().replace('.', '/'));
        } else if (!p_ReturnType.isInterface()) {
            mv.visitTypeInsn(NEW, "java/util/ArrayList");
            mv.visitInsn(DUP);
            mv.visitMethodInsn(INVOKESPECIAL, "java/util/ArrayList", "<init>", "()V");
        } else {
            String resultType;
            if (List.class.isAssignableFrom(p_ReturnType)) {
                resultType = "java/util/ArrayList";
            } else if (Queue.class.isAssignableFrom(p_ReturnType)) {
                resultType = "java/util/concurrent/ArrayBlockingQueue";
            } else if (Set.class.isAssignableFrom(p_ReturnType)) {
                resultType = "java/util/HashSet";
            } else {
                resultType = "java/util/ArrayList";
            }
            mv.visitTypeInsn(NEW, resultType);
            mv.visitInsn(DUP);
            mv.visitVarInsn(ALOAD, 4);
            mv.visitMethodInsn(INVOKEINTERFACE, "javax/naming/directory/Attribute", "size", "()I");
            mv.visitMethodInsn(INVOKESPECIAL, resultType, "<init>", "(I)V");
        }
        mv.visitVarInsn(ASTORE, 1);
    }

    /**
     * Generate code to convert ldapAttribute witch is on the to of the stack to
     * the type of the result
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            Name of the generated class
     * @param p_LdapAttribute
     *            The LdapAttribute that will be used for generating the method
     * @param p_ReturnType
     *            The type of the result
     * @param p_Object
     *            Index of the object to convert on the stack
     * @param p_Result
     *            Index of the converted object on the stack
     */
    private void generateConvert(MethodVisitor p_MethodVisitor, String p_ClassName, LdapAttribute p_LdapAttribute,
            Class<?> p_ReturnType, int p_Object, int p_Result) {
        MethodVisitor mv = p_MethodVisitor;
        Label l0 = new Label();
        Label l1 = new Label();
        if (p_ReturnType != null) {
            // if(value != null) {
            mv.visitVarInsn(ALOAD, p_Object);
            mv.visitJumpInsn(IFNULL, l0);
            if (String.class.isAssignableFrom(p_ReturnType)) {
                generateConvertToString(p_MethodVisitor, p_ClassName, p_ReturnType, p_Object, p_Result);
            } else if (LdapBean.class.isAssignableFrom(p_ReturnType)) {
                generateConvertToLdapBean(p_MethodVisitor, p_ClassName, p_LdapAttribute, p_ReturnType, p_Object,
                        p_Result);
            } else if (boolean.class.isAssignableFrom(p_ReturnType)
                    || Boolean.class.isAssignableFrom(p_ReturnType)) {
                generateConvertToBoolean(p_MethodVisitor, p_ClassName, p_LdapAttribute, p_ReturnType, p_Object,
                        p_Result);
            } else if (Number.class.isAssignableFrom(p_ReturnType)) {
                generateConvertToNumber(p_MethodVisitor, p_ClassName, p_LdapAttribute, p_ReturnType, p_Object,
                        p_Result);
            } else if (p_ReturnType.isPrimitive()) {
                generateConvertToPrimitive(p_MethodVisitor, p_ClassName, p_LdapAttribute, p_ReturnType, p_Object,
                        p_Result);
            } else if (Character.class.isAssignableFrom(p_ReturnType)) {
                // result = Character.valueOf(object.toString().charAt(0));
                mv.visitVarInsn(ALOAD, p_Object);
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
                mv.visitInsn(ICONST_0);
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "charAt", "(I)C");
                mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
                mv.visitVarInsn(ASTORE, p_Result);
            } else {
                mv.visitVarInsn(ALOAD, p_Object);
                mv.visitVarInsn(ASTORE, p_Result);
            }
            // } else {
            mv.visitJumpInsn(GOTO, l1);
            mv.visitLabel(l0);
            // result = null;
            generateDefaultValue(p_MethodVisitor, p_ReturnType, p_Result);
            // }
            mv.visitLabel(l1);
        } else {
            generateConvertToLdapBean(p_MethodVisitor, p_ClassName, p_LdapAttribute, null, p_Object, p_Result);
        }
    }

    /**
     * Generate default value and store it.
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_Type
     *            The type of the default value to generate
     * @param p_StackIndex
     *            The index where the value will be stored
     */
    private void generateDefaultValue(MethodVisitor p_MethodVisitor, Class<?> p_Type, int p_StackIndex) {
        MethodVisitor mv = p_MethodVisitor;
        if (char.class.equals(p_Type)) {
            mv.visitInsn(ICONST_0);
            mv.visitVarInsn(ISTORE, p_StackIndex);
        } else if (byte.class.equals(p_Type)) {
            mv.visitInsn(ICONST_0);
            mv.visitVarInsn(ISTORE, p_StackIndex);
        } else if (short.class.equals(p_Type)) {
            mv.visitInsn(ICONST_0);
            mv.visitVarInsn(ISTORE, p_StackIndex);
        } else if (int.class.equals(p_Type)) {
            mv.visitInsn(ICONST_0);
            mv.visitVarInsn(ISTORE, p_StackIndex);
        } else if (long.class.equals(p_Type)) {
            mv.visitInsn(LCONST_0);
            mv.visitVarInsn(LSTORE, p_StackIndex);
        } else if (float.class.equals(p_Type)) {
            mv.visitInsn(FCONST_0);
            mv.visitVarInsn(FSTORE, p_StackIndex);
        } else if (double.class.equals(p_Type)) {
            mv.visitInsn(Opcodes.DCONST_0);
            mv.visitVarInsn(DSTORE, p_StackIndex);
        } else if (boolean.class.equals(p_Type)) {
            mv.visitInsn(Opcodes.ICONST_0);
            mv.visitVarInsn(ISTORE, p_StackIndex);
        } else {
            mv.visitInsn(ACONST_NULL);
            mv.visitVarInsn(ASTORE, p_StackIndex);
        }

    }

    /**
     * Generate code throwing {@link IllegalArgumentException}
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_Message
     *            The message of the exception, or <code>null</code> if none
     */
    private void generateThrowingIllegalArgumentException(MethodVisitor p_MethodVisitor, String p_Message) {
        MethodVisitor mv = p_MethodVisitor;
        mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
        mv.visitInsn(DUP);
        if (p_Message != null) {
            mv.visitLdcInsn(p_Message);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>",
                    "(Ljava/lang/String;)V");
        } else {
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "()V");
        }
        mv.visitInsn(ATHROW);

    }

    /**
     * Generate code to convert ldapAttribute witch is on the top of the stack
     * to String
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            Name of the generated class
     * @param p_ReturnType
     *            The type of the result
     * @param p_Object
     *            Index of the object to convert on the stack
     * @param p_Result
     *            Index of the converted object on the stack
     */
    private void generateConvertToString(MethodVisitor p_MethodVisitor, String p_ClassName, Class<?> p_ReturnType,
            int p_Object, int p_Result) {
        MethodVisitor mv = p_MethodVisitor;
        // result = value.toString();
        mv.visitVarInsn(ALOAD, p_Object);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
        mv.visitVarInsn(ASTORE, p_Result);
    }

    /**
     * Generate code to convert ldapAttribute witch is on the top of the stack
     * to LdapBean
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            Name of the generated class
     * @param p_LdapAttribute
     *            The LdapAttribute that will be used for generating the method
     * @param p_ReturnType
     *            The type of the result
     * @param p_Object
     *            Index of the object to convert on the stack
     * @param p_Result
     *            Index of the converted object on the stack
     */
    private void generateConvertToLdapBean(MethodVisitor p_MethodVisitor, String p_ClassName,
            LdapAttribute p_LdapAttribute, Class<?> p_ReturnType, int p_Object, int p_Result) {
        MethodVisitor mv = p_MethodVisitor;
        Label l1 = new Label();
        Label l0 = new Label();
        // if(object == null) {
        mv.visitVarInsn(ALOAD, p_Object);
        mv.visitJumpInsn(IFNULL, l0);
        // result = m_LdapBeanManager.searchFirst(p_ReturnType,
        // "search_filter");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, INTERNAL_PACKAGE_NAME + '/' + p_ClassName, "m_LdapBeanManager",
                "Lldapbeans/bean/LdapBeanManager;");
        if (p_ReturnType != null) {
            mv.visitLdcInsn(Type.getType(p_ReturnType));
        } else {
            mv.visitInsn(ACONST_NULL);
        }
        if (p_LdapAttribute.search().length() == 0) {
            mv.visitVarInsn(ALOAD, p_Object);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
            mv.visitMethodInsn(INVOKEVIRTUAL, "ldapbeans/bean/LdapBeanManager", "findByDn",
                    "(Ljava/lang/Class;Ljava/lang/String;)" + "Lldapbeans/bean/LdapBean;");
        } else {
            mv.visitLdcInsn(p_LdapAttribute.search());
            if (p_LdapAttribute.pattern().length() != 0) {
                // regExpGroup = StringUtil.getRegexpGroup(object.toString(),
                // pattern)
                mv.visitVarInsn(ALOAD, p_Object);
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
                mv.visitLdcInsn(p_LdapAttribute.pattern());
                mv.visitMethodInsn(INVOKESTATIC, "ldapbeans/util/StringUtil", "getRegexpGroup",
                        "(Ljava/lang/String;Ljava/lang/String;)" + "[Ljava/lang/String;");
            } else {
                // regExpGroup = new Object[] { object }
                mv.visitInsn(ICONST_1);
                mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
                mv.visitInsn(DUP);
                mv.visitInsn(ICONST_0);
                mv.visitVarInsn(ALOAD, p_Object);
                mv.visitInsn(AASTORE);
            }
            // searchFilter = StringUtil.format("search_filter", regExpGroup);
            mv.visitMethodInsn(INVOKESTATIC, "ldapbeans/util/StringUtil", "format",
                    "(Ljava/lang/String;[Ljava/lang/Object;)" + "Ljava/lang/String;");
            // result = m_LdapBeanManager.searchFirst(foo.class, searchFilter);
            mv.visitMethodInsn(INVOKEVIRTUAL, "ldapbeans/bean/LdapBeanManager", "searchFirst",
                    "(Ljava/lang/Class;Ljava/lang/String;)" + "Lldapbeans/bean/LdapBean;");
        }
        mv.visitVarInsn(ASTORE, p_Result);
        // } else {
        mv.visitJumpInsn(GOTO, l1);
        mv.visitLabel(l0);
        // result = null;
        mv.visitInsn(ACONST_NULL);
        mv.visitVarInsn(ASTORE, p_Result);
        // }
        mv.visitLabel(l1);
    }

    /**
     * Generate code to convert ldapAttribute to primitive type
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            Name of the generated class
     * @param p_LdapAttribute
     *            The LdapAttribute that will be used for generating the method
     * @param p_ReturnType
     *            The type of the result
     * @param p_Object
     *            Index of the object to convert on the stack
     * @param p_Result
     *            Index of the converted object on the stack
     */
    private void generateConvertToPrimitive(MethodVisitor p_MethodVisitor, String p_ClassName,
            LdapAttribute p_LdapAttribute, Class<?> p_ReturnType, int p_Object, int p_Result) {
        MethodVisitor mv = p_MethodVisitor;
        if (byte.class.equals(p_ReturnType)) {
            // result = Integer.parseInt(object.toString());
            mv.visitVarInsn(ALOAD, p_Object);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "parseByte", "(Ljava/lang/String;)B");
            mv.visitVarInsn(ISTORE, p_Result);
        } else if (short.class.equals(p_ReturnType)) {
            // result = Integer.parseInt(object.toString());
            mv.visitVarInsn(ALOAD, p_Object);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "parseShort", "(Ljava/lang/String;)S");
            mv.visitVarInsn(ISTORE, p_Result);
        } else if (int.class.equals(p_ReturnType)) {
            // result = Integer.parseInt(object.toString());
            mv.visitVarInsn(ALOAD, p_Object);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "parseInt", "(Ljava/lang/String;)I");
            mv.visitVarInsn(ISTORE, p_Result);
        } else if (long.class.equals(p_ReturnType)) {
            // result = Integer.parseInt(object.toString());
            mv.visitVarInsn(ALOAD, p_Object);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "parseLong", "(Ljava/lang/String;)J");
            mv.visitVarInsn(LSTORE, p_Result);
        } else if (float.class.equals(p_ReturnType)) {
            // result = Integer.parseInt(object.toString());
            mv.visitVarInsn(ALOAD, p_Object);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "parseFloat", "(Ljava/lang/String;)F");
            mv.visitVarInsn(FSTORE, p_Result);
        } else if (double.class.equals(p_ReturnType)) {
            // result = Integer.parseInt(object.toString());
            mv.visitVarInsn(ALOAD, p_Object);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "parseDouble", "(Ljava/lang/String;)D");
            mv.visitVarInsn(DSTORE, p_Result);
        } else if (char.class.equals(p_ReturnType)) {
            // result = object.toString().charAt(0);
            mv.visitVarInsn(ALOAD, p_Object);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
            mv.visitInsn(ICONST_0);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "charAt", "(I)C");
            mv.visitVarInsn(ISTORE, p_Result);
        }
    }

    /**
     * Generate code to convert ldapAttribute to primitive type
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            Name of the generated class
     * @param p_LdapAttribute
     *            The LdapAttribute that will be used for generating the method
     * @param p_ReturnType
     *            The type of the result
     * @param p_Object
     *            Index of the object to convert on the stack
     * @param p_Result
     *            Index of the converted object on the stack
     */
    private void generateConvertToNumber(MethodVisitor p_MethodVisitor, String p_ClassName,
            LdapAttribute p_LdapAttribute, Class<?> p_ReturnType, int p_Object, int p_Result) {
        MethodVisitor mv = p_MethodVisitor;
        if (Number.class.isAssignableFrom(p_ReturnType)) {
            // result = Integer.parseInt(object.toString());
            String returnTypeInternalName = Type.getInternalName(p_ReturnType);
            mv.visitVarInsn(ALOAD, p_Object);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
            mv.visitMethodInsn(INVOKESTATIC, returnTypeInternalName, "valueOf",
                    "(Ljava/lang/String;)L" + returnTypeInternalName + ';');
            mv.visitVarInsn(ASTORE, p_Result);
        }
    }

    /**
     * Generate code to convert ldapAttribute witch is on the to of the stack to
     * Boolean
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ClassName
     *            Name of the generated class
     * @param p_LdapAttribute
     *            The LdapAttribute that will be used for generating the method
     * @param p_ReturnType
     *            The type of the result
     * @param p_Object
     *            Index of the object to convert on the stack
     * @param p_Result
     *            Index of the converted object on the stack
     */
    private void generateConvertToBoolean(MethodVisitor p_MethodVisitor, String p_ClassName,
            LdapAttribute p_LdapAttribute, Class<?> p_ReturnType, int p_Object, int p_Result) {
        MethodVisitor mv = p_MethodVisitor;
        Label l0 = new Label();
        // return true or false instead of result
        generateConvertToBoolean(mv, p_ReturnType, p_LdapAttribute.trueValue(), true, p_Object, p_Result, l0);
        generateConvertToBoolean(mv, p_ReturnType, p_LdapAttribute.falseValue(), false, p_Object, p_Result, l0);
        // Can't convert attribute to boolean
        // throw new IllegalArgumentException(object +
        // " cannot be converted into boolean");
        mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
        mv.visitInsn(DUP);
        mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V");
        mv.visitVarInsn(ALOAD, p_Object);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
                "(Ljava/lang/Object;)Ljava/lang/StringBuilder;");
        mv.visitLdcInsn(" cannot be converted into boolean");
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
                "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "(Ljava/lang/String;)V");
        mv.visitInsn(ATHROW);
        mv.visitLabel(l0);
    }

    /**
     * Generate code to convert ldapAttribute witch is on the to of the stack to
     * Boolean
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @param p_ReturnType
     *            The type of the result
     * @param p_BValues
     *            Possible values for the attribute
     * @param p_BValue
     *            Boolean value
     * @param p_Object
     *            Index of the object to convert on the stack
     * @param p_Result
     *            Index of the converted object on the stack
     * @param p_End
     *            Destination if the conversion success
     */
    private void generateConvertToBoolean(MethodVisitor p_MethodVisitor, Class<?> p_ReturnType, String[] p_BValues,
            boolean p_BValue, int p_Object, int p_Result, Label p_End) {
        MethodVisitor mv = p_MethodVisitor;
        {
            // if(trueValue.equals(result))
            Label l0 = new Label();
            for (String bValue : p_BValues) {
                mv.visitLdcInsn(bValue);
                mv.visitVarInsn(ALOAD, p_Object);
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equalsIgnoreCase", "(Ljava/lang/String;)Z");
                mv.visitJumpInsn(IFNE, l0);
            }
            Label l1 = new Label();
            mv.visitJumpInsn(GOTO, l1);
            // {
            mv.visitLabel(l0);
            if (boolean.class.equals(p_ReturnType)) {
                // return true|false;
                mv.visitInsn(p_BValue ? ICONST_1 : ICONST_0);
                mv.visitVarInsn(ISTORE, p_Result);
            } else {
                // return Boolean.TRUE|Boolean.FALSE;
                mv.visitFieldInsn(GETSTATIC, "java/lang/Boolean", p_BValue ? "TRUE" : "FALSE",
                        "Ljava/lang/Boolean;");
                mv.visitVarInsn(ASTORE, p_Result);
            }
            mv.visitJumpInsn(GOTO, p_End);
            // }
            mv.visitLabel(l1);
        }
    }

    /**
     * Generate code for printing the object on the top of the stack
     * 
     * @param p_MethodVisitor
     *            The {@link MethodVisitor} of the generated method
     * @deprecated Use this method only for debug.
     */
    @SuppressWarnings("unused")
    @Deprecated
    private void generatePrintTopStack(MethodVisitor p_MethodVisitor) {
        MethodVisitor mv = p_MethodVisitor;
        mv.visitInsn(Opcodes.DUP);
        mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
        mv.visitInsn(Opcodes.SWAP);
        mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/Object;)V");
    }

    /**
     * Get ConvertAttribute annotation from parameters of the method
     * 
     * @param p_Method
     *            the method in wich parameters have to be extract
     * @return Le Convert attribute of each parameter of the method
     */
    private static ConvertAttribute[] getConvertAttributeAnnotation(Method p_Method) {
        ConvertAttribute[] result = new ConvertAttribute[p_Method.getParameterTypes().length];
        int i = 0;
        for (Annotation[] annotations : p_Method.getParameterAnnotations()) {
            result[i] = null;
            for (Annotation annotation : annotations) {
                if (annotation instanceof ConvertAttribute) {
                    result[i] = (ConvertAttribute) annotation;
                }
            }
            i++;
        }
        return result;
    }

    /**
     * Return the index in the stack of the n'th (n=p_ParameterIndex) parameter
     * 
     * @param p_Method
     *            the method
     * @param p_ParameterIndex
     *            the index of the parameter in the method (the first parameter
     *            start at 0)
     * @return the index of the stack after the n'th parameter
     */
    private static int getStackIndexOfParameter(Method p_Method, int p_ParameterIndex) {
        int result = 1;
        Class<?>[] parameterTypes = p_Method.getParameterTypes();
        for (int i = 0; i < p_ParameterIndex; i++) {
            Class<?> clazz = parameterTypes[i];
            if (long.class.equals(clazz) || double.class.equals(clazz)) {
                result += 2;
            } else {
                result += 1;
            }
        }
        return result;
    }
}