All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.drools.core.factmodel.DefaultBeanClassBuilder Maven / Gradle / Ivy

There is a newer version: 9.44.0.Final
Show newest version
/*
 * Copyright 2008 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed 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.drools.core.factmodel;

import org.drools.core.factmodel.traits.Thing;
import org.drools.core.factmodel.traits.TraitFieldTMS;
import org.drools.core.factmodel.traits.TraitFieldTMSImpl;
import org.drools.core.factmodel.traits.TraitTypeMap;
import org.drools.core.factmodel.traits.TraitableBean;
import org.drools.core.phreak.ReactiveObject;
import org.kie.api.definition.type.FactField;
import org.mvel2.asm.AnnotationVisitor;
import org.mvel2.asm.ClassVisitor;
import org.mvel2.asm.ClassWriter;
import org.mvel2.asm.FieldVisitor;
import org.mvel2.asm.Label;
import org.mvel2.asm.MethodVisitor;
import org.mvel2.asm.Opcodes;
import org.mvel2.asm.Type;

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.BitSet;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.drools.core.rule.builder.dialect.asm.ClassGenerator.createClassWriter;

/**
 * A builder to dynamically build simple Javabean(TM) classes
 */
public class DefaultBeanClassBuilder implements Opcodes, BeanClassBuilder, Serializable {
    protected boolean     debug  = false;

    public DefaultBeanClassBuilder() {
        this( "true".equalsIgnoreCase( System.getProperty( "org.drools.classbuilder.debug" ) ) );
    }

    public DefaultBeanClassBuilder(final boolean debug) {
        this.debug = debug;
    }


    /**
     * Dynamically builds, defines and loads a class based on the given class definition
     *
     * @param classDef the class definition object structure
     *
     * @return the Class instance for the given class definition
     *
     * @throws IOException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws ClassNotFoundException
     * @throws IllegalArgumentException
     * @throws SecurityException
     * @throws NoSuchFieldException
     * @throws InstantiationException
     */
    public byte[] buildClass( ClassDefinition classDef, ClassLoader classLoader ) throws IOException,
            SecurityException,
            IllegalArgumentException,
            ClassNotFoundException,
            NoSuchMethodException,
            IllegalAccessException,
            InvocationTargetException,
            InstantiationException,
            NoSuchFieldException {

        ClassWriter cw = this.buildClassHeader( classLoader, classDef );

        this.buildFields( cw, classDef );

        if ( classDef.isTraitable() ) {
            this.buildDynamicPropertyMap( cw, classDef );
            this.buildTraitMap( cw, classDef );
            this.buildFieldTMS( cw, classDef );
        }

        this.buildConstructors( cw, classDef );

        this.buildGettersAndSetters( cw, classDef );

        this.buildEqualityMethods( cw, classDef );

        this.buildToString( cw, classDef );

        if ( classDef.isTraitable() ) {
            // must guarantee serialization order when enhancing fields are present
            this.buildSerializationMethods(cw, classDef);
        }

        if ( classDef.isReactive() ) {
            implementReactivity( cw, classDef );
        }

        cw.visitEnd();

        return cw.toByteArray();
    }

