org.apache.felix.ipojo.manipulation.ClassManipulator.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.felix.ipojo.manipulation.ClassManipulator.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.felix.ipojo.manipulation;

import java.util.*;

import org.apache.felix.ipojo.manipulation.ClassChecker.AnnotationDescriptor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.tree.LocalVariableNode;

/**
 * iPOJO Class Adapter.
 * This class adapt the visited class to link the class with the container.
 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
 */
public class ClassManipulator extends ClassVisitor implements Opcodes {

    /**
     * Instance Manager Field.
     */
    public static final String IM_FIELD = "__IM";

    /**
     * All POJO method will be renamed by using this prefix.
     */
    public static final String PREFIX = "__M_";

    /**
     * POJO class.
     */
    private static final String POJO = "org/apache/felix/ipojo/Pojo";

    /**
     * Filed flag prefix.
     */
    public static final String FIELD_FLAG_PREFIX = "__F";

    /**
     * Method flag prefix.
     */
    public static final String METHOD_FLAG_PREFIX = "__M";

    /**
     * onEntry method name.
     */
    public static final String ENTRY = "onEntry";

    /**
     * onExit method name.
     */
    public static final String EXIT = "onExit";

    /**
     * on Error method name.
     */
    public static final String ERROR = "onError";

    /**
     * onGet method name.
     */
    private static final String GET = "onGet";

    /**
     * onSet method name.
     */
    private static final String SET = "onSet";

    /**
     * The manipulator. It has already collected all the metadata about the class.
     */
    private final Manipulator m_manipulator;

    /**
     * Name of the current manipulated class.
     */
    private String m_owner;

    /**
     * Set of fields detected in the class.
     * (this set is given by the previous analysis)
     */
    private Set<String> m_fields;

    /**
     * List of methods contained in the class.
     * This set contains method id.
     */
    private List<String> m_methods = new ArrayList<String>();

    /**
     * List of fields injected as method flag in the class.
     * This set contains field name generate from method id.
     */
    private List<String> m_methodFlags = new ArrayList<String>();

    /**
     * The list of methods visited during the previous analysis.
     * This list allows getting annotations to move to generated
     * method.
     */
    private List<MethodDescriptor> m_visitedMethods = new ArrayList<MethodDescriptor>();

    /**
     * Set to <code>true</code> when a suitable constructor
     * is found. If not set to <code>true</code> at the end
     * of the visit, the manipulator injects a constructor.
     */
    private boolean m_foundSuitableConstructor = false;

    /**
     * Name of the super class.
     */
    private String m_superclass;

    /**
     * Constructor.
     * @param visitor : class visitor.
     * @param manipulator : the manipulator having analyzed the class.
     */
    public ClassManipulator(ClassVisitor visitor, Manipulator manipulator) {
        super(Opcodes.ASM5, visitor);
        m_manipulator = manipulator;
        m_fields = manipulator.getFields().keySet();
        m_visitedMethods = manipulator.getMethods();
    }

    /**
     * Visit method.
     * This method store the current class name.
     * Moreover the POJO interface is added to the list of implemented interface.
     * Then the Instance manager field is added.
     * @param version : version
     * @param access : access flag
     * @param name : class name
     * @param signature : signature
     * @param superName : parent class
     * @param interfaces : implemented interface
     * @see org.objectweb.asm.ClassVisitor#visit(int, int, java.lang.String, java.lang.String, java.lang.String,
     * java.lang.String[])
     */
    public void visit(int version, int access, String name, String signature, String superName,
            String[] interfaces) {
        m_owner = name;
        m_superclass = superName;
        addPOJOInterface(version, access, name, signature, superName, interfaces);
        addIMField();
        addFlagsForInnerClassMethods();
    }

