org.simantics.databoard.binding.reflection.AsmBindingClassLoader.java Source code

Java tutorial

Introduction

Here is the source code for org.simantics.databoard.binding.reflection.AsmBindingClassLoader.java

Source

/*******************************************************************************
 * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
 * Industry THTH ry.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     VTT Technical Research Centre of Finland - initial API and implementation
 *******************************************************************************/
package org.simantics.databoard.binding.reflection;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
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.simantics.databoard.binding.error.BindingConstructionException;

public class AsmBindingClassLoader extends ClassLoader implements Opcodes {

    Map<String, Class<?>> map = new HashMap<String, Class<?>>();

    public AsmBindingClassLoader() {
        super(Thread.currentThread().getContextClassLoader());
    }

    public AsmBindingClassLoader(ClassLoader parent) {
        super(parent);
    }

    public String toBindingClassName(String targetClassName) {
        if (targetClassName.startsWith("java")) {
            return "x" + targetClassName + ".Binding";
        }
        return targetClassName + ".Binding";
    }

    public String toTargetClassName(String bindingClassName) {
        if (!bindingClassName.endsWith(".Binding"))
            return null;
        if (bindingClassName.substring(1, 5).equals("java")) {
            return bindingClassName.substring(1, bindingClassName.length() - 8);
        } else {
            return bindingClassName.substring(0, bindingClassName.length() - 8);
        }
    }

    @Override
    protected synchronized Class<?> findClass(String bindingClassName) throws ClassNotFoundException {
        Class<?> c = map.get(bindingClassName);
        if (c != null)
            return c;

        try {
            String targetClassName = toTargetClassName(bindingClassName);
            if (targetClassName == null) {
                //            try {
                return super.findClass(bindingClassName);
                //            } catch( ClassNotFoundException e ) {
                //               e.printStackTrace();
                //               throw e;
                //            }
            }

            ClassLoader cl = getParent();
            if (cl == null) {
                cl = Thread.currentThread().getContextClassLoader();
            }
            Class<?> targetClass = cl.loadClass(targetClassName);
            ClassInfo ci = ClassInfo.getInfo(targetClass);
            byte[] data = createBindingClass(ci, bindingClassName);
            Class<?> bindingClass = defineClass(bindingClassName, data, 0, data.length);
            map.put(bindingClassName, bindingClass);
            return bindingClass;
        } catch (BindingConstructionException e) {
            throw new ClassNotFoundException(e.getMessage(), e.getCause());
        }
    }

    public synchronized Class<?> getBindingClass(Class<?> targetClass) throws ClassNotFoundException {
        String targetClassName = targetClass.getName();
        String bindingClassName = toBindingClassName(targetClassName);
        Class<?> c = map.get(bindingClassName);
        if (c != null)
            return c;

        try {
            ClassInfo ci = ClassInfo.getInfo(targetClass);
            byte[] data = createBindingClass(ci, bindingClassName);
            Class<?> bindingClass = defineClass(bindingClassName, data, 0, data.length);
            map.put(bindingClassName, bindingClass);
            return bindingClass;
        } catch (BindingConstructionException e) {
            throw new ClassNotFoundException(e.getMessage(), e.getCause());
        }

    }