    private void buildSerializationMethods(ClassWriter cw, ClassDefinition classDef) {
        MethodVisitor mv;
        {
            mv = cw.visitMethod(ACC_PUBLIC, "writeExternal", "(Ljava/io/ObjectOutput;)V", null, new String[]{"java/io/IOException"});
            mv.visitCode();

            for (  FieldDefinition field : classDef.getFieldsDefinitions() ) {

                mv.visitVarInsn( ALOAD, 1 );
                mv.visitVarInsn( ALOAD, 0 );
                visitFieldOrGetter( mv, classDef, field );
                mv.visitMethodInsn( INVOKEINTERFACE, 
                                    "java/io/ObjectOutput", 
                                    BuildUtils.serializationWriterName( field.getTypeName() ),
                                    "(" + ( BuildUtils.isPrimitive( field.getTypeName() ) ?
                                            BuildUtils.getTypeDescriptor( BuildUtils.serializationType( field.getTypeName() ) ) :
                                            "Ljava/lang/Object;" ) + ")V");
                               
            }

            if ( classDef.isTraitable() ) {
                mv.visitVarInsn( ALOAD, 1 );
                mv.visitVarInsn( ALOAD, 0 );
                mv.visitFieldInsn( Opcodes.GETFIELD,
                                   BuildUtils.getInternalType( classDef.getClassName() ),
                                   TraitableBean.MAP_FIELD_NAME,
                                   Type.getDescriptor( Map.class ) );
                mv.visitMethodInsn( INVOKEINTERFACE,
                                    "java/io/ObjectOutput",
                                    "writeObject",
                                    "(Ljava/lang/Object;)V" );

                mv.visitVarInsn( ALOAD, 1 );
                mv.visitVarInsn( ALOAD, 0 );
                mv.visitFieldInsn( Opcodes.GETFIELD,
                                   BuildUtils.getInternalType( classDef.getClassName() ),
                                   TraitableBean.TRAITSET_FIELD_NAME,
                                   Type.getDescriptor( Map.class ) );
                mv.visitMethodInsn( INVOKEINTERFACE,
                                    "java/io/ObjectOutput",
                                    "writeObject",
                                    "(Ljava/lang/Object;)V" );

                if ( classDef.isFullTraiting() ) {
                    mv.visitVarInsn( ALOAD, 1 );
                    mv.visitVarInsn( ALOAD, 0 );
                    mv.visitFieldInsn( Opcodes.GETFIELD,
                                       BuildUtils.getInternalType( classDef.getClassName() ),
                                       TraitableBean.FIELDTMS_FIELD_NAME,
                                       Type.getDescriptor( TraitFieldTMS.class ) );
                    mv.visitMethodInsn( INVOKEINTERFACE,
                                        "java/io/ObjectOutput",
                                        "writeObject",
                                        "(Ljava/lang/Object;)V" );
                }
            }

            mv.visitInsn(RETURN);
            mv.visitMaxs( 0, 0 );
            mv.visitEnd();
        }
        {
            mv = cw.visitMethod(ACC_PUBLIC, "readExternal", "(Ljava/io/ObjectInput;)V", null, new String[]{"java/io/IOException", "java/lang/ClassNotFoundException"});
            mv.visitCode();

            for (  FieldDefinition field : classDef.getFieldsDefinitions() ) {
                mv.visitVarInsn( ALOAD, 0 );
                mv.visitVarInsn( ALOAD, 1 );
                mv.visitMethodInsn( INVOKEINTERFACE,
                                    "java/io/ObjectInput",
                                    BuildUtils.serializationReaderName( field.getTypeName() ),
                                    "()" + ( BuildUtils.isPrimitive( field.getTypeName() ) ?
                                             BuildUtils.getTypeDescriptor( field.getTypeName() ) :
                                             "Ljava/lang/Object;" ) );
                if  ( !  BuildUtils.isPrimitive( field.getTypeName() ) ) {
                    mv.visitTypeInsn( CHECKCAST, BuildUtils.getInternalType( field.getTypeName() ) );
                }
                mv.visitMethodInsn( INVOKEVIRTUAL,
                                    BuildUtils.getInternalType( classDef.getName() ),
                                    BuildUtils.setterName( field.getName(), field.getTypeName() ),
                                    "(" + BuildUtils.getTypeDescriptor( field.getTypeName() )+ ")V");
            }

            if ( classDef.isTraitable() ) {
                mv.visitVarInsn( ALOAD, 0 );
                mv.visitVarInsn( ALOAD, 1 );
                mv.visitMethodInsn( INVOKEINTERFACE,
                                    "java/io/ObjectInput",
                                    "readObject",
                                    "()Ljava/lang/Object;");
                mv.visitTypeInsn( CHECKCAST, "java/util/Map" );
                mv.visitFieldInsn( Opcodes.PUTFIELD,
                                   BuildUtils.getInternalType( classDef.getClassName() ),
                                   TraitableBean.MAP_FIELD_NAME,
                                   Type.getDescriptor( Map.class ) );
//
                mv.visitVarInsn( ALOAD, 0 );
                mv.visitVarInsn( ALOAD, 1 );
                mv.visitMethodInsn( INVOKEINTERFACE,
                                    "java/io/ObjectInput",
                                    "readObject",
                                    "()Ljava/lang/Object;");
                mv.visitTypeInsn( CHECKCAST, "java/util/Map" );
                mv.visitFieldInsn( Opcodes.PUTFIELD,
                                   BuildUtils.getInternalType( classDef.getClassName() ),
                                   TraitableBean.TRAITSET_FIELD_NAME,
                                   Type.getDescriptor( Map.class ) );

                if ( classDef.isFullTraiting() ) {
                    mv.visitVarInsn( ALOAD, 0 );
                    mv.visitVarInsn( ALOAD, 1 );
                    mv.visitMethodInsn( INVOKEINTERFACE,
                                        "java/io/ObjectInput",
                                        "readObject",
                                        "()Ljava/lang/Object;");
                    mv.visitTypeInsn( CHECKCAST, Type.getInternalName( TraitFieldTMS.class ) );
                    mv.visitFieldInsn( Opcodes.PUTFIELD,
                                       BuildUtils.getInternalType( classDef.getClassName() ),
                                       TraitableBean.FIELDTMS_FIELD_NAME,
                                       Type.getDescriptor( TraitFieldTMS.class ) );
                }
            }

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

    }

    protected void buildGettersAndSetters(ClassWriter cw, ClassDefinition classDef) {
        // Building methods
        for ( FieldDefinition fieldDef : classDef.getFieldsDefinitions() ) {
            if (! fieldDef.isInherited() || fieldDef.hasOverride()) {
                this.buildGetMethod( cw,
                        classDef,
                        fieldDef );
                this.buildSetMethod( cw,
                        classDef,
                        fieldDef );
            }
        }
    }

    protected void buildEqualityMethods(ClassWriter cw, ClassDefinition classDef) {
        boolean hasKey = false;
        for ( FieldDefinition fld : classDef.getFieldsDefinitions() ) {
            if ( fld.isKey() ) {
                hasKey = true;
                break;
            }
        }

        if (hasKey) {
            this.buildEquals( cw,
                    classDef );
            this.buildHashCode( cw,
                    classDef );
        }
    }

    protected void buildFields(ClassWriter cw, ClassDefinition classDef) {
        // Building fields
        for ( FieldDefinition fieldDef : classDef.getFieldsDefinitions() ) {
            if (! fieldDef.isInherited())
                this.buildField( cw, fieldDef );
        }
    }

    private void implementReactivity(ClassWriter cw, ClassDefinition classDef) {
        final String LEFT_TUPLES_FIELD_NAME = "_lts";
        final String TYPE_NAME = BuildUtils.getInternalType( classDef.getClassName() );

        FieldVisitor fv;
        /*
            private Collection _lts;
         */
        {
            fv = cw.visitField( ACC_PRIVATE, LEFT_TUPLES_FIELD_NAME, "Ljava/util/Collection;", "Ljava/util/Collection;", null );
            fv.visitEnd();
        }

        MethodVisitor mv;
        /*
            public void addLeftTuple(Tuple leftTuple) {
                if (_lts == null) {
                    _lts = new HashSet();
                }
                _lts.add(leftTuple);
            }
         */
        {
            mv = cw.visitMethod( ACC_PUBLIC, "addLeftTuple", "(Lorg/drools/core/spi/Tuple;)V", null, null );
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel( l0 );
            mv.visitLineNumber( 30, l0 );
            mv.visitVarInsn( ALOAD, 0 );
            mv.visitFieldInsn( GETFIELD, TYPE_NAME, LEFT_TUPLES_FIELD_NAME, "Ljava/util/Collection;" );
            Label l1 = new Label();
            mv.visitJumpInsn( IFNONNULL, l1 );
            Label l2 = new Label();
            mv.visitLabel( l2 );
            mv.visitLineNumber( 31, l2 );
            mv.visitVarInsn( ALOAD, 0 );
            mv.visitTypeInsn( NEW, "java/util/HashSet" );
            mv.visitInsn( DUP );
            mv.visitMethodInsn( INVOKESPECIAL, "java/util/HashSet", "", "()V", false );
            mv.visitFieldInsn( PUTFIELD, TYPE_NAME, LEFT_TUPLES_FIELD_NAME, "Ljava/util/Collection;" );
            mv.visitLabel( l1 );
            mv.visitLineNumber( 33, l1 );
            mv.visitFrame( Opcodes.F_SAME, 0, null, 0, null );
            mv.visitVarInsn( ALOAD, 0 );
            mv.visitFieldInsn( GETFIELD, TYPE_NAME, LEFT_TUPLES_FIELD_NAME, "Ljava/util/Collection;" );
            mv.visitVarInsn( ALOAD, 1 );
            mv.visitMethodInsn( INVOKEINTERFACE, "java/util/Collection", "add", "(Ljava/lang/Object;)Z", true );
            mv.visitInsn( POP );
            Label l3 = new Label();
            mv.visitLabel( l3 );
            mv.visitLineNumber( 34, l3 );
            mv.visitInsn( RETURN );
            Label l4 = new Label();
            mv.visitLabel( l4 );
            mv.visitLocalVariable( "this", "L" + TYPE_NAME + ";", null, l0, l4, 0 );
            mv.visitLocalVariable( "leftTuple", "Lorg/drools/core/spi/Tuple;", null, l0, l4, 1 );
            mv.visitMaxs( 3, 2 );
            mv.visitEnd();
        }
        /*
            public Collection getLeftTuples() {             
                return _lts != null ? _lts : Collections.emptyList();
            }                                                      
         */
        {
            mv = cw.visitMethod( ACC_PUBLIC, "getLeftTuples", "()Ljava/util/Collection;", "()Ljava/util/Collection;", null );
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel( l0 );
            mv.visitLineNumber( 37, l0 );
            mv.visitVarInsn( ALOAD, 0 );
            mv.visitFieldInsn( GETFIELD, TYPE_NAME, LEFT_TUPLES_FIELD_NAME, "Ljava/util/Collection;");
            Label l1 = new Label();
            mv.visitJumpInsn( IFNULL, l1 );
            mv.visitVarInsn( ALOAD, 0 );
            mv.visitFieldInsn( GETFIELD, TYPE_NAME, LEFT_TUPLES_FIELD_NAME, "Ljava/util/Collection;" );
            Label l2 = new Label();
            mv.visitJumpInsn( GOTO, l2 );
            mv.visitLabel( l1 );
            mv.visitFrame( Opcodes.F_SAME, 0, null, 0, null );
            mv.visitMethodInsn( INVOKESTATIC, "java/util/Collections", "emptyList", "()Ljava/util/List;", false );
            mv.visitLabel( l2 );
            mv.visitFrame( Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/util/Collection"} );
            mv.visitInsn( ARETURN );
            Label l3 = new Label();
            mv.visitLabel( l3 );
            mv.visitLocalVariable( "this", "L" + TYPE_NAME + ";", null, l0, l3, 0 );
            mv.visitMaxs( 1, 1 );
            mv.visitEnd();
        }
        /*
            protected void notifyModification() {           
                ReactiveObjectUtil.notifyModification(this);
            }                                               
         */
        {
            mv = cw.visitMethod( ACC_PROTECTED, "notifyModification", "()V", null, null );
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel( l0 );
            mv.visitLineNumber( 41, l0 );
            mv.visitVarInsn( ALOAD, 0 );
            mv.visitMethodInsn( INVOKESTATIC, "org/drools/core/phreak/ReactiveObjectUtil", "notifyModification", "(Lorg/drools/core/phreak/ReactiveObject;)V", false );
            Label l1 = new Label();
            mv.visitLabel( l1 );
            mv.visitLineNumber( 42, l1 );
            mv.visitInsn( RETURN );
            Label l2 = new Label();
            mv.visitLabel( l2 );
            mv.visitLocalVariable( "this", "L" + TYPE_NAME + ";", null, l0, l2, 0 );
            mv.visitMaxs( 1, 1 );
            mv.visitEnd();
        }
        /*
            public void removeLeftTuple(Tuple leftTuple) {
                _lts.remove(leftTuple);
            }
         */
        {
            mv = cw.visitMethod( ACC_PUBLIC, "removeLeftTuple", "(Lorg/drools/core/spi/Tuple;)V", null, null );
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel( l0 );
            mv.visitLineNumber( 46, l0 );
            mv.visitVarInsn( ALOAD, 0 );
            mv.visitFieldInsn( GETFIELD, TYPE_NAME, LEFT_TUPLES_FIELD_NAME, "Ljava/util/Collection;" );
            mv.visitVarInsn( ALOAD, 1 );
            mv.visitMethodInsn( INVOKEINTERFACE, "java/util/Collection", "remove", "(Ljava/lang/Object;)Z", true );
            mv.visitInsn( POP );
            Label l1 = new Label();
            mv.visitLabel( l1 );
            mv.visitLineNumber( 47, l1 );
            mv.visitInsn(RETURN);
            Label l2 = new Label();
            mv.visitLabel( l2 );
            mv.visitLocalVariable( "this", "Lorg/drools/core/phreak/AbstractReactiveObject;", null, l0, l2, 0 );
            mv.visitLocalVariable( "leftTuple", "Lorg/drools/core/spi/Tuple;", null, l0, l2, 1 );
            mv.visitMaxs( 2, 2 );
            mv.visitEnd();
        }
    }


    protected void buildConstructors(ClassWriter cw, ClassDefinition classDef) {
        // Building default constructor
        try {
            this.buildDefaultConstructor( cw,
                    classDef );
        } catch (Exception e) {
            e.printStackTrace();
        }

        // Building constructor with all fields
        if (classDef.getFieldsDefinitions().size() > 0 && classDef.getFieldsDefinitions().size() < 120) {
            this.buildConstructorWithFields( cw,
                    classDef,
                    classDef.getFieldsDefinitions() );
        }

        // Building constructor with key fields only
        List keys = new LinkedList();
        for ( FieldDefinition fieldDef : classDef.getFieldsDefinitions() ) {
            if ( fieldDef.isKey() ) {
                keys.add( fieldDef );
            }
        }
        if ( !keys.isEmpty() && keys.size() != classDef.getFieldsDefinitions().size() ) {
            this.buildConstructorWithFields( cw,
                    classDef,
                    keys );
        }
    }


    /**
     * A traitable class is a special class with support for dynamic properties and types.
     *
     * This method builds the trait map, containing the references to the proxies
     * for each trait carried by an object at a given time.
     *
     * @param cw
     * @param classDef
     */
    protected void buildTraitMap(ClassWriter cw, ClassDefinition classDef) {

        FieldVisitor fv = cw.visitField( ACC_PRIVATE,
                TraitableBean.TRAITSET_FIELD_NAME,
                Type.getDescriptor( Map.class ),
                "Ljava/util/Map;",
                null );
        fv.visitEnd();

        MethodVisitor mv;

        mv = cw.visitMethod( ACC_PUBLIC,
                             "_getTraitMap",
                             Type.getMethodDescriptor( Type.getType( Map.class ), new Type[] {} ),
                             "()Ljava/util/Map;",
                             null );
        mv.visitCode();
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitFieldInsn( GETFIELD,
                           BuildUtils.getInternalType( classDef.getName() ),
                           TraitableBean.TRAITSET_FIELD_NAME,
                           Type.getDescriptor( Map.class ) );
        mv.visitInsn(ARETURN);
        mv.visitMaxs( 0, 0 );
        mv.visitEnd();

        mv = cw.visitMethod( ACC_PUBLIC, "_setTraitMap", Type.getMethodDescriptor( Type.getType( void.class ), new Type[] { Type.getType( Map.class ) } ), null, null);
        mv.visitCode();
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitVarInsn( ALOAD, 1 );
        mv.visitFieldInsn( PUTFIELD, BuildUtils.getInternalType( classDef.getName() ), TraitableBean.TRAITSET_FIELD_NAME, Type.getDescriptor( Map.class ));
        mv.visitInsn( RETURN );
        mv.visitMaxs( 0, 0 );
        mv.visitEnd();


        mv = cw.visitMethod( ACC_PUBLIC, "addTrait",
                Type.getMethodDescriptor( Type.getType( void.class ), new Type[] { Type.getType( String.class ), Type.getType( Thing.class ) } ),
                "(Ljava/lang/String;Lorg/drools/core/factmodel/traits/Thing;)V", null );
        mv.visitCode();
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitMethodInsn( INVOKEVIRTUAL,
                BuildUtils.getInternalType( classDef.getName() ),
                "_getTraitMap",
                Type.getMethodDescriptor( Type.getType( Map.class ), new Type[] {} ) );
        mv.visitVarInsn( ALOAD, 1 );
        mv.visitVarInsn( ALOAD, 2 );
        mv.visitMethodInsn( INVOKEINTERFACE,
                Type.getInternalName( Map.class ),
                "put",
                Type.getMethodDescriptor( Type.getType( Object.class ), new Type[] { Type.getType( Object.class ), Type.getType( Object.class ) } ) );
        mv.visitInsn( POP );
        mv.visitInsn( RETURN );
        mv.visitMaxs( 0, 0 );
        mv.visitEnd();


        mv = cw.visitMethod( ACC_PUBLIC,
                "getTrait",
                Type.getMethodDescriptor( Type.getType( Thing.class ), new Type[] { Type.getType( String.class ) } ),
                Type.getMethodDescriptor( Type.getType( Thing.class ), new Type[] { Type.getType( String.class ) } ),
                null );
        mv.visitCode();
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitMethodInsn( INVOKEVIRTUAL,
                BuildUtils.getInternalType( classDef.getName() ),
                "_getTraitMap",
                Type.getMethodDescriptor( Type.getType( Map.class ), new Type[] {} ) );
        mv.visitVarInsn( ALOAD, 1 );
        mv.visitMethodInsn( INVOKEINTERFACE,
                Type.getInternalName( Map.class ),
                "get",
                Type.getMethodDescriptor( Type.getType( Object.class ), new Type[] { Type.getType( Object.class ) } ) );
        mv.visitTypeInsn( CHECKCAST, Type.getInternalName( Thing.class ) );
        mv.visitInsn( ARETURN );
        mv.visitMaxs( 0, 0 );
        mv.visitEnd();


        mv = cw.visitMethod( ACC_PUBLIC,
                "hasTrait",
                Type.getMethodDescriptor( Type.getType( boolean.class ), new Type[] { Type.getType( String.class ) } ),
                null,
                null );
        mv.visitCode();
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitMethodInsn( INVOKEVIRTUAL,
                BuildUtils.getInternalType( classDef.getName() ),
                "_getTraitMap",
                Type.getMethodDescriptor( Type.getType( Map.class ), new Type[] {} ) );
        Label l0 = new Label();
        mv.visitJumpInsn( IFNONNULL, l0 );
        mv.visitInsn( ICONST_0 );
        mv.visitInsn( IRETURN );
        mv.visitLabel( l0 );
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitMethodInsn( INVOKEVIRTUAL,
                BuildUtils.getInternalType( classDef.getName() ),
                "_getTraitMap",
                Type.getMethodDescriptor( Type.getType( Map.class ), new Type[] {} ) );
        mv.visitVarInsn( ALOAD, 1 );
        mv.visitMethodInsn( INVOKEINTERFACE,
                Type.getInternalName( Map.class ),
                "containsKey",
                Type.getMethodDescriptor( Type.getType( boolean.class ), new Type[] { Type.getType( Object.class ) } ) );
        mv.visitInsn( IRETURN );
        mv.visitMaxs( 0, 0 );
        mv.visitEnd();


        mv = cw.visitMethod( ACC_PUBLIC,
                "hasTraits",
                Type.getMethodDescriptor( Type.getType( boolean.class ), new Type[] {} ),
                null,
                null );
        mv.visitCode();
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitFieldInsn( GETFIELD, BuildUtils.getInternalType( classDef.getName() ),TraitableBean.TRAITSET_FIELD_NAME, Type.getDescriptor( Map.class ) );
        Label l5 = new Label();
        mv.visitJumpInsn( IFNULL, l5 );
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitFieldInsn( GETFIELD, BuildUtils.getInternalType( classDef.getName() ), TraitableBean.TRAITSET_FIELD_NAME, Type.getDescriptor( Map.class ) );
        mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Map.class ), "isEmpty", Type.getMethodDescriptor( Type.BOOLEAN_TYPE, new Type[] {} ) );
        mv.visitJumpInsn( IFNE, l5 );
        mv.visitInsn( ICONST_1 );
        Label l4 = new Label();
        mv.visitJumpInsn( GOTO, l4 );
        mv.visitLabel( l5 );
        mv.visitInsn( ICONST_0 );
        mv.visitLabel( l4 );
        mv.visitInsn( IRETURN );
        mv.visitMaxs( 0, 0 );
        mv.visitEnd();


        mv = cw.visitMethod( ACC_PUBLIC, "removeTrait",
                Type.getMethodDescriptor( Type.getType( Collection.class ), new Type[] { Type.getType( String.class ) } ),
                Type.getMethodDescriptor( Type.getType( Collection.class ), new Type[] { Type.getType( String.class ) } ),
                null );
        mv.visitCode();
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitMethodInsn( INVOKEVIRTUAL, BuildUtils.getInternalType( classDef.getName() ), "_getTraitMap", Type.getMethodDescriptor( Type.getType( Map.class ), new Type[] {} ) );
        mv.visitTypeInsn( CHECKCAST, Type.getInternalName( TraitTypeMap.class ) );
        mv.visitVarInsn(ALOAD, 1);
        mv.visitMethodInsn( INVOKEVIRTUAL, Type.getInternalName( TraitTypeMap.class ), "removeCascade",
                Type.getMethodDescriptor( Type.getType( Collection.class ), new Type[] { Type.getType( String.class )} ) );
        mv.visitInsn( ARETURN );
        mv.visitMaxs( 0, 0 );
        mv.visitEnd();

        mv = cw.visitMethod( ACC_PUBLIC, "removeTrait",
                Type.getMethodDescriptor( Type.getType( Collection.class ), new Type[] { Type.getType( BitSet.class ) } ),
                Type.getMethodDescriptor( Type.getType( Collection.class ), new Type[] { Type.getType( BitSet.class ) } ),
                null );
        mv.visitCode();
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitMethodInsn( INVOKEVIRTUAL, BuildUtils.getInternalType( classDef.getName() ), "_getTraitMap", Type.getMethodDescriptor( Type.getType( Map.class ), new Type[] {} ) );
        mv.visitTypeInsn( CHECKCAST, Type.getInternalName( TraitTypeMap.class ) );
        mv.visitVarInsn( ALOAD, 1 );
        mv.visitMethodInsn( INVOKEVIRTUAL, Type.getInternalName( TraitTypeMap.class ), "removeCascade",
                Type.getMethodDescriptor( Type.getType( Collection.class ), new Type[] { Type.getType( BitSet.class )} ) );
        mv.visitInsn( ARETURN );
        mv.visitMaxs( 0, 0 );
        mv.visitEnd();


        mv = cw.visitMethod( ACC_PUBLIC,
                "getTraits",
                Type.getMethodDescriptor( Type.getType( Collection.class ), new Type[] { } ),
                "()Ljava/util/Collection;",
                null );
        mv.visitCode();
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitMethodInsn( INVOKEVIRTUAL,
                BuildUtils.getInternalType( classDef.getName() ),
                "_getTraitMap",
                Type.getMethodDescriptor( Type.getType( Map.class ), new Type[] {} ) );
        mv.visitMethodInsn( INVOKEINTERFACE,
                Type.getInternalName( Map.class ),
                "keySet",
                Type.getMethodDescriptor( Type.getType( Set.class ), new Type[] {} ) );
        mv.visitInsn( ARETURN );
        mv.visitMaxs( 0, 0 );
        mv.visitEnd();


        mv = cw.visitMethod( ACC_PUBLIC,
                "_setBottomTypeCode",
                Type.getMethodDescriptor( Type.getType( void.class ), new Type[] { Type.getType( BitSet.class ) } ),
                null, null );
        mv.visitCode();
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitFieldInsn( GETFIELD, BuildUtils.getInternalType( classDef.getName() ), TraitableBean.TRAITSET_FIELD_NAME , Type.getDescriptor( Map.class ) );
        mv.visitTypeInsn( CHECKCAST, Type.getInternalName( TraitTypeMap.class ) );
        mv.visitVarInsn( ALOAD, 1 );
        mv.visitMethodInsn( INVOKEVIRTUAL,
                Type.getInternalName( TraitTypeMap.class ),
                "setBottomCode",
                Type.getMethodDescriptor( Type.getType( void.class ), new Type[] { Type.getType( BitSet.class ) } ) );
        mv.visitInsn( RETURN );
        mv.visitMaxs( 0, 0 );
        mv.visitEnd();

        mv = cw.visitMethod( ACC_PUBLIC,
                "getMostSpecificTraits",
                Type.getMethodDescriptor( Type.getType( Collection.class ), new Type[] { } ) ,
                "()Ljava/util/Collection;",
                null );
        mv.visitCode();

        mv.visitVarInsn( ALOAD, 0 );
        mv.visitFieldInsn( GETFIELD, BuildUtils.getInternalType( classDef.getName() ),
                TraitableBean.TRAITSET_FIELD_NAME ,
                Type.getDescriptor( Map.class ) );


        Label l99 = new Label();
        mv.visitJumpInsn( IFNULL, l99 );
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitFieldInsn( GETFIELD, BuildUtils.getInternalType( classDef.getName() ),
                           TraitableBean.TRAITSET_FIELD_NAME ,
                           Type.getDescriptor( Map.class ) );
        mv.visitTypeInsn( CHECKCAST, Type.getInternalName( TraitTypeMap.class ) );
        mv.visitMethodInsn( INVOKEVIRTUAL,
                Type.getInternalName( TraitTypeMap.class ),
                "getMostSpecificTraits",
                Type.getMethodDescriptor( Type.getType( Collection.class ), new Type[] { } )  );
        mv.visitInsn( ARETURN );
        mv.visitLabel( l99 );
        mv.visitMethodInsn( INVOKESTATIC,
                            Type.getInternalName( Collections.class ),
                            "emptySet",
                            Type.getMethodDescriptor( Type.getType( Set.class ), new Type[] { } )  );
        mv.visitMethodInsn( INVOKESTATIC,
                            Type.getInternalName( Collections.class ),
                            "unmodifiableCollection",
                            Type.getMethodDescriptor( Type.getType( Collection.class ), new Type[] { Type.getType( Collection.class ) } )  );
        mv.visitInsn( ARETURN );
        mv.visitMaxs( 0, 0 );
        mv.visitEnd();

        mv = cw.visitMethod( ACC_PUBLIC, "getCurrentTypeCode", Type.getMethodDescriptor( Type.getType( BitSet.class ), new Type[] { } ) , null, null );
        mv.visitCode();
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitFieldInsn( GETFIELD,
                           BuildUtils.getInternalType( classDef.getName() ),
                           TraitableBean.TRAITSET_FIELD_NAME,
                           Type.getDescriptor( Map.class ) );
        Label l3 = new Label();
        mv.visitJumpInsn( IFNONNULL, l3 );
        mv.visitInsn( ACONST_NULL );
        mv.visitInsn( ARETURN );
        mv.visitLabel( l3 );
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitFieldInsn( GETFIELD,
                           BuildUtils.getInternalType( classDef.getName() ),
                           TraitableBean.TRAITSET_FIELD_NAME,
                           Type.getDescriptor( Map.class ) );
        mv.visitTypeInsn( CHECKCAST, Type.getInternalName( TraitTypeMap.class ) );
        mv.visitMethodInsn( INVOKEVIRTUAL,
                            Type.getInternalName( TraitTypeMap.class ),
                            "getCurrentTypeCode",
                            Type.getMethodDescriptor( Type.getType( BitSet.class ), new Type[] { } ) );
        mv.visitInsn( ARETURN );
        mv.visitMaxs( 0, 0 );
        mv.visitEnd();


    }