    /**
     * A method is visited.
     * This method does not manipulate clinit and class$ methods.
     * In the case of a constructor, this method will generate a constructor with the instance manager
     * and will adapt the current constructor to call this constructor.
     * For standard method, this method will create method header, rename the current method and adapt it.
     * @param access : access flag.
     * @param name : name of the method
     * @param desc : method descriptor
     * @param signature : signature
     * @param exceptions : declared exceptions.
     * @return the MethodVisitor wich will visit the method code.
     * @see org.objectweb.asm.ClassVisitor#visitMethod(int, java.lang.String, java.lang.String, java.lang.String,
     * java.lang.String[])
     */
    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        // Avoid manipulating special methods
        if (name.equals("<clinit>") || name.equals("class$")) {
            return super.visitMethod(access, name, desc, signature, exceptions);
        }
        // The constructor is manipulated separately
        if (name.equals("<init>")) {
            MethodDescriptor md = getMethodDescriptor("$init", desc);
            // 1) change the constructor descriptor (add a component manager arg as first argument)
            String newDesc = desc.substring(1);
            newDesc = "(Lorg/apache/felix/ipojo/InstanceManager;" + newDesc;

            Type[] args = Type.getArgumentTypes(desc);

            // TODO HERE ! => All constructor matches, no distinction between the different constructors.
            generateConstructor(access, desc, signature, exceptions, md.getAnnotations(),
                    md.getParameterAnnotations(), md.getLocals());

            if (args.length == 0) {
                m_foundSuitableConstructor = true;
            } else if (args.length == 1 && args[0].getClassName().equals("org.osgi.framework.BundleContext")) {
                m_foundSuitableConstructor = true;
            }

            // Insert the new constructor
            MethodVisitor mv = super.visitMethod(ACC_PRIVATE, "<init>", newDesc, signature, exceptions);
            return new ConstructorCodeAdapter(mv, m_owner, m_fields, ACC_PRIVATE, name, newDesc, m_superclass);
        }

        if ((access & ACC_SYNTHETIC) == ACC_SYNTHETIC && name.startsWith("access$")) {
            MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
            return new MethodCodeAdapter(mv, m_owner, access, name, desc, m_fields);
        }

        // Do nothing on static methods
        if ((access & ACC_STATIC) == ACC_STATIC) {
            return super.visitMethod(access, name, desc, signature, exceptions);
        }

        // Do nothing on native methods
        if ((access & ACC_NATIVE) == ACC_NATIVE) {
            return super.visitMethod(access, name, desc, signature, exceptions);
        }

        MethodDescriptor md = getMethodDescriptor(name, desc);
        if (md == null) {
            generateMethodHeader(access, name, desc, signature, exceptions, null, null, null);
        } else {
            generateMethodHeader(access, name, desc, signature, exceptions, md.getArgumentLocalVariables(),
                    md.getAnnotations(), md.getParameterAnnotations());
        }

        // TODO Also add the method flags for inner class methods.
        String id = generateMethodFlag(name, desc);
        if (!m_methodFlags.contains(id)) {
            FieldVisitor flagField = cv.visitField(0, id, "Z", null, null);
            flagField.visitEnd();
            m_methodFlags.add(id);
        }

        MethodVisitor mv = super.visitMethod(ACC_PRIVATE, PREFIX + name, desc, signature, exceptions);
        return new MethodCodeAdapter(mv, m_owner, ACC_PRIVATE, PREFIX + name, desc, m_fields);
    }

    /**
     * Gets the method descriptor for the specified name and descriptor.
     * The method descriptor is looked inside the
     * {@link ClassManipulator#m_visitedMethods}
     * @param name the name of the method
     * @param desc the descriptor of the method
     * @return the method descriptor or <code>null</code> if not found.
     */
    private MethodDescriptor getMethodDescriptor(String name, String desc) {
        for (MethodDescriptor md : m_visitedMethods) {
            if (md.getName().equals(name) && md.getDescriptor().equals(desc)) {
                return md;
            }
        }
        return null;
    }

    /**
     * Visit a Field.
     * This field access is replaced by an invocation to the getter method or to the setter method.
     * (except for static field).
     * Inject the getter and the setter method for this field.
     * @see org.objectweb.asm.ClassVisitor#visitField(int, java.lang.String, java.lang.String, java.lang.String, java.lang.Object)
     * @param access : access modifier
     * @param name : name of the field
     * @param desc : description of the field
     * @param signature : signature of the field
     * @param value : value of the field
     * @return FieldVisitor : null
     */
    public FieldVisitor visitField(final int access, final String name, final String desc, final String signature,
            final Object value) {
        if ((access & ACC_STATIC) == 0) {
            FieldVisitor flag = cv.visitField(Opcodes.ACC_PRIVATE, FIELD_FLAG_PREFIX + name, "Z", null, null);
            flag.visitEnd();

            Type type = Type.getType(desc);

            if (type.getSort() == Type.ARRAY) {
                String gDesc = "()" + desc;
                createArrayGetter(name, gDesc);

                // Generates setter method
                String sDesc = "(" + desc + ")V";
                createArraySetter(name, sDesc);

            } else {
                // Generate the getter method
                String gDesc = "()" + desc;
                createSimpleGetter(name, gDesc, type);

                // Generates setter method
                String sDesc = "(" + desc + ")V";
                createSimpleSetter(name, sDesc, type);
            }

        }
        return cv.visitField(access, name, desc, signature, value);
    }

    /**
     * Modify the given constructor to be something like:
     * <code>
     * this(null, params...);
     * return;
     * </code>
     * The actual constructor is modified to support the instance manager argument.
     * @param access : access flag
     * @param descriptor : the original constructor descriptor
     * @param signature : method signature
     * @param exceptions : declared exception
     * @param annotations : the annotations to move to this constructor.
     * @param locals : the local variables from the original constructors.
     */
    private void generateConstructor(int access, String descriptor, String signature, String[] exceptions,
            List<AnnotationDescriptor> annotations, Map<Integer, List<AnnotationDescriptor>> paramAnnotations,
            LinkedHashMap<Integer, LocalVariableNode> locals) {
        GeneratorAdapter mv = new GeneratorAdapter(
                cv.visitMethod(access, "<init>", descriptor, signature, exceptions), access, "<init>", descriptor);
        // Compute the new signature
        String newDesc = descriptor.substring(1); // Remove the first (
        newDesc = "(Lorg/apache/felix/ipojo/InstanceManager;" + newDesc;

        mv.visitCode();
        Label start = new Label();
        mv.visitLabel(start);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitInsn(ACONST_NULL);
        mv.loadArgs();
        mv.visitMethodInsn(INVOKESPECIAL, m_owner, "<init>", newDesc, false);
        mv.visitInsn(RETURN);
        Label stop = new Label();
        mv.visitLabel(stop);

        // Move annotations
        if (annotations != null) {
            for (AnnotationDescriptor ad : annotations) {
                ad.visitAnnotation(mv);
            }
        }

        // Move parameter annotations if any
        if (paramAnnotations != null && !paramAnnotations.isEmpty()) {
            for (Integer id : paramAnnotations.keySet()) {
                List<AnnotationDescriptor> ads = paramAnnotations.get(id);
                for (AnnotationDescriptor ad : ads) {
                    ad.visitParameterAnnotation(id, mv);
                }
            }
        }

        // Add local variables for the arguments.
        for (Map.Entry<Integer, LocalVariableNode> local : locals.entrySet()) {
            // Write the parameter name. Only write the local variable that are either `this` or parameters from the
            // initial descriptor.
            if (local.getValue().index <= Type.getArgumentTypes(descriptor).length) {
                mv.visitLocalVariable(local.getValue().name, local.getValue().desc, local.getValue().signature,
                        start, stop, local.getValue().index);
            }
        }

        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Generate the method header of a POJO method.
     * This method header encapsulate the POJO method call to
     * signal entry exit and error to the container.
     * @param access : access flag.
     * @param name : method name.
     * @param desc : method descriptor.
     * @param signature : method signature.
     * @param exceptions : declared exceptions.
     * @param localVariables : the local variable nodes.
     * @param annotations : the annotations to move to this method.
     * @param paramAnnotations : the parameter annotations to move to this method.
     */
    private void generateMethodHeader(int access, String name, String desc, String signature, String[] exceptions,
            List<LocalVariableNode> localVariables, List<AnnotationDescriptor> annotations,
            Map<Integer, List<AnnotationDescriptor>> paramAnnotations) {
        GeneratorAdapter mv = new GeneratorAdapter(cv.visitMethod(access, name, desc, signature, exceptions),
                access, name, desc);
        mv.visitCode();

        // If we have variables, we wraps the code within labels. The `lifetime` of the variables are bound to those
        // two variables.
        boolean hasArgumentLabels = localVariables != null && !localVariables.isEmpty();
        Label start = null;
        if (hasArgumentLabels) {
            start = new Label();
            mv.visitLabel(start);
        }

        mv.visitCode();

        Type returnType = Type.getReturnType(desc);

        // Compute result and exception stack location
        int result = -1;
        int exception;

        //int arguments = mv.newLocal(Type.getType((new Object[0]).getClass()));

        if (returnType.getSort() != Type.VOID) {
            // The method returns something
            result = mv.newLocal(returnType);
            exception = mv.newLocal(Type.getType(Throwable.class));
        } else {
            exception = mv.newLocal(Type.getType(Throwable.class));
        }

        Label l0 = new Label();
        Label l1 = new Label();
        Label l2 = new Label();

        mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Throwable");

        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, m_owner, generateMethodFlag(name, desc), "Z");
        mv.visitJumpInsn(IFNE, l0);

        mv.visitVarInsn(ALOAD, 0);
        mv.loadArgs();
        mv.visitMethodInsn(INVOKESPECIAL, m_owner, PREFIX + name, desc, false);
        mv.visitInsn(returnType.getOpcode(IRETURN));

        // end of the non intercepted method invocation.

        mv.visitLabel(l0);

        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitLdcInsn(generateMethodId(name, desc));
        mv.loadArgArray();
        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", ENTRY,
                "(Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)V", false);

        mv.visitVarInsn(ALOAD, 0);

        // Do not allow argument modification : just reload arguments.
        mv.loadArgs();
        mv.visitMethodInsn(INVOKESPECIAL, m_owner, PREFIX + name, desc, false);

        if (returnType.getSort() != Type.VOID) {
            mv.visitVarInsn(returnType.getOpcode(ISTORE), result);
        }

        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitLdcInsn(generateMethodId(name, desc));
        if (returnType.getSort() != Type.VOID) {
            mv.visitVarInsn(returnType.getOpcode(ILOAD), result);
            mv.box(returnType);
        } else {
            mv.visitInsn(ACONST_NULL);
        }
        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", EXIT,
                "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V", false);

        mv.visitLabel(l1);
        Label l7 = new Label();
        mv.visitJumpInsn(GOTO, l7);
        mv.visitLabel(l2);

        mv.visitVarInsn(ASTORE, exception);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitLdcInsn(generateMethodId(name, desc));
        mv.visitVarInsn(ALOAD, exception);
        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", ERROR,
                "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Throwable;)V", false);
        mv.visitVarInsn(ALOAD, exception);
        mv.visitInsn(ATHROW);

        mv.visitLabel(l7);
        if (returnType.getSort() != Type.VOID) {
            mv.visitVarInsn(returnType.getOpcode(ILOAD), result);
        }
        mv.visitInsn(returnType.getOpcode(IRETURN));

        // If we had arguments, we mark the end of the lifetime.
        Label end = null;
        if (hasArgumentLabels) {
            end = new Label();
            mv.visitLabel(end);
        }

        // Move annotations
        if (annotations != null) {
            for (AnnotationDescriptor ad : annotations) {
                ad.visitAnnotation(mv);
            }
        }

        // Move parameter annotations
        if (paramAnnotations != null && !paramAnnotations.isEmpty()) {
            for (Integer id : paramAnnotations.keySet()) {
                List<AnnotationDescriptor> ads = paramAnnotations.get(id);
                for (AnnotationDescriptor ad : ads) {
                    ad.visitParameterAnnotation(id, mv);
                }
            }
        }

        // Write the arguments name.
        if (hasArgumentLabels) {
            for (LocalVariableNode var : localVariables) {
                mv.visitLocalVariable(var.name, var.desc, var.signature, start, end, var.index);
            }
        }

        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Generate a method flag name.
     * @param name : method name.
     * @param desc : method descriptor.
     * @return the method flag name
     */
    private String generateMethodFlag(String name, String desc) {
        return METHOD_FLAG_PREFIX + generateMethodId(name, desc);
    }

    private String generateMethodFlagForMethodFromInnerClass(String name, String desc, String inner) {
        return METHOD_FLAG_PREFIX + generateMethodIdForMethodFromInnerClass(name, desc, inner);
    }

    /**
     * Generate the method id based on the given method name and method descriptor.
     * The method Id is unique for this method and serves to create the flag field (so
     * must follow field name Java restrictions).
     * @param name : method name
     * @param desc : method descriptor
     * @return  method ID
     */
    private String generateMethodId(String name, String desc) {
        StringBuilder id = new StringBuilder(name);
        Type[] args = Type.getArgumentTypes(desc);
        for (Type type : args) {
            String arg = type.getClassName();
            if (arg.endsWith("[]")) {
                // We have to replace all []
                String acc = "";
                while (arg.endsWith("[]")) {
                    arg = arg.substring(0, arg.length() - 2);
                    acc += "__";
                }
                id.append("$").append(arg.replace('.', '_')).append(acc);
            } else {
                id.append("$").append(arg.replace('.', '_'));
            }
        }
        if (!m_methods.contains(id.toString())) {
            m_methods.add(id.toString());
        }
        return id.toString();
    }

    private String generateMethodIdForMethodFromInnerClass(String name, String desc, String inner) {
        StringBuilder id = new StringBuilder(inner);
        id.append("___"); // Separator
        id.append(name);

        Type[] args = Type.getArgumentTypes(desc);
        for (Type type : args) {
            String arg = type.getClassName();
            if (arg.endsWith("[]")) {
                // We have to replace all []
                String acc = "";
                while (arg.endsWith("[]")) {
                    arg = arg.substring(0, arg.length() - 2);
                    acc += "__";
                }
                id.append("$").append(arg.replace('.', '_')).append(acc);
            } else {
                id.append("$").append(arg.replace('.', '_'));
            }
        }

        if (!m_methods.contains(id.toString())) {
            m_methods.add(id.toString());
        }

        return id.toString();
    }

    /**
     * Add the instance manager field (__im).
     */
    private void addIMField() {
        FieldVisitor fv = super.visitField(0, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;", null, null);
        fv.visitEnd();
    }

    /**
     * Add the boolean flag fields for methods from inner classes.
     */
    private void addFlagsForInnerClassMethods() {
        for (Map.Entry<String, List<MethodDescriptor>> entry : m_manipulator.getInnerClassesAndMethods()
                .entrySet()) {
            for (MethodDescriptor descriptor : entry.getValue()) {
                String id = generateMethodFlagForMethodFromInnerClass(descriptor.getName(),
                        descriptor.getDescriptor(), entry.getKey());
                if (!m_methodFlags.contains(id)) {
                    FieldVisitor flagField = cv.visitField(0, id, "Z", null, null);
                    flagField.visitEnd();
                    m_methodFlags.add(id);
                }
            }
        }
    }

    /**
     * Add the POJO interface to the visited class.
     * @param version : class version
     * @param access : class access
     * @param name : class name
     * @param signature : class signature
     * @param superName : super class
     * @param interfaces : implemented interfaces.
     */
    private void addPOJOInterface(int version, int access, String name, String signature, String superName,
            String[] interfaces) {

        // Add the POJO interface to the interface list
        // Check that the POJO interface is not already in the list
        boolean found = false;
        for (String anInterface : interfaces) {
            if (anInterface.equals(POJO)) {
                found = true;
            }
        }
        String[] itfs;
        if (!found) {
            itfs = new String[interfaces.length + 1];
            System.arraycopy(interfaces, 0, itfs, 0, interfaces.length);
            itfs[interfaces.length] = POJO;
        } else {
            itfs = interfaces;
        }
        cv.visit(version, access, name, signature, superName, itfs);
    }

    /**
     * Visit end.
     * Create helper methods.
     * @see org.objectweb.asm.ClassVisitor#visitEnd()
     */
    public void visitEnd() {
        // Create the component manager setter method
        createSetInstanceManagerMethod();

        // Add the getComponentInstance
        createGetComponentInstanceMethod();

        // Need to inject a constructor?
        if (!m_foundSuitableConstructor) { // No adequate constructor, create one.
            createSimpleConstructor();
        }

        m_methods.clear();
        m_methodFlags.clear();

        cv.visitEnd();
    }

    /**
     * Creates a simple constructor with an instance manager
     * in argument if no suitable constructor is found during
     * the visit.
     */
    private void createSimpleConstructor() {
        MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "<init>", "(Lorg/apache/felix/ipojo/InstanceManager;)V", null,
                null);
        mv.visitCode();

        // Super call
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, m_superclass, "<init>", "()V", false);

        // Call set instance manager
        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(INVOKEVIRTUAL, m_owner, "_setInstanceManager",
                "(Lorg/apache/felix/ipojo/InstanceManager;)V", false);

        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Create the setter method for the __cm field.
     */
    private void createSetInstanceManagerMethod() {
        MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, "_setInstanceManager",
                "(Lorg/apache/felix/ipojo/InstanceManager;)V", null, null);
        mv.visitCode();

        // If the given instance manager is null, just returns.
        mv.visitVarInsn(ALOAD, 1);
        Label l1 = new Label();
        mv.visitJumpInsn(IFNONNULL, l1);
        mv.visitInsn(RETURN);
        mv.visitLabel(l1);

        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitFieldInsn(PUTFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");

        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getRegistredFields",
                "()Ljava/util/Set;", false);
        mv.visitVarInsn(ASTORE, 2);

        mv.visitVarInsn(ALOAD, 2);
        Label endif = new Label();
        mv.visitJumpInsn(IFNULL, endif);
        for (String field : m_fields) {
            mv.visitVarInsn(ALOAD, 2);
            mv.visitLdcInsn(field);
            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Set", "contains", "(Ljava/lang/Object;)Z", true);
            Label l3 = new Label();
            mv.visitJumpInsn(IFEQ, l3);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitInsn(ICONST_1);
            mv.visitFieldInsn(PUTFIELD, m_owner, FIELD_FLAG_PREFIX + field, "Z");
            mv.visitLabel(l3);
        }
        mv.visitLabel(endif);

        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", "getRegistredMethods",
                "()Ljava/util/Set;", false);
        mv.visitVarInsn(ASTORE, 2);

        mv.visitVarInsn(ALOAD, 2);
        Label endif2 = new Label();
        mv.visitJumpInsn(IFNULL, endif2);

        for (String methodId : m_methods) {
            if (!methodId.equals("<init>")) {
                mv.visitVarInsn(ALOAD, 2);
                mv.visitLdcInsn(methodId);
                mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Set", "contains", "(Ljava/lang/Object;)Z", true);
                Label l3 = new Label();
                mv.visitJumpInsn(IFEQ, l3);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitInsn(ICONST_1);
                mv.visitFieldInsn(PUTFIELD, m_owner, METHOD_FLAG_PREFIX + methodId, "Z");
                mv.visitLabel(l3);
            }
        }

        mv.visitLabel(endif2);
        mv.visitInsn(RETURN);

        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Create the getComponentInstance method.
     */
    private void createGetComponentInstanceMethod() {
        MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "getComponentInstance",
                "()Lorg/apache/felix/ipojo/ComponentInstance;", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Create a getter method for an array.
     * @param name : field name
     * @param desc : method description
     */
    private void createArraySetter(String name, String desc) {
        MethodVisitor mv = cv.visitMethod(0, "__set" + name, desc, null, null);
        mv.visitCode();

        String internalType = desc.substring(1);
        internalType = internalType.substring(0, internalType.length() - 2);

        Label l1 = new Label();
        mv.visitLabel(l1);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
        Label l2 = new Label();
        mv.visitJumpInsn(IFNE, l2);

        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitFieldInsn(PUTFIELD, m_owner, name, internalType);
        mv.visitInsn(RETURN);
        mv.visitLabel(l2);

        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitLdcInsn(name);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", SET,
                "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V", false);

        mv.visitInsn(RETURN);

        // End
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Create a setter method for an array.
     * @param name : field name
     * @param desc : method description
     */
    private void createArrayGetter(String name, String desc) {
        String methodName = "__get" + name;
        MethodVisitor mv = cv.visitMethod(0, methodName, desc, null, null);
        mv.visitCode();

        String internalType = desc.substring(2);

        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
        Label l1 = new Label();
        mv.visitJumpInsn(IFNE, l1);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, m_owner, name, internalType);
        mv.visitInsn(ARETURN);
        mv.visitLabel(l1);

        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
        mv.visitVarInsn(ALOAD, 0);
        mv.visitLdcInsn(name);
        mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", GET,
                "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;", false);
        mv.visitTypeInsn(CHECKCAST, internalType);
        mv.visitInsn(ARETURN);

        // End
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Create the getter for a field.
     * @param name : field of the dependency
     * @param desc : description of the getter method
     * @param type : type to return
     */
    private void createSimpleGetter(String name, String desc, Type type) {
        String methodName = "__get" + name;
        MethodVisitor mv = cv.visitMethod(0, methodName, desc, null, null);
        mv.visitCode();

        switch (type.getSort()) {
        case Type.BOOLEAN:
        case Type.CHAR:
        case Type.BYTE:
        case Type.SHORT:
        case Type.INT:

            String internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];
            String boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];
            String unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];

            Label l0 = new Label();
            mv.visitLabel(l0);

            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
            Label l1 = new Label();
            mv.visitJumpInsn(IFNE, l1);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);
            mv.visitInsn(IRETURN);

            mv.visitLabel(l1);

            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
            mv.visitVarInsn(ALOAD, 0);
            mv.visitLdcInsn(name);
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", GET,
                    "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;", false);
            mv.visitVarInsn(ASTORE, 1);

            mv.visitVarInsn(ALOAD, 1);
            mv.visitTypeInsn(CHECKCAST, boxingType);
            mv.visitVarInsn(ASTORE, 2);

            mv.visitVarInsn(ALOAD, 2);
            mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName, false);
            mv.visitInsn(type.getOpcode(IRETURN));
            break;

        case Type.LONG:
            internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];
            boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];
            unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];

            l0 = new Label();
            mv.visitLabel(l0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
            l1 = new Label();
            mv.visitJumpInsn(IFNE, l1);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);
            mv.visitInsn(LRETURN);
            mv.visitLabel(l1);

            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
            mv.visitVarInsn(ALOAD, 0);
            mv.visitLdcInsn(name);
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", GET,
                    "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;", false);
            mv.visitVarInsn(ASTORE, 1);

            mv.visitVarInsn(ALOAD, 1);
            mv.visitTypeInsn(CHECKCAST, boxingType);
            mv.visitVarInsn(ASTORE, 2);

            mv.visitVarInsn(ALOAD, 2);
            mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName, false);
            mv.visitInsn(LRETURN);

            break;

        case Type.DOUBLE:
            internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];
            boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];
            unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];

            l0 = new Label();
            mv.visitLabel(l0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
            l1 = new Label();
            mv.visitJumpInsn(IFNE, l1);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);
            mv.visitInsn(DRETURN);
            mv.visitLabel(l1);

            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
            mv.visitVarInsn(ALOAD, 0);
            mv.visitLdcInsn(name);
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", GET,
                    "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;", false);
            mv.visitVarInsn(ASTORE, 1);

            mv.visitVarInsn(ALOAD, 1);
            mv.visitTypeInsn(CHECKCAST, boxingType);
            mv.visitVarInsn(ASTORE, 2);

            mv.visitVarInsn(ALOAD, 2);
            mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName, false);
            mv.visitInsn(DRETURN);

            break;

        case Type.FLOAT:
            internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];
            boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];
            unboxingMethod = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][2];

            l0 = new Label();
            mv.visitLabel(l0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
            l1 = new Label();
            mv.visitJumpInsn(IFNE, l1);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, name, internalName);
            mv.visitInsn(FRETURN);
            mv.visitLabel(l1);

            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
            mv.visitVarInsn(ALOAD, 0);
            mv.visitLdcInsn(name);
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", GET,
                    "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;", false);
            mv.visitVarInsn(ASTORE, 1);

            mv.visitVarInsn(ALOAD, 1);
            mv.visitTypeInsn(CHECKCAST, boxingType);
            mv.visitVarInsn(ASTORE, 2);

            mv.visitVarInsn(ALOAD, 2);
            mv.visitMethodInsn(INVOKEVIRTUAL, boxingType, unboxingMethod, "()" + internalName, false);
            mv.visitInsn(FRETURN);

            break;

        case Type.OBJECT:
            l0 = new Label();
            mv.visitLabel(l0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
            l1 = new Label();
            mv.visitJumpInsn(IFNE, l1);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, name, "L" + type.getInternalName() + ";");
            mv.visitInsn(ARETURN);
            mv.visitLabel(l1);

            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
            mv.visitVarInsn(ALOAD, 0);
            mv.visitLdcInsn(name);
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", GET,
                    "(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;", false);
            mv.visitTypeInsn(CHECKCAST, type.getInternalName());
            mv.visitInsn(ARETURN);

            break;

        default:
            ManipulationProperty.getLogger().log(ManipulationProperty.SEVERE,
                    "Manipulation problem in " + m_owner + " : a type is not implemented : " + type);
            break;
        }

        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /**
     * Create the setter method for one property. The name of the method is _set+name of the field
     * @param name : name of the field representing a property
     * @param desc : description of the setter method
     * @param type : type of the property
     */
    private void createSimpleSetter(String name, String desc, Type type) {
        MethodVisitor mv = cv.visitMethod(0, "__set" + name, desc, null, null);
        mv.visitCode();

        switch (type.getSort()) {
        case Type.BOOLEAN:
        case Type.CHAR:
        case Type.BYTE:
        case Type.SHORT:
        case Type.INT:
        case Type.FLOAT:
            String internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];
            String boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];

            Label l1 = new Label();
            mv.visitLabel(l1);

            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
            Label l22 = new Label();
            mv.visitJumpInsn(IFNE, l22);

            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(type.getOpcode(ILOAD), 1);
            mv.visitFieldInsn(PUTFIELD, m_owner, name, internalName);
            mv.visitInsn(RETURN);
            mv.visitLabel(l22);

            mv.visitTypeInsn(NEW, boxingType);
            mv.visitInsn(DUP);
            mv.visitVarInsn(type.getOpcode(ILOAD), 1);
            mv.visitMethodInsn(INVOKESPECIAL, boxingType, "<init>", "(" + internalName + ")V", false);
            mv.visitVarInsn(ASTORE, 2);

            Label l2 = new Label();
            mv.visitLabel(l2);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
            mv.visitVarInsn(ALOAD, 0);
            mv.visitLdcInsn(name);
            mv.visitVarInsn(ALOAD, 2);
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", SET,
                    "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V", false);

            Label l3 = new Label();
            mv.visitLabel(l3);
            mv.visitInsn(RETURN);
            break;

        case Type.LONG:
        case Type.DOUBLE:
            internalName = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][0];
            boxingType = ManipulationProperty.PRIMITIVE_BOXING_INFORMATION[type.getSort()][1];

            l1 = new Label();
            mv.visitLabel(l1);

            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
            Label l23 = new Label();
            mv.visitJumpInsn(IFNE, l23);

            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(type.getOpcode(ILOAD), 1);
            mv.visitFieldInsn(PUTFIELD, m_owner, name, internalName);
            mv.visitInsn(RETURN);
            mv.visitLabel(l23);

            mv.visitTypeInsn(NEW, boxingType);
            mv.visitInsn(DUP);
            mv.visitVarInsn(type.getOpcode(ILOAD), 1);
            mv.visitMethodInsn(INVOKESPECIAL, boxingType, "<init>", "(" + internalName + ")V", false);
            mv.visitVarInsn(ASTORE, 3); // Double space

            l2 = new Label();
            mv.visitLabel(l2);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
            mv.visitVarInsn(ALOAD, 0);
            mv.visitLdcInsn(name);
            mv.visitVarInsn(ALOAD, 3);
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", SET,
                    "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V", false);

            l3 = new Label();
            mv.visitLabel(l3);
            mv.visitInsn(RETURN);
            break;

        case Type.OBJECT:
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, FIELD_FLAG_PREFIX + name, "Z");
            Label l24 = new Label();
            mv.visitJumpInsn(IFNE, l24);

            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitFieldInsn(PUTFIELD, m_owner, name, "L" + type.getInternalName() + ";");
            mv.visitInsn(RETURN);
            mv.visitLabel(l24);

            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, m_owner, IM_FIELD, "Lorg/apache/felix/ipojo/InstanceManager;");
            mv.visitVarInsn(ALOAD, 0);
            mv.visitLdcInsn(name);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/apache/felix/ipojo/InstanceManager", SET,
                    "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V", false);

            mv.visitInsn(RETURN);
            break;
        default:
            ManipulationProperty.getLogger().log(ManipulationProperty.SEVERE,
                    "Manipulation Error : Cannot create the setter method for the field : " + name + " (" + type
                            + ")");
            break;
        }

        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

}