    public byte[] createBindingClass(ClassInfo ci, String bindingClassName) {
        //System.out.println("BindingFactory: "+bindingClassName+" (for "+ci.clazz.getClassLoader()+")");
        int count = ci.fields.length;
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
        ClassVisitor cv = cw;//new CheckClassAdapter(cw);

        FieldVisitor fv;
        MethodVisitor mv;
        AnnotationVisitor av0;

        String className = ci.clazz.getName().replaceAll("\\.", "/");
        bindingClassName = bindingClassName.replaceAll("\\.", "/");
        Object[] classNameX = new Object[] { className };
        String signature = "L" + bindingClassName + ";";

        // Constructor
        String superClass = "org/simantics/databoard/binding/reflection/ClassBinding";
        cv.visit(V1_6, ACC_PUBLIC + ACC_SUPER, bindingClassName, null, superClass, null);

        // Constructor
        {
            mv = cv.visitMethod(ACC_PUBLIC, "<init>", "(Lorg/simantics/databoard/type/RecordType;)V", null,
                    new String[] { "org/simantics/databoard/binding/error/BindingConstructionException" });

            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitLdcInsn(Type.getType("L" + className + ";"));
            mv.visitMethodInsn(INVOKESPECIAL, superClass, "<init>", "(Ljava/lang/Class;)V");

            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitFieldInsn(PUTFIELD, bindingClassName, "type", "Lorg/simantics/databoard/type/Datatype;");

            Label l2 = new Label();
            mv.visitLabel(l2);
            mv.visitInsn(RETURN);

            Label l3 = new Label();
            mv.visitLabel(l3);
            mv.visitLocalVariable("this", signature, null, l0, l3, 0);
            mv.visitLocalVariable("type", "Lorg/simantics/databoard/type/RecordType;", null, l0, l3, 1);
            mv.visitMaxs(2, 2);
            mv.visitEnd();
        }

        // getComponent
        {
            mv = cv.visitMethod(ACC_PUBLIC, "getComponent", "(Ljava/lang/Object;I)Ljava/lang/Object;", null,
                    new String[] { "org/simantics/databoard/binding/error/BindingException" });
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitTypeInsn(CHECKCAST, className);
            mv.visitVarInsn(ASTORE, 3);
            Label l1 = new Label();
            mv.visitLabel(l1);

            Label caseLabels[] = createFieldLabels(ci);
            Label elseLabel = new Label();

            if (count > 0) {
                // Switch
                mv.visitVarInsn(ILOAD, 2);
                mv.visitTableSwitchInsn(0, count - 1, elseLabel, caseLabels);

                // case i: x.field = value[i]
                for (int i = 0; i < count; i++) {
                    Label label = caseLabels[i];
                    Field field = ci.fields[i];
                    String fieldName = field.getName();
                    Class<?> fieldClass = ci.fields[i].getType();
                    String typeDescriptor = toTypeDescriptor(fieldClass);

                    Method getter = ci.getters[i];
                    boolean useGetter = ((field.getModifiers() & Modifier.PUBLIC) == 0) && getter != null;

                    mv.visitLabel(label);
                    if (i == 0) {
                        mv.visitFrame(Opcodes.F_APPEND, 1, classNameX, 0, null);
                    } else {
                        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
                    }

                    // Read instance argument
                    mv.visitVarInsn(ALOAD, 3);

                    if (useGetter) {
                        // call getField
                        mv.visitMethodInsn(INVOKEVIRTUAL, className, getter.getName(), "()" + typeDescriptor);
                    } else {
                        // Read field
                        mv.visitFieldInsn(GETFIELD, className, fieldName, typeDescriptor);
                    }

                    // Box 
                    box(mv, fieldClass);

                    mv.visitInsn(ARETURN);
                }

            }

            mv.visitLabel(elseLabel);
            if (count > 0) {
                mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
            }
            mv.visitTypeInsn(NEW, "org/simantics/databoard/binding/error/BindingException");
            mv.visitInsn(DUP);
            mv.visitLdcInsn("Illegal field index");
            mv.visitMethodInsn(INVOKESPECIAL, "org/simantics/databoard/binding/error/BindingException", "<init>",
                    "(Ljava/lang/String;)V");
            mv.visitInsn(ATHROW);

            // End 
            Label l19 = new Label();
            mv.visitLabel(l19);
            mv.visitLocalVariable("this", "L" + className + ";", null, l0, l19, 0);
            mv.visitLocalVariable("obj", "Ljava/lang/Object;", null, l0, l19, 1);
            mv.visitLocalVariable("index", "I", null, l0, l19, 2);
            //mv.visitLocalVariable("x", "Lorg/simantics/databoard/binding/reflection/MyClass;", null, l1, l19, 3);
            mv.visitMaxs(3, 4);
            mv.visitEnd();
        }

        // Create
        {
            mv = cv.visitMethod(ACC_PUBLIC + ACC_VARARGS, "create", "([Ljava/lang/Object;)Ljava/lang/Object;", null,
                    new String[] { "org/simantics/databoard/binding/error/BindingException" });
            if (ci.beanConstructor != null) {
                mv.visitCode();
                Label l0 = new Label();
                mv.visitLabel(l0);
                mv.visitTypeInsn(NEW, className);
                mv.visitInsn(DUP);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitMethodInsn(INVOKESPECIAL, className, "<init>",
                        "(Lorg/simantics/databoard/binding/Binding;)V");
                mv.visitVarInsn(ASTORE, 2);
                Label l1 = new Label();
                mv.visitLabel(l1);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitVarInsn(ALOAD, 2);
                mv.visitVarInsn(ALOAD, 1);
                mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "setComponents",
                        "(Ljava/lang/Object;[Ljava/lang/Object;)V");
                Label l2 = new Label();
                mv.visitLabel(l2);
                mv.visitVarInsn(ALOAD, 2);
                mv.visitInsn(ARETURN);
                Label l3 = new Label();
                mv.visitLabel(l3);
                mv.visitLocalVariable("this", "L" + bindingClassName + ";", null, l0, l3, 0);
                mv.visitLocalVariable("values", "[Ljava/lang/Object;", null, l0, l3, 1);
                //mv.visitLocalVariable("x", "L"+className+";", null, l1, l3, 2);
                mv.visitMaxs(3, 3);
                mv.visitEnd();
            } else if (ci.argsConstructor != null) {
                mv.visitCode();
                Label l0 = new Label();
                mv.visitLabel(l0);
                mv.visitTypeInsn(NEW, className);
                mv.visitInsn(DUP);

                String constArgsDescriptor = "(";
                Class<?>[] args = ci.argsConstructor.getParameterTypes();
                for (int i = 0; i < count; i++) {
                    Label label = new Label();
                    Class<?> field = args[i];
                    String fieldName = field.getName();
                    Method getter = ci.getters[i];
                    Class<?> fieldClass = ci.fields[i].getType();
                    Class<?> boxClass = getBoxClass(fieldClass);
                    String typeDescriptor = toTypeDescriptor(fieldClass);
                    String boxTypeDescriptor = toTypeDescriptor(boxClass);
                    constArgsDescriptor += typeDescriptor;

                    mv.visitLabel(label);
                    mv.visitVarInsn(ALOAD, 1);
                    if (i < 6) {
                        mv.visitInsn(ICONST_0 + i);
                    } else {
                        mv.visitIntInsn(BIPUSH, i);
                    }

                    mv.visitInsn(AALOAD);
                    mv.visitTypeInsn(CHECKCAST, toClassCanonicalName(boxClass));
                    unbox(mv, fieldClass);
                }

                Label l17 = new Label();
                mv.visitLabel(l17);
                constArgsDescriptor += ")V";
                mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", constArgsDescriptor);
                mv.visitInsn(ARETURN);
                Label l18 = new Label();
                mv.visitLabel(l18);
                mv.visitLocalVariable("this", "L" + bindingClassName + ";", null, l0, l18, 0);
                mv.visitLocalVariable("values", "[Ljava/lang/Object;", null, l0, l18, 1);
                mv.visitMaxs(21, 2);
                mv.visitEnd();

            } else {
                mv.visitCode();
                Label l0 = new Label();
                mv.visitLabel(l0);
                mv.visitTypeInsn(NEW, className);
                mv.visitInsn(DUP);
                mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "()V");
                mv.visitVarInsn(ASTORE, 2);
                Label l1 = new Label();
                mv.visitLabel(l1);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitVarInsn(ALOAD, 2);
                mv.visitVarInsn(ALOAD, 1);
                mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "setComponents",
                        "(Ljava/lang/Object;[Ljava/lang/Object;)V");
                Label l2 = new Label();
                mv.visitLabel(l2);
                mv.visitVarInsn(ALOAD, 2);
                mv.visitInsn(ARETURN);
                Label l3 = new Label();
                mv.visitLabel(l3);
                mv.visitLocalVariable("this", "L" + bindingClassName + ";", null, l0, l3, 0);
                mv.visitLocalVariable("values", "[Ljava/lang/Object;", null, l0, l3, 1);
                //mv.visitLocalVariable("x", "L"+className+";", null, l1, l3, 2);
                mv.visitMaxs(3, 3);
                mv.visitEnd();
            }
        }

        // CreatePartial
        mv = cv.visitMethod(ACC_PUBLIC, "createPartial", "()Ljava/lang/Object;", null,
                new String[] { "org/simantics/databoard/binding/error/BindingException" });
        if (ci.beanConstructor != null) {
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitTypeInsn(NEW, className);
            mv.visitInsn(DUP);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "(Lorg/simantics/databoard/binding/Binding;)V");
            mv.visitInsn(ARETURN);
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLocalVariable("this", "L" + bindingClassName + ";", null, l0, l1, 0);
            mv.visitMaxs(3, 1);
            mv.visitEnd();
        } else if (ci.noArgsConstructor != null) {
            // return new MyClass();
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitTypeInsn(NEW, className);
            mv.visitInsn(DUP);
            mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "()V");
            mv.visitInsn(ARETURN);
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLocalVariable("this", "L" + bindingClassName + ";", null, l0, l1, 0);
            mv.visitMaxs(2, 1);
            mv.visitEnd();
        } else {
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitIntInsn(BIPUSH, count);
            mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
            mv.visitVarInsn(ASTORE, 1);
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitInsn(ICONST_0);
            mv.visitVarInsn(ISTORE, 2);
            Label l2 = new Label();
            mv.visitLabel(l2);
            Label l3 = new Label();
            mv.visitJumpInsn(GOTO, l3);
            Label l4 = new Label();
            mv.visitLabel(l4);
            mv.visitFrame(Opcodes.F_APPEND, 2, new Object[] { "[Ljava/lang/Object;", Opcodes.INTEGER }, 0, null);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, bindingClassName, "componentBindings",
                    "[Lorg/simantics/databoard/binding/Binding;");
            mv.visitVarInsn(ILOAD, 2);
            mv.visitInsn(AALOAD);
            mv.visitVarInsn(ASTORE, 3);
            Label l5 = new Label();
            mv.visitLabel(l5);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitVarInsn(ILOAD, 2);
            mv.visitVarInsn(ALOAD, 3);
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/Binding", "createDefault",
                    "()Ljava/lang/Object;");
            mv.visitInsn(AASTORE);
            Label l6 = new Label();
            mv.visitLabel(l6);
            mv.visitIincInsn(2, 1);
            mv.visitLabel(l3);
            mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
            mv.visitVarInsn(ILOAD, 2);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitInsn(ARRAYLENGTH);
            mv.visitJumpInsn(IF_ICMPLT, l4);
            Label l7 = new Label();
            mv.visitLabel(l7);
            mv.visitLineNumber(109, l7);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "create",
                    "([Ljava/lang/Object;)Ljava/lang/Object;");
            mv.visitInsn(ARETURN);
            Label l8 = new Label();
            mv.visitLabel(l8);
            mv.visitLocalVariable("this", "L" + bindingClassName + ";", null, l0, l8, 0);
            mv.visitLocalVariable("values", "[Ljava/lang/Object;", null, l1, l8, 1);
            mv.visitLocalVariable("i", "I", null, l2, l7, 2);
            mv.visitLocalVariable("fb", "Lorg/simantics/databoard/binding/Binding;", null, l5, l6, 3);
            mv.visitMaxs(3, 4);
            mv.visitEnd();
        }

        // setComponent
        {
            mv = cv.visitMethod(ACC_PUBLIC, "setComponent", "(Ljava/lang/Object;ILjava/lang/Object;)V", null,
                    new String[] { "org/simantics/databoard/binding/error/BindingException" });
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitTypeInsn(CHECKCAST, className);
            mv.visitVarInsn(ASTORE, 4);
            Label endLabel = new Label();
            Label l1 = new Label();
            mv.visitLabel(l1);

            Label elseLabel = new Label();
            Label labels[] = new Label[count];
            for (int i = 0; i < count; i++)
                labels[i] = new Label();

            if (count > 0) {
                mv.visitVarInsn(ILOAD, 2);
                mv.visitTableSwitchInsn(0, count - 1, elseLabel, labels);

                for (int i = 0; i < count; i++) {
                    Label label = labels[i];
                    mv.visitLabel(label);
                    Field field = ci.fields[i];
                    String fieldName = field.getName();
                    Class<?> fieldClass = ci.fields[i].getType();
                    Class<?> boxClass = getBoxClass(fieldClass);
                    String typeDescriptor = toTypeDescriptor(fieldClass);
                    String boxTypeDescriptor = toTypeDescriptor(boxClass);

                    Method setter = ci.setters[i];
                    Class<?> setterClass = setter != null ? setter.getParameterTypes()[0] : null;
                    boolean useSetter = ((field.getModifiers() & Modifier.PUBLIC) == 0) && setter != null;

                    if (i == 0) {
                        mv.visitFrame(Opcodes.F_APPEND, 1, classNameX, 0, null);
                    } else {
                        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
                    }
                    mv.visitVarInsn(ALOAD, 4);
                    mv.visitVarInsn(ALOAD, 3);
                    mv.visitTypeInsn(CHECKCAST, toClassCanonicalName(boxClass));

                    if (useSetter) {
                        unbox(mv, setterClass);
                        mv.visitMethodInsn(INVOKEVIRTUAL, className, setter.getName(), "(" + typeDescriptor + ")V");
                    } else {
                        unbox(mv, fieldClass);
                        mv.visitFieldInsn(PUTFIELD, className, field.getName(), typeDescriptor);
                    }
                    mv.visitInsn(RETURN);
                }
            }

            mv.visitLabel(elseLabel);
            mv.visitLineNumber(178, elseLabel);
            if (count > 0) {
                mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
            }
            mv.visitTypeInsn(NEW, "org/simantics/databoard/binding/error/BindingException");
            mv.visitInsn(DUP);
            mv.visitLdcInsn("Illegal field index");
            mv.visitMethodInsn(INVOKESPECIAL, "org/simantics/databoard/binding/error/BindingException", "<init>",
                    "(Ljava/lang/String;)V");
            mv.visitInsn(ATHROW);

            mv.visitLabel(endLabel);
            mv.visitLocalVariable("this", "L" + bindingClassName + ";", null, l0, endLabel, 0);
            mv.visitLocalVariable("obj", "Ljava/lang/Object;", null, l0, endLabel, 1);
            mv.visitLocalVariable("index", "I", null, l0, endLabel, 2);
            mv.visitLocalVariable("value", "Ljava/lang/Object;", null, l0, endLabel, 3);
            //mv.visitLocalVariable("x", "L"+className+";", null, l1, endLabel, 4);
            mv.visitMaxs(3, 5);
            mv.visitEnd();
        }

        // IsImmutable
        {
            mv = cv.visitMethod(ACC_PUBLIC, "isImmutable", "()Z", null, null);
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitInsn(ICONST_0);
            mv.visitInsn(IRETURN);
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLocalVariable("this", "L" + className + ";", null, l0, l1, 0);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }

        // IsInstance
        {
            mv = cv.visitMethod(ACC_PUBLIC, "isInstance", "(Ljava/lang/Object;)Z", null, null);
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitTypeInsn(INSTANCEOF, className);
            mv.visitInsn(IRETURN);
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLocalVariable("this", "L" + className + ";", null, l0, l1, 0);
            mv.visitLocalVariable("obj", "Ljava/lang/Object;", null, l0, l1, 1);
            mv.visitMaxs(1, 2);
            mv.visitEnd();
        }

        // SetComponents
        {
            mv = cv.visitMethod(ACC_PUBLIC + ACC_VARARGS, "setComponents",
                    "(Ljava/lang/Object;[Ljava/lang/Object;)V", null,
                    new String[] { "org/simantics/databoard/binding/error/BindingException" });
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitTypeInsn(CHECKCAST, className);
            mv.visitVarInsn(ASTORE, 3);
            Label firstLabel = l0;

            for (int i = 0; i < count; i++) {
                Label label = new Label();
                if (firstLabel == l0)
                    firstLabel = label;
                Field field = ci.fields[i];
                String fieldName = field.getName();
                Class<?> fieldClass = ci.fields[i].getType();
                Class<?> boxClass = getBoxClass(fieldClass);
                String typeDescriptor = toTypeDescriptor(fieldClass);
                String boxTypeDescriptor = toTypeDescriptor(boxClass);

                Method setter = ci.setters[i];
                Class<?> setterClass = setter != null ? setter.getParameterTypes()[0] : null;
                boolean useSetter = ((field.getModifiers() & Modifier.PUBLIC) == 0) && setter != null;

                mv.visitLabel(label);
                mv.visitVarInsn(ALOAD, 3);
                mv.visitVarInsn(ALOAD, 2);
                if (i < 6) {
                    mv.visitInsn(ICONST_0 + i);
                } else {
                    mv.visitIntInsn(BIPUSH, i);
                }
                mv.visitInsn(AALOAD);
                mv.visitTypeInsn(CHECKCAST, toClassCanonicalName(boxClass));

                if (useSetter) {
                    unbox(mv, setterClass);
                    mv.visitMethodInsn(INVOKEVIRTUAL, className, setter.getName(), "(" + typeDescriptor + ")V");
                } else {
                    unbox(mv, fieldClass);
                    mv.visitFieldInsn(PUTFIELD, className, field.getName(), typeDescriptor);
                }

            }
            Label l17 = new Label();
            mv.visitLabel(l17);
            mv.visitInsn(RETURN);
            Label endLabel = new Label();
            mv.visitLabel(endLabel);
            mv.visitLocalVariable("this", "L" + className + ";", null, l0, endLabel, 0);
            mv.visitLocalVariable("obj", "Ljava/lang/Object;", null, l0, endLabel, 1);
            mv.visitLocalVariable("value", "[Ljava/lang/Object;", null, l0, endLabel, 2);
            //mv.visitLocalVariable("x", "Lorg/simantics/databoard/binding/reflection/MyClass;", null, firstLabel, endLabel, 3);
            mv.visitMaxs(3, 4);
            mv.visitEnd();
        }

        // Add primitive setters
        {
            addGetSetPrimitive(ci, cv, "Boolean", "Z", bindingClassName);
            addGetSetPrimitive(ci, cv, "Byte", "B", bindingClassName);
            addGetSetPrimitive(ci, cv, "Int", "I", bindingClassName);
            addGetSetPrimitive(ci, cv, "Long", "J", bindingClassName);
            addGetSetPrimitive(ci, cv, "Float", "F", bindingClassName);
            addGetSetPrimitive(ci, cv, "Double", "D", bindingClassName);
        }

        cv.visitEnd();
        return cw.toByteArray();
    }

    private void addGetSetPrimitive(ClassInfo ci, ClassVisitor cv, String setterName, String signature,
            String bindingClassName) {
        String className = ci.clazz.getName().replaceAll("\\.", "/");

        Label firstLabel = new Label();
        Label secondLabel = new Label();
        Label errorLabel = new Label();
        Label exitLabel = new Label();
        Label lastLabel = new Label();

        boolean oneByte = !signature.equals("J") && !signature.equals("D");

        int c = 0;
        for (Field f : ci.fields) {
            if (toTypeDescriptor(getPrimitiveClass(f.getType())).equals(signature))
                c++;
        }

        int[] indices = new int[c];
        Label[] caseLabel = new Label[c];

        c = 0;
        for (int i = 0; i < ci.fields.length; i++) {
            Class<?> fieldClass = ci.fields[i].getType();
            fieldClass = getPrimitiveClass(fieldClass);
            String s = toTypeDescriptor(fieldClass);
            if (!s.equals(signature))
                continue;

            indices[c] = i;
            caseLabel[c] = new Label();
            c++;
        }

        //////////////////
        /// Setter
        ///
        MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "set" + setterName, "(Ljava/lang/Object;I" + signature + ")V",
                null, new String[] { "org/simantics/databoard/binding/error/BindingException" });
        mv.visitCode();
        mv.visitLabel(firstLabel);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitTypeInsn(CHECKCAST, className);
        mv.visitVarInsn(ASTORE, oneByte ? 4 : 5);

        mv.visitLabel(secondLabel);
        mv.visitVarInsn(ILOAD, 2);

        // switch
        mv.visitLookupSwitchInsn(errorLabel, indices, caseLabel);

        // case 1:
        if (c > 0) {
            for (int i = 0; i < c; i++) {
                int index = indices[i];
                Method setter = ci.setters[index];
                Field field = ci.fields[index];
                Class<?> fieldClass = field.getType();
                Class<?> setterClass = setter != null ? setter.getParameterTypes()[0] : null;
                boolean useSetter = ((field.getModifiers() & Modifier.PUBLIC) == 0) && setter != null;
                String typeDescriptor = toTypeDescriptor(useSetter ? setterClass : fieldClass);

                mv.visitLabel(caseLabel[i]);
                if (i == 0) {
                    mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] { className }, 0, null);
                } else {
                    mv.visitFrame(Opcodes.F_SAME, 0, new Object[] { className }, 0, null);
                }
                if (signature.equals("F")) {
                    mv.visitVarInsn(ALOAD, 4);
                    mv.visitVarInsn(FLOAD, 3);
                } else if (signature.equals("D")) {
                    mv.visitVarInsn(ALOAD, 5);
                    mv.visitVarInsn(DLOAD, 3);
                } else if (signature.equals("J")) {
                    mv.visitVarInsn(ALOAD, 5);
                    mv.visitVarInsn(LLOAD, 3);
                } else {
                    mv.visitVarInsn(ALOAD, 4);
                    mv.visitVarInsn(ILOAD, 3);
                }

                if (useSetter) {
                    boxTo(mv, setterClass);
                    mv.visitMethodInsn(INVOKEVIRTUAL, className, setter.getName(), "(" + typeDescriptor + ")V");
                } else {
                    boxTo(mv, fieldClass);
                    mv.visitFieldInsn(PUTFIELD, className, field.getName(), typeDescriptor);
                }
                mv.visitJumpInsn(GOTO, exitLabel);
            }
        } else {
            mv.visitInsn(POP);
        }

        // default: (error)
        /*
        mv.visitLabel(errorLabel);
        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
        mv.visitTypeInsn(NEW, "org/simantics/databoard/binding/error/BindingException");
        mv.visitInsn(DUP);
        mv.visitLdcInsn("Field is not "+setterName);
        mv.visitMethodInsn(INVOKESPECIAL, "org/simantics/databoard/binding/error/BindingException", "<init>", "(Ljava/lang/String;)V");
        mv.visitInsn(ATHROW);
        */

        // default: setComponent
        mv.visitLabel(errorLabel);
        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitVarInsn(ILOAD, 2);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, bindingClassName, "componentBindings",
                "[Lorg/simantics/databoard/binding/Binding;");
        mv.visitVarInsn(ILOAD, 2);
        mv.visitInsn(AALOAD);
        if (signature.equals("F")) {
            mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/FloatBinding");
            mv.visitVarInsn(FLOAD, 3);
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/FloatBinding", "create",
                    "(F)Ljava/lang/Object;");
        } else if (signature.equals("D")) {
            mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/DoubleBinding");
            mv.visitVarInsn(DLOAD, 3);
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/DoubleBinding", "create",
                    "(D)Ljava/lang/Object;");
        } else if (signature.equals("J")) {
            mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/LongBinding");
            mv.visitVarInsn(LLOAD, 3);
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/LongBinding", "create",
                    "(J)Ljava/lang/Object;");
        } else if (signature.equals("Z")) {
            mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/BooleanBinding");
            mv.visitVarInsn(ILOAD, 3);
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/BooleanBinding", "create",
                    "(Z)Ljava/lang/Object;");
        } else if (signature.equals("I")) {
            mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/IntBinding");
            mv.visitVarInsn(ILOAD, 3);
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/IntBinding", "create",
                    "(I)Ljava/lang/Object;");
        } else if (signature.equals("B")) {
            mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/ByteBinding");
            mv.visitVarInsn(ILOAD, 3);
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/ByteBinding", "create",
                    "(B)Ljava/lang/Object;");
        }
        mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "setComponent",
                "(Ljava/lang/Object;ILjava/lang/Object;)V");

        // return
        mv.visitLabel(exitLabel);
        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
        mv.visitInsn(RETURN);

        // Something at the end
        mv.visitLabel(lastLabel);
        //       mv.visitLocalVariable("this", "L"+bindingClassName+";", null, firstLabel, lastLabel, 0);
        //       mv.visitLocalVariable("r", "Ljava/lang/Object;", null, firstLabel, lastLabel, 1);
        //       mv.visitLocalVariable("index", "I", null, firstLabel, lastLabel, 2);
        //       mv.visitLocalVariable("z", signature, null, firstLabel, lastLabel, 3);
        //       mv.visitLocalVariable("x", "L"+className+";", null, secondLabel, lastLabel, 4);
        mv.visitMaxs(oneByte ? 5 : 6, oneByte ? 5 : 6);
        mv.visitEnd();

        //////////////////
        /// Getter
        ///
        firstLabel = new Label();
        secondLabel = new Label();
        errorLabel = new Label();
        exitLabel = new Label();
        lastLabel = new Label();
        for (int i = 0; i < c; i++)
            caseLabel[i] = new Label();
        mv = cv.visitMethod(ACC_PUBLIC, "get" + setterName, "(Ljava/lang/Object;I)" + signature, null,
                new String[] { "org/simantics/databoard/binding/error/BindingException" });
        mv.visitCode();
        mv.visitLabel(firstLabel);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitTypeInsn(CHECKCAST, className);
        mv.visitVarInsn(ASTORE, 3);

        mv.visitLabel(secondLabel);
        mv.visitVarInsn(ILOAD, 2);

        // switch
        if (c > 0) {
            mv.visitLookupSwitchInsn(errorLabel, indices, caseLabel);

            // case i:
            for (int i = 0; i < c; i++) {
                int index = indices[i];
                Method getter = ci.getters[index];
                Field field = ci.fields[index];
                Class<?> fieldClass = field.getType();
                Class<?> getterClass = getter != null ? getter.getReturnType() : null;
                boolean useGetter = ((field.getModifiers() & Modifier.PUBLIC) == 0) && getter != null;
                String typeDescriptor = toTypeDescriptor(useGetter ? getterClass : fieldClass);

                mv.visitLabel(caseLabel[i]);
                if (i == 0) {
                    mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] { className }, 0, null);
                } else {
                    mv.visitFrame(Opcodes.F_SAME, 0, new Object[] { className }, 0, null);
                }

                mv.visitVarInsn(ALOAD, 3);

                if (useGetter) {
                    mv.visitMethodInsn(INVOKEVIRTUAL, className, getter.getName(), "()" + typeDescriptor);
                    unboxFrom(mv, getterClass);
                } else {
                    mv.visitFieldInsn(GETFIELD, className, field.getName(), typeDescriptor);
                    unboxFrom(mv, fieldClass);
                }

                if (signature.equals("F")) {
                    mv.visitInsn(FRETURN);
                } else if (signature.equals("D")) {
                    mv.visitInsn(DRETURN);
                } else if (signature.equals("J")) {
                    mv.visitInsn(LRETURN);
                } else {
                    mv.visitInsn(IRETURN);
                }
            }
        } else {
            mv.visitInsn(POP);
        }

        // default: (error)
        /*
        mv.visitLabel(errorLabel);
        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
        mv.visitTypeInsn(NEW, "org/simantics/databoard/binding/error/BindingException");
        mv.visitInsn(DUP);
        mv.visitLdcInsn("Field is not "+setterName);
        mv.visitMethodInsn(INVOKESPECIAL, "org/simantics/databoard/binding/error/BindingException", "<init>", "(Ljava/lang/String;)V");
        mv.visitInsn(ATHROW);
        */

        // default:
        mv.visitLabel(errorLabel);
        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, bindingClassName, "componentBindings",
                "[Lorg/simantics/databoard/binding/Binding;");
        mv.visitVarInsn(ILOAD, 2);
        mv.visitInsn(AALOAD);
        if (signature.equals("Z")) {
            mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/BooleanBinding");
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitVarInsn(ILOAD, 2);
            mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "getComponent",
                    "(Ljava/lang/Object;I)Ljava/lang/Object;");
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/BooleanBinding", "getValue_",
                    "(Ljava/lang/Object;)Z");
            mv.visitInsn(IRETURN);
        } else if (signature.equals("B")) {
            mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/ByteBinding");
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitVarInsn(ILOAD, 2);
            mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "getComponent",
                    "(Ljava/lang/Object;I)Ljava/lang/Object;");
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/ByteBinding", "getValue_",
                    "(Ljava/lang/Object;)B");
            mv.visitInsn(IRETURN);
        } else if (signature.equals("I")) {
            mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/IntBinding");
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitVarInsn(ILOAD, 2);
            mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "getComponent",
                    "(Ljava/lang/Object;I)Ljava/lang/Object;");
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/IntBinding", "getValue_",
                    "(Ljava/lang/Object;)I");
            mv.visitInsn(IRETURN);
        } else if (signature.equals("J")) {
            mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/LongBinding");
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitVarInsn(ILOAD, 2);
            mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "getComponent",
                    "(Ljava/lang/Object;I)Ljava/lang/Object;");
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/LongBinding", "getValue_",
                    "(Ljava/lang/Object;)J");
            mv.visitInsn(LRETURN);
        } else if (signature.equals("F")) {
            mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/FloatBinding");
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitVarInsn(ILOAD, 2);
            mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "getComponent",
                    "(Ljava/lang/Object;I)Ljava/lang/Object;");
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/FloatBinding", "getValue_",
                    "(Ljava/lang/Object;)F");
            mv.visitInsn(FRETURN);
        } else if (signature.equals("D")) {
            mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/DoubleBinding");
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitVarInsn(ILOAD, 2);
            mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "getComponent",
                    "(Ljava/lang/Object;I)Ljava/lang/Object;");
            mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/DoubleBinding", "getValue_",
                    "(Ljava/lang/Object;)D");
            mv.visitInsn(DRETURN);
        }

        // Something at the end
        mv.visitLabel(lastLabel);
        //       mv.visitLocalVariable("this", "Lorg/simantics/databoard/binding/reflection/MyBinding;", null, firstLabel, lastLabel, 0);
        //       mv.visitLocalVariable("r", "Ljava/lang/Object;", null, firstLabel, lastLabel, 1);
        //       mv.visitLocalVariable("index", "I", null, firstLabel, lastLabel, 2);
        //       mv.visitLocalVariable("x", "Lorg/simantics/databoard/binding/reflection/MyClass;", null, secondLabel, lastLabel, 3);
        mv.visitMaxs(4, 4);
        mv.visitEnd();

    }

    public static Label[] createFieldLabels(ClassInfo ci) {
        Label caseLabels[] = new Label[ci.fields.length];
        for (int i = 0; i < ci.fields.length; i++)
            caseLabels[i] = new Label();
        return caseLabels;
    }

    public static String toTypeDescriptor(Class<?> clazz) {
        if (clazz == void.class)
            return "V";
        if (clazz == boolean.class)
            return "Z";
        if (clazz == char.class)
            return "C";
        if (clazz == byte.class)
            return "B";
        if (clazz == short.class)
            return "S";
        if (clazz == int.class)
            return "I";
        if (clazz == float.class)
            return "F";
        if (clazz == long.class)
            return "J";
        if (clazz == double.class)
            return "D";
        if (clazz.isArray())
            return clazz.getName().replaceAll("\\.", "/");
        return "L" + clazz.getName().replaceAll("\\.", "/") + ";";
    }

    /**
     * Get respective boxed class
     * @param clazz
     * @return box-class
     */
    public static Class<?> getBoxClass(Class<?> clazz) {
        if (clazz == void.class)
            return null;
        if (clazz == boolean.class)
            return Boolean.class;
        if (clazz == char.class)
            return Character.class;
        if (clazz == byte.class)
            return Byte.class;
        if (clazz == short.class)
            return Short.class;
        if (clazz == int.class)
            return Integer.class;
        if (clazz == float.class)
            return Float.class;
        if (clazz == long.class)
            return Long.class;
        if (clazz == double.class)
            return Double.class;
        return clazz;
    }

    /**
     * Get respective primitive class
     * @param clazz
     * @return primitive-class
     */
    public static Class<?> getPrimitiveClass(Class<?> clazz) {
        if (clazz == Boolean.class)
            return boolean.class;
        if (clazz == Character.class)
            return char.class;
        if (clazz == Byte.class)
            return byte.class;
        if (clazz == Short.class)
            return short.class;
        if (clazz == Integer.class)
            return int.class;
        if (clazz == Float.class)
            return float.class;
        if (clazz == Long.class)
            return long.class;
        if (clazz == Double.class)
            return double.class;
        return clazz;
    }

    public static boolean isPrimitive(Class<?> clazz) {
        return clazz == boolean.class || clazz == char.class || clazz == byte.class || clazz == short.class
                || clazz == int.class || clazz == float.class || clazz == long.class || clazz == double.class;
    }

    public static void unbox(MethodVisitor mv, Class<?> clazz) {
        if (clazz == boolean.class) {
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
        } else if (clazz == char.class) {
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C"); // C?
        } else if (clazz == byte.class) {
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
        } else if (clazz == short.class) {
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
        } else if (clazz == int.class) {
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
        } else if (clazz == float.class) {
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
        } else if (clazz == long.class) {
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
        } else if (clazz == double.class) {
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
        }
    }

    public static void box(MethodVisitor mv, Class<?> clazz) {
        if (clazz == boolean.class) {
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
        } else if (clazz == char.class) {
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
        } else if (clazz == byte.class) {
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
        } else if (clazz == short.class) {
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
        } else if (clazz == int.class) {
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
        } else if (clazz == float.class) {
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
        } else if (clazz == long.class) {
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
        } else if (clazz == double.class) {
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
        }
    }

    public static void boxTo(MethodVisitor mv, Class<?> clazz) {
        if (clazz == Boolean.class) {
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
        } else if (clazz == Character.class) {
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
        } else if (clazz == Byte.class) {
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
        } else if (clazz == Short.class) {
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
        } else if (clazz == Integer.class) {
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
        } else if (clazz == Float.class) {
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
        } else if (clazz == Long.class) {
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
        } else if (clazz == Double.class) {
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
        }
    }

    public static void unboxFrom(MethodVisitor mv, Class<?> clazz) {
        if (clazz == Boolean.class) {
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
        } else if (clazz == Character.class) {
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C"); // C?
        } else if (clazz == Byte.class) {
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
        } else if (clazz == Short.class) {
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
        } else if (clazz == Integer.class) {
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
        } else if (clazz == Float.class) {
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
        } else if (clazz == Long.class) {
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
        } else if (clazz == Double.class) {
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
        }
    }

    public static String toClassCanonicalName(Class<?> clazz) {
        return clazz.getName().replaceAll("\\.", "/");
    }

}