    /**
     * A traitable class is a special class with support for dynamic properties and types.
     *
     * This method builds the property map, containing the key/values pairs to implement
     * any property defined in a trait interface but not supported by the traited class
     * fields.
     *
     * @param cw
     * @param def
     */
    protected void buildDynamicPropertyMap( ClassWriter cw, ClassDefinition def ) {

        FieldVisitor fv = cw.visitField( Opcodes.ACC_PRIVATE,
                TraitableBean.MAP_FIELD_NAME,
                Type.getDescriptor( Map.class ) ,
                "Ljava/util/Map;",
                null);
        fv.visitEnd();

        MethodVisitor mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
                "_getDynamicProperties",
                Type.getMethodDescriptor( Type.getType( Map.class ), new Type[] {} ),
                "()Ljava/util/Map;",
                null);
        mv.visitCode();
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitFieldInsn( GETFIELD, BuildUtils.getInternalType(def.getName()), TraitableBean.MAP_FIELD_NAME, Type.getDescriptor( Map.class ) );
        mv.visitInsn( ARETURN );
        mv.visitMaxs( 0, 0 );
        mv.visitEnd();



        mv = cw.visitMethod( ACC_PUBLIC,
                "_setDynamicProperties",
                Type.getMethodDescriptor( Type.getType( void.class ), new Type[] { Type.getType( Map.class ) } ),
                "(Ljava/util/Map;)V",
                null);
        mv.visitCode();
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitVarInsn( ALOAD, 1 );
        mv.visitFieldInsn ( PUTFIELD, BuildUtils.getInternalType( def.getName() ), TraitableBean.MAP_FIELD_NAME, Type.getDescriptor( Map.class ) );
        mv.visitInsn( RETURN) ;
        mv.visitMaxs( 0, 0 );
        mv.visitEnd();

    }

    /**
     * A traitable class is a special class with support for dynamic properties and types.
     *
     * A traitable class in logical mode provides additional control over the values
     * and type(s) of its fields.
     *
     * @param cw
     * @param def
     */
    protected void buildFieldTMS( ClassWriter cw, ClassDefinition def ) {

        FieldVisitor fv = cw.visitField( Opcodes.ACC_PRIVATE,
                                         TraitableBean.FIELDTMS_FIELD_NAME,
                                         Type.getDescriptor( TraitFieldTMS.class ),
                                         null,
                                         null );
        fv.visitEnd();

        MethodVisitor mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
                "_getFieldTMS",
                Type.getMethodDescriptor( Type.getType( TraitFieldTMS.class ), new Type[] {} ),
                null,
                null);
        mv.visitCode();
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitFieldInsn( GETFIELD, BuildUtils.getInternalType( def.getName() ), TraitableBean.FIELDTMS_FIELD_NAME, Type.getDescriptor( TraitFieldTMS.class ) );
        mv.visitInsn( ARETURN );
        mv.visitMaxs( 0, 0 );
        mv.visitEnd();

        mv = cw.visitMethod( ACC_PUBLIC,
                "_setFieldTMS",
                Type.getMethodDescriptor( Type.VOID_TYPE, new Type[] { Type.getType( TraitFieldTMS.class ) } ),
                null,
                null);
        mv.visitCode();
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitVarInsn( ALOAD, 1 );
        mv.visitFieldInsn ( PUTFIELD, BuildUtils.getInternalType( def.getName() ), TraitableBean.FIELDTMS_FIELD_NAME, Type.getDescriptor( TraitFieldTMS.class ) );
        mv.visitInsn( RETURN) ;
        mv.visitMaxs( 0, 0 );
        mv.visitEnd();

    }

    /**
     * Defines the class header for the given class definition
     */
    protected ClassWriter buildClassHeader(ClassLoader classLoader,
                                           ClassDefinition classDef) {
        boolean reactive = classDef.isReactive();

        String[] original = classDef.getInterfaces();
        int interfacesNr = original.length + (reactive ? 2 : 1);
        String[] interfaces = new String[interfacesNr];
        for ( int i = 0; i < original.length; i++ ) {
            interfaces[i] = BuildUtils.getInternalType( original[i] );
        }
        interfaces[original.length] = BuildUtils.getInternalType( GeneratedFact.class.getName() );
        if (reactive) {
            interfaces[original.length+1] = BuildUtils.getInternalType( ReactiveObject.class.getName() );
        }

        int classModifiers = Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER;
        if ( classDef.isAbstrakt() ) {
            classModifiers += Opcodes.ACC_ABSTRACT;
        }

        ClassWriter cw = createClassWriter( classLoader,
                                            classModifiers,
                                            BuildUtils.getInternalType( classDef.getClassName() ),
                                            null,
                                            BuildUtils.getInternalType( classDef.getSuperClass() ),
                                            interfaces );

        buildClassAnnotations(classDef, cw);

        cw.visitSource( classDef.getClassName() + ".java",
                        null );

        return cw;
    }



    /**
     * Creates the field defined by the given FieldDefinition
     *
     * @param cw
     * @param fieldDef
     */
    protected void buildField( ClassVisitor cw,
                               FieldDefinition fieldDef) {
        FieldVisitor fv = cw.visitField( Opcodes.ACC_PROTECTED,
                                         fieldDef.getName(),
                                         BuildUtils.getTypeDescriptor( fieldDef.getTypeName() ),
                                         null,
                                         null );


        buildFieldAnnotations( fieldDef, fv );

        fv.visitEnd();
    }



    /**
     * Creates a default constructor for the class
     *
     * @param cw
     */
    protected void buildDefaultConstructor(ClassVisitor cw,
                                           ClassDefinition classDef) {


        MethodVisitor mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
                "",
                Type.getMethodDescriptor( Type.VOID_TYPE,
                        new Type[]{} ),
                null,
                null );
        mv.visitCode();

        Label l0 = null;
        if ( this.debug ) {
            l0 = new Label();
            mv.visitLabel( l0 );
        }

        boolean hasObjects = defaultConstructorStart( mv, classDef );

        mv.visitInsn(Opcodes.RETURN);
        Label l1 = null;
        if ( this.debug ) {
            l1 = new Label();
            mv.visitLabel( l1 );
            mv.visitLocalVariable( "this",
                                   BuildUtils.getTypeDescriptor( classDef.getClassName() ),
                                   null,
                                   l0,
                                   l1,
                                   0 );
        }
        mv.visitMaxs( 0, 0 );
        mv.visitEnd();

    }


    protected boolean defaultConstructorStart( MethodVisitor mv, ClassDefinition classDef ) {
        // Building default constructor

        mv.visitVarInsn( Opcodes.ALOAD,
                0 );

        String sup = "";
        try {
            sup = Type.getInternalName(Class.forName(classDef.getSuperClass()));
        } catch (ClassNotFoundException e) {
            sup = BuildUtils.getInternalType( classDef.getSuperClass() );
        }
        mv.visitMethodInsn( Opcodes.INVOKESPECIAL,
                sup,
                "",
                Type.getMethodDescriptor( Type.VOID_TYPE,
                        new Type[]{} ) );

        boolean hasObjects = false;
        for (FieldDefinition field : classDef.getFieldsDefinitions()) {

            hasObjects = hasObjects || initFieldWithDefaultValue( mv, classDef, field );
        }


        if ( classDef.isTraitable() ) {
            initializeDynamicTypeStructures( mv, classDef );
        }

        return hasObjects;
    }


    protected boolean initFieldWithDefaultValue( MethodVisitor mv, ClassDefinition classDef, FieldDefinition field ) {
        if ( field.getInitExpr() == null && field.isInherited() ) {
            return false;
        }
        // get simple init expression value
        Object val = BuildUtils.getDefaultValue(field);
        boolean hasObjects = false;

        if (val != null) {
            // there's a simple init expression
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            if ( BuildUtils.isPrimitive( field.getTypeName() )
                    || BuildUtils.isBoxed( field.getTypeName() )
                    || String.class.getName().equals( field.getTypeName() ) ) {
                mv.visitLdcInsn(val);
                if ( BuildUtils.isBoxed(field.getTypeName()) ) {
                    mv.visitMethodInsn(Opcodes.INVOKESTATIC,
                            BuildUtils.getInternalType(field.getTypeName()),
                            "valueOf",
                            "("+BuildUtils.unBox(field.getTypeName())+")"+BuildUtils.getTypeDescriptor(field.getTypeName()));
                }
            } else {
                hasObjects = true;
                String type = BuildUtils.getInternalType( val.getClass().getName() );
                mv.visitTypeInsn( NEW, type );
                mv.visitInsn(DUP);
                mv.visitMethodInsn( INVOKESPECIAL,
                        type,
                        "",
                        "()V");
            }
        } else {
            // there's a complex init expression
            if ( field.getInitExpr() != null ) {
                mv.visitVarInsn( ALOAD, 0 );
                mv.visitLdcInsn( field.getInitExpr() );
                mv.visitMethodInsn( INVOKESTATIC,
                        "org/mvel2/MVEL",
                        "eval",
                        "(Ljava/lang/String;)Ljava/lang/Object;");
                mv.visitTypeInsn( CHECKCAST, BuildUtils.getInternalType( field.getTypeName() ) );
                val = field.getInitExpr();
            }
        }


        if ( val != null ) {
            if (! field.isInherited()) {
                mv.visitFieldInsn( Opcodes.PUTFIELD,
                        BuildUtils.getInternalType( classDef.getClassName() ),
                        field.getName(),
                        BuildUtils.getTypeDescriptor( field.getTypeName() ) );
            } else {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
                        BuildUtils.getInternalType( classDef.getClassName() ),
                        field.getWriteMethod(),
                        Type.getMethodDescriptor(Type.VOID_TYPE,
                                new Type[]{Type.getType(BuildUtils.getTypeDescriptor(field.getTypeName()))}
                        ));
            }

        }

        return hasObjects;
    }


    /**
     * Initializes the trait map and dynamic property map to empty values
     * @param mv
     * @param classDef
     */
    protected void initializeDynamicTypeStructures( MethodVisitor mv, ClassDefinition classDef) {
        if ( classDef.isFullTraiting() ) {

            mv.visitVarInsn( ALOAD, 0 );
            mv.visitTypeInsn( NEW, Type.getInternalName( TraitFieldTMSImpl.class ) );
            mv.visitInsn( DUP );
            mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( TraitFieldTMSImpl.class ), "", "()V" );
            mv.visitFieldInsn( PUTFIELD, BuildUtils.getInternalType( classDef.getClassName() ), TraitableBean.FIELDTMS_FIELD_NAME, Type.getDescriptor( TraitFieldTMS.class ) );

            for ( FactField hardField : classDef.getFields() ) {
                FieldDefinition fld = (FieldDefinition) hardField;
                mv.visitVarInsn( ALOAD, 0 );
                mv.visitFieldInsn( GETFIELD, BuildUtils.getInternalType( classDef.getClassName() ), TraitableBean.FIELDTMS_FIELD_NAME, Type.getDescriptor( TraitFieldTMS.class ) );

                mv.visitLdcInsn( Type.getType( BuildUtils.getTypeDescriptor( classDef.getClassName() ) ) );

                mv.visitLdcInsn( fld.resolveAlias() );

                if ( BuildUtils.isPrimitive( fld.getTypeName() ) ) {
//                    mv.visitFieldInsn( GETSTATIC, BuildUtils.getInternalType( BuildUtils.box( fld.getTypeName() ) ), "TYPE", Type.getDescriptor( Class.class ) );
                    mv.visitLdcInsn( Type.getType( BuildUtils.getTypeDescriptor( BuildUtils.box( fld.getTypeName() ) ) ) );
                } else {
                    mv.visitLdcInsn( Type.getType( BuildUtils.getTypeDescriptor( fld.getTypeName() ) ) );
                }

                mv.visitVarInsn( ALOAD, 0 );
                mv.visitMethodInsn( INVOKEVIRTUAL, BuildUtils.getInternalType( classDef.getClassName() ), BuildUtils.getterName( fld.getName(), fld.getTypeName() ), "()" + BuildUtils.getTypeDescriptor( fld.getTypeName() ) );
                if ( BuildUtils.isPrimitive( fld.getTypeName() ) ) {
                    mv.visitMethodInsn( INVOKESTATIC, BuildUtils.getInternalType( BuildUtils.box( fld.getTypeName() ) ), "valueOf", "(" + BuildUtils.getTypeDescriptor( fld.getTypeName() ) + ")" + BuildUtils.getTypeDescriptor( BuildUtils.box( fld.getTypeName() ) ) );
                }

                if ( fld.getInitExpr() != null ) {
                    mv.visitLdcInsn( fld.getInitExpr() );
                } else {
                    mv.visitInsn( ACONST_NULL );
                }

                mv.visitMethodInsn( INVOKEINTERFACE,
                                    Type.getInternalName( TraitFieldTMS.class ),
                                    "registerField",
                                    Type.getMethodDescriptor( Type.VOID_TYPE, new Type[] { Type.getType( Class.class ), Type.getType( String.class ), Type.getType( Class.class ), Type.getType( Object.class ), Type.getType( String.class ) } ) );
            }
        }
    }

    /**
     * Creates a constructor that takes and assigns values to all
     * fields in the order they are declared.
     *
     * @param cw
     * @param classDef
     */
    protected void buildConstructorWithFields(ClassVisitor cw,
                                              ClassDefinition classDef,
                                              Collection fieldDefs) {


        Type[] params = new Type[fieldDefs.size()];
        int index = 0;
        for ( FieldDefinition field : fieldDefs ) {
            params[index++] = Type.getType( BuildUtils.getTypeDescriptor( field.getTypeName() ) );
        }

        MethodVisitor mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
                "",
                Type.getMethodDescriptor( Type.VOID_TYPE,
                        params ),
                null,
                null );
        mv.visitCode();
        Label l0 = null;
        if ( this.debug ) {
            l0 = new Label();
            mv.visitLabel( l0 );
        }

        fieldConstructorStart( mv, classDef, fieldDefs );

        mv.visitInsn( Opcodes.RETURN );
        Label l1 = null;
        if ( this.debug ) {
            l1 = new Label();
            mv.visitLabel( l1 );
            mv.visitLocalVariable( "this",
                    BuildUtils.getTypeDescriptor( classDef.getClassName() ),
                    null,
                    l0,
                    l1,
                    0 );
            for ( FieldDefinition field : classDef.getFieldsDefinitions() ) {
                Label l11 = new Label();
                mv.visitLabel( l11 );
                mv.visitLocalVariable( field.getName(),
                        BuildUtils.getTypeDescriptor( field.getTypeName() ),
                        null,
                        l0,
                        l1,
                        0 );
            }
        }
        mv.visitMaxs( 0,
                0 );
        mv.visitEnd();

    }

    protected void fieldConstructorStart(MethodVisitor mv, ClassDefinition classDef, Collection fieldDefs) {
        mv.visitVarInsn( Opcodes.ALOAD,
                0 );

        String sup = "";
        try {
            sup = Type.getInternalName(Class.forName(classDef.getSuperClass()));
        } catch (ClassNotFoundException e) {
            sup = BuildUtils.getInternalType( classDef.getSuperClass() );
        }

        mv.visitMethodInsn( Opcodes.INVOKESPECIAL,
                sup,
                "",
                Type.getMethodDescriptor( Type.VOID_TYPE,
                        new Type[]{} ) );

        int index = 1; // local vars start at 1, as 0 is "this"
        for ( FieldDefinition field : fieldDefs ) {
            if ( this.debug ) {
                Label l11 = new Label();
                mv.visitLabel( l11 );
            }
            mv.visitVarInsn( Opcodes.ALOAD,
                    0 );
            mv.visitVarInsn( Type.getType( BuildUtils.getTypeDescriptor( field.getTypeName() ) ).getOpcode( Opcodes.ILOAD ),
                    index++ );
            if ( field.getTypeName().equals( "long" ) || field.getTypeName().equals( "double" ) ) {
                // long and double variables use 2 words on the variables table
                index++;
            }

            if (! field.isInherited()) {
                mv.visitFieldInsn( Opcodes.PUTFIELD,
                        BuildUtils.getInternalType( classDef.getClassName() ),
                        field.getName(),
                        BuildUtils.getTypeDescriptor( field.getTypeName() ) );
            } else {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
                        BuildUtils.getInternalType(classDef.getClassName()),
                        field.getWriteMethod(),
                        Type.getMethodDescriptor(Type.VOID_TYPE,
                                new Type[]{Type.getType(BuildUtils.getTypeDescriptor(field.getTypeName()))}
                        ));
            }

        }



        for ( FieldDefinition field : classDef.getFieldsDefinitions() ) {
            if ( ! fieldDefs.contains( field ) && field.getInitExpr() != null && ! "".equals( field.getInitExpr().trim() ) ) {

                initFieldWithDefaultValue( mv, classDef, field );

            }
        }

        if ( classDef.isTraitable() ) {
            initializeDynamicTypeStructures( mv, classDef );
        }

    }




    /**
     * Creates the set method for the given field definition
     *
     * @param cw
     * @param classDef
     * @param fieldDef
     */
    protected void buildSetMethod(ClassVisitor cw,
                                  ClassDefinition classDef,
                                  FieldDefinition fieldDef) {
        MethodVisitor mv;
        // set method
        {
            mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
                    fieldDef.getWriteMethod(),
                    Type.getMethodDescriptor( Type.VOID_TYPE,
                            new Type[]{Type.getType( BuildUtils.getTypeDescriptor( fieldDef.getTypeName() ) )} ),
                    null,
                    null );
            mv.visitCode();
            Label l0 = null;
            if ( this.debug ) {
                l0 = new Label();
                mv.visitLabel( l0 );
            }
            mv.visitVarInsn( Opcodes.ALOAD, 0 );

            if ( classDef.isTraitable() && classDef.isFullTraiting() ) {
                updateTraitableField( mv, classDef, fieldDef );
            } else {
                mv.visitVarInsn( Type.getType( BuildUtils.getTypeDescriptor( fieldDef.getTypeName() ) ).getOpcode( Opcodes.ILOAD ), 1 );
            }

            if ( ! fieldDef.hasOverride() ) {
                mv.visitFieldInsn( Opcodes.PUTFIELD,
                                   BuildUtils.getInternalType( classDef.getClassName() ),
                                   fieldDef.getName(),
                                   BuildUtils.getTypeDescriptor( fieldDef.getTypeName() ) );
            } else {
                mv.visitMethodInsn( INVOKESPECIAL,
                                    BuildUtils.getInternalType( classDef.getSuperClass() ),
                                    BuildUtils.setterName( fieldDef.getName(), fieldDef.getOverriding() ),
                                    Type.getMethodDescriptor( Type.VOID_TYPE,
                                                              new Type[]{Type.getType( BuildUtils.getTypeDescriptor( fieldDef.getOverriding()) )} ),
                                    false );
            }

            if (classDef.isReactive()) {
                mv.visitVarInsn( ALOAD, 0 );
                mv.visitMethodInsn( INVOKEVIRTUAL, BuildUtils.getInternalType( classDef.getClassName() ), "notifyModification", "()V", false );
            }

            mv.visitInsn( Opcodes.RETURN );
            Label l1 = null;
            if ( this.debug ) {
                l1 = new Label();
                mv.visitLabel( l1 );
                mv.visitLocalVariable( "this",
                        BuildUtils.getTypeDescriptor( classDef.getClassName() ),
                        null,
                        l0,
                        l1,
                        0 );
            }
            mv.visitMaxs( 0, 0 );
            mv.visitEnd();
        }
    }

    /**
     * Creates the get method for the given field definition
     *
     * @param cw
     * @param classDef
     * @param fieldDef
     */
    protected void buildGetMethod(ClassVisitor cw,
                                  ClassDefinition classDef,
                                  FieldDefinition fieldDef) {
        MethodVisitor mv;
        // Get method
        {
            mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
                    fieldDef.getReadMethod(),
                    Type.getMethodDescriptor( Type.getType( BuildUtils.getTypeDescriptor( fieldDef.getTypeName() ) ),
                            new Type[]{} ),
                    null,
                    null );
            mv.visitCode();
            Label l0 = null;
            if ( this.debug ) {
                l0 = new Label();
                mv.visitLabel( l0 );
            }
            mv.visitVarInsn( Opcodes.ALOAD,
                    0 );
            if ( ! fieldDef.hasOverride() ) {
                mv.visitFieldInsn( Opcodes.GETFIELD,
                                   BuildUtils.getInternalType( classDef.getClassName() ),
                                   fieldDef.getName(),
                                   BuildUtils.getTypeDescriptor( fieldDef.getTypeName() ) );
                mv.visitInsn( Type.getType( BuildUtils.getTypeDescriptor( fieldDef.getTypeName() ) ).getOpcode( Opcodes.IRETURN ) );
            } else {
                mv.visitMethodInsn( INVOKESPECIAL,
                                    BuildUtils.getInternalType( classDef.getSuperClass() ),
                                    BuildUtils.getterName( fieldDef.getName(), fieldDef.getOverriding() ),
                                    Type.getMethodDescriptor( Type.getType( BuildUtils.getTypeDescriptor( fieldDef.getOverriding() ) ), new Type[]{} ),
                                    false );
                mv.visitTypeInsn( CHECKCAST, BuildUtils.getInternalType( fieldDef.getTypeName() ) );
                mv.visitInsn( BuildUtils.returnType( fieldDef.getTypeName() ) );
            }

            Label l1 = null;
            if ( this.debug ) {
                l1 = new Label();
                mv.visitLabel( l1 );
                mv.visitLocalVariable( "this",
                        BuildUtils.getTypeDescriptor( classDef.getClassName() ),
                        null,
                        l0,
                        l1,
                        0 );
            }
            mv.visitMaxs( 0,
                    0 );
            mv.visitEnd();
        }
    }

    protected void buildEquals(ClassVisitor cw,
                               ClassDefinition classDef) {
        MethodVisitor mv;
        // Building equals method
        {
            mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
                    "equals",
                    "(Ljava/lang/Object;)Z",
                    null,
                    null );
            mv.visitCode();
            Label l0 = null;
            if ( this.debug ) {
                l0 = new Label();
                mv.visitLabel( l0 );
            }

            // if ( this == obj ) return true;
            mv.visitVarInsn( Opcodes.ALOAD,
                    0 );
            mv.visitVarInsn( Opcodes.ALOAD,
                    1 );
            Label l1 = new Label();
            mv.visitJumpInsn( Opcodes.IF_ACMPNE,
                    l1 );
            mv.visitInsn( Opcodes.ICONST_1 );
            mv.visitInsn( Opcodes.IRETURN );

            // if ( obj == null ) return false;
            mv.visitLabel( l1 );
            mv.visitVarInsn( Opcodes.ALOAD,
                    1 );
            Label l2 = new Label();
            mv.visitJumpInsn( Opcodes.IFNONNULL,
                    l2 );
            mv.visitInsn( Opcodes.ICONST_0 );
            mv.visitInsn( Opcodes.IRETURN );

            // if ( getClass() != obj.getClass() ) return false;
            mv.visitLabel( l2 );
            mv.visitVarInsn( Opcodes.ALOAD,
                    0 );
            mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
                    Type.getInternalName( Object.class ),
                    "getClass",
                    Type.getMethodDescriptor( Type.getType( Class.class ),
                            new Type[]{} ) );
            mv.visitVarInsn( Opcodes.ALOAD,
                    1 );
            mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
                    Type.getInternalName( Object.class ),
                    "getClass",
                    Type.getMethodDescriptor( Type.getType( Class.class ),
                            new Type[]{} ) );
            Label l3 = new Label();
            mv.visitJumpInsn( Opcodes.IF_ACMPEQ,
                    l3 );
            mv.visitInsn( Opcodes.ICONST_0 );
            mv.visitInsn( Opcodes.IRETURN );

            // final  other = () obj;
            mv.visitLabel( l3 );
            mv.visitVarInsn( Opcodes.ALOAD,
                    1 );
            mv.visitTypeInsn( Opcodes.CHECKCAST,
                    BuildUtils.getInternalType( classDef.getClassName() ) );
            mv.visitVarInsn( Opcodes.ASTORE,
                    2 );

            // for each key field
            int count = 0;
            for ( FieldDefinition field : classDef.getFieldsDefinitions() ) {
                if ( field.isKey() ) {
                    count++;

                    Label goNext = new Label();

                    if ( BuildUtils.isPrimitive(field.getTypeName()) ) {
                        // if attr is primitive

                        // if ( this. != other. ) return false;
                        mv.visitVarInsn( Opcodes.ALOAD,
                                0 );


                        visitFieldOrGetter(mv, classDef, field);

                        mv.visitVarInsn(Opcodes.ALOAD,
                                2);

                        visitFieldOrGetter(mv, classDef, field);

                        if ( field.getTypeName().equals( "long" ) ) {
                            mv.visitInsn( Opcodes.LCMP );
                            mv.visitJumpInsn( Opcodes.IFEQ,
                                    goNext );
                        } else if ( field.getTypeName().equals( "double" ) ) {
                            mv.visitInsn( Opcodes.DCMPL );
                            mv.visitJumpInsn( Opcodes.IFEQ,
                                    goNext );
                        } else if ( field.getTypeName().equals( "float" ) ) {
                            mv.visitInsn( Opcodes.FCMPL );
                            mv.visitJumpInsn( Opcodes.IFEQ,
                                    goNext );
                        } else {
                            // boolean, byte, char, short, int
                            mv.visitJumpInsn( Opcodes.IF_ICMPEQ,
                                    goNext );
                        }
                        mv.visitInsn( Opcodes.ICONST_0 );
                        mv.visitInsn( Opcodes.IRETURN );
                    } else {
                        // if attr is not a primitive

                        // if ( this. == null && other. != null ||
                        //      this. != null && ! this..equals( other. ) ) return false;
                        mv.visitVarInsn( Opcodes.ALOAD,
                                0 );

                        visitFieldOrGetter(mv, classDef, field);

                        Label secondIfPart = new Label();
                        mv.visitJumpInsn( Opcodes.IFNONNULL,
                                secondIfPart );

                        // if ( other.objAttr != null ) return false;
                        mv.visitVarInsn( Opcodes.ALOAD,
                                2 );

                        visitFieldOrGetter(mv, classDef, field);

                        Label returnFalse = new Label();
                        mv.visitJumpInsn( Opcodes.IFNONNULL,
                                returnFalse );

                        mv.visitLabel( secondIfPart );
                        mv.visitVarInsn( Opcodes.ALOAD,
                                0 );

                        visitFieldOrGetter(mv, classDef, field);

                        mv.visitJumpInsn( Opcodes.IFNULL,
                                goNext );

                        mv.visitVarInsn( Opcodes.ALOAD,
                                0 );

                        visitFieldOrGetter(mv, classDef, field);

                        mv.visitVarInsn( Opcodes.ALOAD,
                                2 );

                        visitFieldOrGetter(mv, classDef, field);

                        if ( ! BuildUtils.isArray( field.getTypeName() ) ) {
                            mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
                                    "java/lang/Object",
                                    "equals",
                                    "(Ljava/lang/Object;)Z" );
                        } else {
                            mv.visitMethodInsn( Opcodes.INVOKESTATIC,
                                    "java/util/Arrays",
                                    "equals",
                                    "(" +
                                            BuildUtils.arrayType( field.getTypeName() ) +
                                            BuildUtils.arrayType( field.getTypeName() ) +
                                    ")Z" );
                        }
                        mv.visitJumpInsn( Opcodes.IFNE,
                                goNext );

                        mv.visitLabel( returnFalse );
                        mv.visitInsn( Opcodes.ICONST_0 );
                        mv.visitInsn( Opcodes.IRETURN );
                    }
                    mv.visitLabel( goNext );
                }
            }
            if ( count > 0 ) {
                mv.visitInsn( Opcodes.ICONST_1 );
            } else {
                mv.visitInsn( Opcodes.ICONST_0 );
            }
            mv.visitInsn( Opcodes.IRETURN );
            Label lastLabel = null;
            if ( this.debug ) {
                lastLabel = new Label();
                mv.visitLabel( lastLabel );
                mv.visitLocalVariable( "this",
                        BuildUtils.getTypeDescriptor( classDef.getClassName() ),
                        null,
                        l0,
                        lastLabel,
                        0 );
                mv.visitLocalVariable( "obj",
                        Type.getDescriptor( Object.class ),
                        null,
                        l0,
                        lastLabel,
                        1 );
                mv.visitLocalVariable( "other",
                        BuildUtils.getTypeDescriptor( classDef.getClassName() ),
                        null,
                        l0,
                        lastLabel,
                        2 );
            }
            mv.visitMaxs( 0,
                    0 );
            mv.visitEnd();
        }
    }


    protected void buildSystemHashCode(ClassWriter cw) {
        {
            MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "hashCode", "()I", null, null);
            mv.visitCode();
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "identityHashCode", "(Ljava/lang/Object;)I");
            mv.visitInsn(IRETURN);
            mv.visitMaxs( 0, 0 );
            mv.visitEnd();
        }
    }


    protected void buildHashCode(ClassVisitor cw,
                                 ClassDefinition classDef) {

        MethodVisitor mv;
        // Building hashCode() method
        {
            mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
                    "hashCode",
                    "()I",
                    null,
                    null );
            mv.visitCode();
            Label l0 = null;
            if ( this.debug ) {
                l0 = new Label();
                mv.visitLabel( l0 );
            }

            // int result = 1;
            mv.visitInsn( Opcodes.ICONST_1 );
            mv.visitVarInsn( Opcodes.ISTORE,
                             1 );

            // for each key field
            for ( FieldDefinition field : classDef.getFieldsDefinitions() ) {
                if ( field.isKey() ) {

                    // result = result * 31 + 
                    mv.visitVarInsn( Opcodes.ILOAD,
                            1 );
                    mv.visitIntInsn( Opcodes.BIPUSH,
                            31 );
                    mv.visitVarInsn( Opcodes.ILOAD,
                            1 );
                    mv.visitInsn( Opcodes.IMUL );

                    mv.visitVarInsn(Opcodes.ALOAD,
                            0);

                    visitFieldOrGetter(mv, classDef, field);

                    if ( "boolean".equals( field.getTypeName() ) ) {
                        // attr_hash ::==  ? 1231 : 1237;
                        Label blabel1 = new Label();
                        mv.visitJumpInsn( Opcodes.IFEQ,
                                blabel1 );
                        mv.visitIntInsn( Opcodes.SIPUSH,
                                1231 );
                        Label blabel2 = new Label();
                        mv.visitJumpInsn( Opcodes.GOTO,
                                blabel2 );
                        mv.visitLabel( blabel1 );
                        mv.visitIntInsn( Opcodes.SIPUSH,
                                1237 );
                        mv.visitLabel( blabel2 );
                    } else if ( "long".equals( field.getTypeName() ) ) {
                        // attr_hash ::== (int) (longAttr ^ (longAttr >>> 32))
                        mv.visitVarInsn( Opcodes.ALOAD,
                                0 );

                        visitFieldOrGetter(mv, classDef, field);

                        mv.visitIntInsn( Opcodes.BIPUSH,
                                32 );
                        mv.visitInsn( Opcodes.LUSHR );
                        mv.visitInsn( Opcodes.LXOR );
                        mv.visitInsn( Opcodes.L2I );

                    } else if ( "float".equals( field.getTypeName() ) ) {
                        // attr_hash ::== Float.floatToIntBits( floatAttr );
                        mv.visitMethodInsn( Opcodes.INVOKESTATIC,
                                Type.getInternalName( Float.class ),
                                "floatToIntBits",
                                "(F)I" );
                    } else if ( "double".equals( field.getTypeName() ) ) {
                        // attr_hash ::== (int) (Double.doubleToLongBits( doubleAttr ) ^ (Double.doubleToLongBits( doubleAttr ) >>> 32));
                        mv.visitMethodInsn( Opcodes.INVOKESTATIC,
                                Type.getInternalName( Double.class ),
                                "doubleToLongBits",
                                "(D)J" );
                        mv.visitInsn( Opcodes.DUP2 );
                        mv.visitIntInsn( Opcodes.BIPUSH,
                                32 );
                        mv.visitInsn( Opcodes.LUSHR );
                        mv.visitInsn( Opcodes.LXOR );
                        mv.visitInsn( Opcodes.L2I );
                    } else if ( !BuildUtils.isPrimitive(field.getTypeName()) ) {
                        // attr_hash ::== ((objAttr == null) ? 0 : objAttr.hashCode());
                        Label olabel1 = new Label();
                        mv.visitJumpInsn( Opcodes.IFNONNULL,
                                olabel1 );
                        mv.visitInsn( Opcodes.ICONST_0 );
                        Label olabel2 = new Label();
                        mv.visitJumpInsn( Opcodes.GOTO,
                                olabel2 );
                        mv.visitLabel( olabel1 );
                        mv.visitVarInsn( Opcodes.ALOAD,
                                0 );

                        visitFieldOrGetter(mv, classDef, field);

                        if ( ! BuildUtils.isArray( field.getTypeName() ) ) {
                            mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
                                    "java/lang/Object",
                                    "hashCode",
                                    "()I" );
                        } else {
                            mv.visitMethodInsn( INVOKESTATIC,
                                    "java/util/Arrays",
                                    "hashCode",
                                    "(" + BuildUtils.arrayType( field.getTypeName() ) + ")I");
                        }
                        mv.visitLabel( olabel2 );
                    }

                    mv.visitInsn( Opcodes.IADD );
                    mv.visitVarInsn( Opcodes.ISTORE,
                            1 );
                }
            }
            mv.visitVarInsn( Opcodes.ILOAD,
                             1 );
            mv.visitInsn( Opcodes.IRETURN );

            Label lastLabel = null;
            if ( this.debug ) {
                lastLabel = new Label();
                mv.visitLabel( lastLabel );
                mv.visitLocalVariable( "this",
                        BuildUtils.getTypeDescriptor( classDef.getClassName() ),
                        null,
                        l0,
                        lastLabel,
                        0 );
                mv.visitLocalVariable( "hash",
                        Type.getDescriptor( int.class ),
                        null,
                        l0,
                        lastLabel,
                        1 );
            }
            mv.visitMaxs( 0,
                    0 );
            mv.visitEnd();
        }
    }

    protected void buildToString(ClassVisitor cw,
                                 ClassDefinition classDef) {
        MethodVisitor mv;
        {
            mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
                                 "toString",
                                 "()Ljava/lang/String;",
                                 null,
                                 null );
            mv.visitCode();

            Label l0 = null;
            if ( this.debug ) {
                l0 = new Label();
                mv.visitLabel( l0 );
            }

            // StringBuilder buf = new StringBuilder();
            mv.visitTypeInsn( Opcodes.NEW,
                              Type.getInternalName( StringBuilder.class ) );
            mv.visitInsn( Opcodes.DUP );
            mv.visitMethodInsn( Opcodes.INVOKESPECIAL,
                                Type.getInternalName( StringBuilder.class ),
                                "",
                                "()V" );
            mv.visitVarInsn( Opcodes.ASTORE,
                             1 );

            // buf.append(this.getClass().getSimpleName())
            mv.visitVarInsn( Opcodes.ALOAD,
                             1 );
            mv.visitVarInsn( Opcodes.ALOAD,
                             0 );
            mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
                                BuildUtils.getInternalType( classDef.getClassName() ),
                                "getClass",
                                "()Ljava/lang/Class;" );
            mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
                                Type.getInternalName( Class.class ),
                                "getSimpleName",
                                "()Ljava/lang/String;" );
            mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
                                Type.getInternalName( StringBuilder.class ),
                                "append",
                                "(Ljava/lang/String;)Ljava/lang/StringBuilder;" );

            appendToStringBuilder(mv, "( ");
            buildFieldsToString( classDef, mv, false );
            appendToStringBuilder(mv, " )");

            mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
                                Type.getInternalName( StringBuilder.class ),
                                "toString",
                                "()Ljava/lang/String;" );
            mv.visitInsn( Opcodes.ARETURN );

            Label lastLabel = null;
            if ( this.debug ) {
                lastLabel = new Label();
                mv.visitLabel( lastLabel );
                mv.visitLocalVariable( "this",
                                       BuildUtils.getTypeDescriptor( classDef.getClassName() ),
                                       null,
                                       l0,
                                       lastLabel,
                                       0 );
                mv.visitLocalVariable( "buf",
                                       Type.getDescriptor( StringBuilder.class ),
                                       null,
                                       l0,
                                       lastLabel,
                                       1 );
            }
            mv.visitMaxs( 0, 0 );
            mv.visitEnd();
        }
    }

    protected boolean buildFieldsToString( ClassDefinition classDef, MethodVisitor mv, boolean previous ) {
        boolean first = true;
        for ( FieldDefinition field : classDef.getFieldsDefinitions() ) {
            buildFieldToString( field, classDef, mv, first );
            first = false;
        }
        return previous;
    }

    protected void buildFieldToString(FieldDefinition field, ClassDefinition classDef, MethodVisitor mv, boolean first) {
        if ( !first ) {
            // buf.append(", ");
            appendToStringBuilder(mv, ", ");
        }

        // buf.append(attrName)
        appendToStringBuilder(mv, field.getName());

        // buf.append("=");
        appendToStringBuilder(mv, "=");

        // buf.append(attrValue)
        if (field.isRecursive()) {
            appendToStringBuilder( mv, field.getTypeName() + " [recursive]");
        } else {
            mv.visitVarInsn(Opcodes.ALOAD,
                            0);

            visitFieldOrGetter( mv, classDef, field );

            if ( BuildUtils.isPrimitive(field.getTypeName()) ) {
                String type = field.getTypeName().matches( "(byte|short)" ) ? "int" : field.getTypeName();
                mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
                        Type.getInternalName( StringBuilder.class ),
                        "append",
                        Type.getMethodDescriptor( Type.getType( StringBuilder.class ), Type.getType( BuildUtils.getTypeDescriptor( type ) ) ) );
            } else if ( BuildUtils.isArray( field.getTypeName() ) && BuildUtils.arrayDimSize( field.getTypeName() ) == 1 ) {


                mv.visitMethodInsn( INVOKESTATIC,
                        "java/util/Arrays",
                        "toString",
                        "(" + BuildUtils.getTypeDescriptor( BuildUtils.arrayType( field.getTypeName() ) ) + ")Ljava/lang/String;" );

                mv.visitMethodInsn( INVOKEVIRTUAL,
                        "java/lang/StringBuilder",
                        "append",
                        "(Ljava/lang/Object;)Ljava/lang/StringBuilder;" );

            } else {
                mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
                        Type.getInternalName( StringBuilder.class ),
                        "append",
                        Type.getMethodDescriptor( Type.getType( StringBuilder.class ), Type.getType( Object.class ) ) );
            }
        }
    }

    private void appendToStringBuilder(MethodVisitor mv, String s) {
        mv.visitLdcInsn( s );
        mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
                            Type.getInternalName(StringBuilder.class),
                            "append",
                            "(Ljava/lang/String;)Ljava/lang/StringBuilder;" );
    }


    protected void buildClassAnnotations(ClassDefinition classDef, ClassVisitor cw) {
        for (AnnotationDefinition ad : classDef.getAnnotations()) {
            AnnotationVisitor av = cw.visitAnnotation("L"+BuildUtils.getInternalType(ad.getName())+";", true);
            addAnnotationAttribute( ad, av );
            av.visitEnd();
        }
    }

    protected void buildFieldAnnotations(FieldDefinition fieldDef, FieldVisitor fv) {
        if (fieldDef.getAnnotations() != null) {
            for (AnnotationDefinition ad : fieldDef.getAnnotations()) {
                AnnotationVisitor av = fv.visitAnnotation("L"+BuildUtils.getInternalType(ad.getName())+";", true);
                addAnnotationAttribute( ad, av );
                av.visitEnd();
            }
        }
    }

    public static void addAnnotationAttribute( AnnotationDefinition ad, AnnotationVisitor av ) {
        for (String key : ad.getValues().keySet()) {
            AnnotationDefinition.AnnotationPropertyVal apv = ad.getValues().get(key);

            switch (apv.getValType()) {
                case STRINGARRAY:
                    AnnotationVisitor subAv = av.visitArray(apv.getProperty());
                    Object[] array = (Object[]) apv.getValue();
                    for (Object o : array) {
                        subAv.visit(null,o);
                    }
                    subAv.visitEnd();
                    break;
                case PRIMARRAY:
                    av.visit(apv.getProperty(),apv.getValue());
                    break;
                case ENUMARRAY:
                    AnnotationVisitor subEnav = av.visitArray(apv.getProperty());
                    Enum[] enArray = (Enum[]) apv.getValue();
                    String aenumType = "L" + BuildUtils.getInternalType( enArray[0].getClass().getName() ) + ";";
                    for (Enum enumer : enArray) {
                        subEnav.visitEnum(null,aenumType,enumer.name());
                    }
                    subEnav.visitEnd();
                    break;
                case CLASSARRAY:
                    AnnotationVisitor subKlav = av.visitArray(apv.getProperty());
                    Class[] klarray = (Class[]) apv.getValue();
                    for (Class klass : klarray) {
                        subKlav.visit( null, Type.getType( "L" + BuildUtils.getInternalType( klass.getName() ) + ";" ) );
                    }
                    subKlav.visitEnd();
                    break;
                case ENUMERATION:
                    String enumType = "L" + BuildUtils.getInternalType(apv.getType().getName()) + ";";
                    av.visitEnum(apv.getProperty(),enumType,((Enum) apv.getValue()).name());
                    break;
                case KLASS:
                    String klassName = BuildUtils.getInternalType(((Class) apv.getValue()).getName());
                    av.visit(apv.getProperty(),Type.getType("L"+klassName+";"));
                    break;
                case PRIMITIVE:
                    av.visit(apv.getProperty(),apv.getValue());
                    break;
                case STRING:
                    av.visit(apv.getProperty(),apv.getValue());
                    break;
            }

        }
    }


    protected void visitFieldOrGetter(MethodVisitor mv, ClassDefinition classDef, FieldDefinition field) {
        if (! field.isInherited()) {
            mv.visitFieldInsn( Opcodes.GETFIELD,
                    BuildUtils.getInternalType( classDef.getClassName() ),
                    field.getName(),
                    BuildUtils.getTypeDescriptor( field.getTypeName() ) );
        } else {
            mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
                    BuildUtils.getInternalType( classDef.getClassName()),
                    field.getReadMethod(),
                    Type.getMethodDescriptor(Type.getType(BuildUtils.getTypeDescriptor(field.getTypeName())),
                            new Type[]{})
            );
        }
    }


    protected  void updateTraitableField( MethodVisitor mv, ClassDefinition classDef, FieldDefinition fieldDef ) {
        String fieldType = fieldDef.getTypeName();
        
        mv.visitVarInsn( ALOAD, 0 );
        mv.visitFieldInsn( GETFIELD, BuildUtils.getInternalType( classDef.getClassName() ), TraitableBean.FIELDTMS_FIELD_NAME, Type.getDescriptor( TraitFieldTMS.class ) );

        mv.visitLdcInsn( fieldDef.resolveAlias() );

        if ( BuildUtils.isPrimitive( fieldType ) ) {
            mv.visitVarInsn( BuildUtils.varType( fieldType ), 1 );
            mv.visitMethodInsn( INVOKESTATIC, BuildUtils.getInternalType( BuildUtils.box( fieldType ) ), "valueOf", "(" + BuildUtils.getTypeDescriptor( fieldType ) + ")" + BuildUtils.getTypeDescriptor( BuildUtils.box( fieldType ) ) );
        } else {
            mv.visitVarInsn( ALOAD, 1 );
        }

        if ( BuildUtils.isPrimitive( fieldType ) ) {
//            mv.visitFieldInsn( GETSTATIC, BuildUtils.getInternalType( BuildUtils.box( fieldType ) ), "TYPE", Type.getDescriptor( Class.class ) );
            mv.visitLdcInsn( Type.getType( BuildUtils.getTypeDescriptor( BuildUtils.box( fieldDef.getTypeName() ) ) ) );
        } else {
            mv.visitLdcInsn( Type.getType( BuildUtils.getTypeDescriptor( fieldType ) ) );
        }

        mv.visitMethodInsn( INVOKEINTERFACE,
                            Type.getInternalName( TraitFieldTMS.class ),
                            "set",
                            Type.getMethodDescriptor( Type.getType( Object.class ), new Type[] { Type.getType( String.class ), Type.getType( Object.class ), Type.getType( Class.class ) } ) );

        if ( BuildUtils.isPrimitive( fieldType ) ) {
            mv.visitTypeInsn( CHECKCAST, BuildUtils.getInternalType( BuildUtils.box( fieldType ) ) );
            mv.visitMethodInsn( INVOKEVIRTUAL, BuildUtils.getInternalType( BuildUtils.box( fieldType ) ), BuildUtils.numericMorph( BuildUtils.box( fieldType ) ), "()" + BuildUtils.getTypeDescriptor( fieldType ) );
        } else {
            mv.visitTypeInsn( CHECKCAST, BuildUtils.getInternalType( fieldType ) );
        }

    }

}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy