/* * Copyright 2011 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.traits; import org.drools.core.factmodel.BuildUtils; import org.drools.core.factmodel.ClassDefinition; import org.drools.core.factmodel.FieldDefinition; 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.Type; import java.io.IOException; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.BitSet; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import static org.drools.core.rule.builder.dialect.asm.ClassGenerator.createClassWriter; public class TraitMapPropertyWrapperClassBuilderImpl implements TraitPropertyWrapperClassBuilder, Serializable { private transient ClassDefinition trait; private transient TraitRegistry traitRegistry; public void init( ClassDefinition trait, TraitRegistry traitRegistry ) { this.trait = trait; this.traitRegistry = traitRegistry; } public byte[] buildClass( ClassDefinition core, ClassLoader classLoader ) throws IOException, SecurityException, IllegalArgumentException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException { FieldVisitor fv; MethodVisitor mv; // get the method bitmask BitSet mask = traitRegistry.getFieldMask( trait.getName(), core.getDefinedClass().getName() ); String name = TraitFactory.getPropertyWrapperName(trait, core); String internalWrapper = BuildUtils.getInternalType( name ); String descrCore = Type.getDescriptor( core.getDefinedClass() ); String internalCore = Type.getInternalName( core.getDefinedClass() ); ClassWriter cw = createClassWriter( classLoader, ACC_PUBLIC + ACC_SUPER, internalWrapper, Type.getDescriptor( Object.class ) + Type.getDescriptor( Map.class ) + Type.getDescriptor( MapWrapper.class ), // "Ljava/lang/Object;Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;Lorg/drools/factmodel/traits/MapWrapper;", Type.getInternalName( Object.class ), new String[]{ Type.getInternalName( Map.class ), Type.getInternalName( MapWrapper.class ), Type.getInternalName( Serializable.class ) } ); cw.visitInnerClass( Type.getInternalName( Map.Entry.class ), Type.getInternalName( Map.class ), "Entry", ACC_PUBLIC + ACC_STATIC + ACC_ABSTRACT + ACC_INTERFACE ); { fv = cw.visitField( 0, "object", descrCore, null, null ); fv.visitEnd(); } { fv = cw.visitField( 0, "map", Type.getDescriptor( Map.class ), "Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;", null ); fv.visitEnd(); } { mv = cw.visitMethod( ACC_PUBLIC, "<init>", "(" + descrCore + Type.getDescriptor( Map.class ) + ")V", "(" + descrCore + "Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;)V", null); mv.visitCode(); mv.visitVarInsn( ALOAD, 0 ); mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( Object.class ), "<init>", "()V" ); mv.visitVarInsn( ALOAD, 0 ); mv.visitVarInsn( ALOAD, 1 ); mv.visitFieldInsn( PUTFIELD, internalWrapper, "object", descrCore ); mv.visitVarInsn( ALOAD, 0 ); mv.visitVarInsn( ALOAD, 2 ); mv.visitFieldInsn( PUTFIELD, internalWrapper, "map", Type.getDescriptor( Map.class ) ); mv.visitVarInsn( ALOAD, 1 ); mv.visitVarInsn( ALOAD, 2 ); mv.visitMethodInsn( INVOKEVIRTUAL, internalCore, "_setDynamicProperties", "(" + Type.getDescriptor( Map.class ) + ")V" ); initSoftFields( mv, trait, core, internalWrapper, mask, 2 ); mv.visitInsn( RETURN ); mv.visitMaxs( 0, 0 ); mv.visitEnd(); } buildSize( cw, name, core.getClassName(), trait, core, mask ); buildIsEmpty( cw, name, core.getClassName(), trait, core, mask ); buildGet( cw, name, core.getClassName(), trait, core, mask ); buildPut( cw, name, core.getClassName(), trait, core, mask ); buildClear(cw, name, core.getClassName(), trait, core, mask); buildRemove(cw, name, core.getClassName(), trait, core, mask); buildContainsKey(cw, name, core.getClassName(), trait, core, mask); buildContainsValue(cw, name, core.getClassName(), trait, core, mask); buildKeyset(cw, name, core.getClassName(), trait, core, mask); buildValues(cw, name, core.getClassName(), trait, core, mask); buildEntryset(cw, name, core.getClassName(), trait, core, mask); buildCommonMethods( cw, name ); cw.visitEnd(); return cw.toByteArray(); } private void invokeRemove( MethodVisitor mv, String wrapperName, ClassDefinition core, String fieldName, FieldDefinition field ) { mv.visitLdcInsn( fieldName ); mv.visitVarInsn( ALOAD, 1 ); mv.visitMethodInsn( INVOKEVIRTUAL, Type.getInternalName(String.class), "equals", "(" + Type.getDescriptor( Object.class ) + ")Z" ); Label l1 = new Label(); mv.visitJumpInsn( IFEQ, l1 ); TraitFactory.invokeExtractor( mv, wrapperName, trait, core, field ); if ( BuildUtils.isPrimitive( field.getTypeName() ) ) { TraitFactory.valueOf( mv, field.getTypeName() ); } mv.visitVarInsn( ASTORE, 2 ); TraitFactory.invokeInjector( mv, wrapperName, trait, core, field, true, 1 ); mv.visitVarInsn( ALOAD, 2 ); mv.visitInsn( ARETURN ); mv.visitLabel( l1 ); } private void buildRemove( ClassWriter cw, String wrapperName, String coreName, ClassDefinition trait, ClassDefinition core, BitSet mask ) { String internalWrapper = BuildUtils.getInternalType( wrapperName ); MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "remove", "(" + Type.getDescriptor( Object.class ) +")" + Type.getDescriptor( Object.class ), null, null ); mv.visitCode(); for ( FieldDefinition field : core.getFieldsDefinitions() ) { invokeRemove( mv, wrapperName, core, field.getName(), field ); } int j = 0; int stack = 0; for ( FieldDefinition field : trait.getFieldsDefinitions() ) { boolean isSoftField = TraitRegistry.isSoftField( field, j++, mask ); if ( isSoftField ) { mv.visitLdcInsn( field.getName() ); mv.visitVarInsn( ALOAD, 1 ); mv.visitMethodInsn( INVOKEVIRTUAL, Type.getInternalName( String.class ), "equals", "(" + Type.getDescriptor( Object.class ) + ")Z" ); Label l2 = new Label(); mv.visitJumpInsn( IFEQ, l2 ); mv.visitVarInsn( ALOAD, 0 ); mv.visitFieldInsn( GETFIELD, internalWrapper, "map", Type.getDescriptor( Map.class ) ); mv.visitLdcInsn( field.getName() ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Map.class ), "get", "(" + Type.getDescriptor( Object.class ) + ")" + Type.getDescriptor( Object.class ) ); mv.visitVarInsn( ASTORE, 2 ); mv.visitVarInsn( ALOAD, 0 ); mv.visitFieldInsn( GETFIELD, internalWrapper, "map", Type.getDescriptor( Map.class ) ); mv.visitLdcInsn( field.getName() ); mv.visitInsn( BuildUtils.zero( field.getTypeName() ) ); if ( BuildUtils.isPrimitive( field.getTypeName() ) ) { TraitFactory.valueOf( mv, field.getTypeName() ); } mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Map.class ), "put", "(" + Type.getDescriptor( Object.class ) + Type.getDescriptor( Object.class ) + ")" + Type.getDescriptor( Object.class ) ); mv.visitInsn( POP ); mv.visitVarInsn( ALOAD, 2 ); mv.visitInsn( ARETURN ); mv.visitLabel( l2 ); } } mv.visitVarInsn( ALOAD, 0 ); mv.visitFieldInsn( GETFIELD, internalWrapper, "map", Type.getDescriptor( Map.class ) ); mv.visitVarInsn( ALOAD, 1 ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Map.class ), "remove", "(" + Type.getDescriptor( Object.class ) + ")" + Type.getDescriptor( Object.class ) ); mv.visitVarInsn( ASTORE, 2 ); mv.visitVarInsn( ALOAD, 2 ); mv.visitInsn( ARETURN ); // mv.visitMaxs( 4 + stack, 3 ); mv.visitMaxs( 0, 0 ); mv.visitEnd(); } private int initSoftFields( MethodVisitor mv, ClassDefinition trait, ClassDefinition core, String internalWrapper, BitSet mask, int varNum ) { int j = 0; for ( FieldDefinition field : trait.getFieldsDefinitions() ) { boolean isSoftField = TraitRegistry.isSoftField( field, j++, mask ); if ( isSoftField ) { mv.visitVarInsn( ALOAD, varNum ); mv.visitLdcInsn( field.resolveAlias() ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Map.class ), "containsKey", Type.getMethodDescriptor( Type.getType( boolean.class ), new Type[] { Type.getType( Object.class ) } ) ); Label l0 = new Label(); mv.visitJumpInsn( IFNE, l0 ); mv.visitVarInsn( ALOAD, varNum ); mv.visitLdcInsn( field.resolveAlias() ); mv.visitInsn( BuildUtils.zero( field.getTypeName() ) ); if ( BuildUtils.isPrimitive( field.getTypeName() ) ) { TraitFactory.valueOf( mv, field.getTypeName() ); } 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 ); if ( core.isFullTraiting() ) { mv.visitVarInsn( ALOAD, 0 ); mv.visitFieldInsn( GETFIELD, internalWrapper, "object", Type.getDescriptor( core.getDefinedClass() ) ); mv.visitTypeInsn( CHECKCAST, Type.getInternalName( TraitableBean.class ) ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( TraitableBean.class ), "_getFieldTMS", Type.getMethodDescriptor( Type.getType( TraitFieldTMS.class ), new Type[] {} ) ); mv.visitVarInsn( ASTORE, 1 ); mv.visitVarInsn( ALOAD, 1 ); mv.visitLdcInsn( field.resolveAlias() ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( TraitFieldTMS.class ), "isManagingField", Type.getMethodDescriptor( Type.BOOLEAN_TYPE, new Type[] { Type.getType( String.class ) } ) ); Label l1 = new Label(); mv.visitJumpInsn( IFNE, l1 ); mv.visitVarInsn( ALOAD, 1 ); mv.visitLdcInsn( Type.getType( BuildUtils.getTypeDescriptor( core.getClassName() ) ) ); mv.visitLdcInsn( field.resolveAlias() ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( TraitFieldTMS.class ), "registerField", Type.getMethodDescriptor( Type.VOID_TYPE, new Type[]{ Type.getType( Class.class ), Type.getType( String.class ) } ) ); mv.visitLabel( l1 ); } mv.visitLabel( l0 ); } } return 0; } private void buildClear( ClassWriter cw, String wrapperName, String coreName, ClassDefinition trait, ClassDefinition core, BitSet mask ) { String internalWrapper = BuildUtils.getInternalType( wrapperName ); boolean hasPrimitiveFields = false; boolean hasObjectFields = false; MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "clear", "()V", null, null ); mv.visitCode(); for ( FieldDefinition field : core.getFieldsDefinitions() ) { if ( field.isKey() ) continue; if ( BuildUtils.isPrimitive( field.getTypeName() ) ) { hasPrimitiveFields = true; } else { hasObjectFields = true; } TraitFactory.invokeInjector( mv, wrapperName, trait, core, field, true, 1 ); } int stack = 2; if ( hasPrimitiveFields ) { stack++; } if ( hasObjectFields ) { stack++; } mv.visitVarInsn( ALOAD, 0 ); mv.visitFieldInsn( GETFIELD, internalWrapper, "map", Type.getDescriptor( Map.class ) ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Map.class ), "clear", "()V" ); int num = initSoftFields( mv, trait, core, internalWrapper, mask, 0 ); stack += num; mv.visitInsn( RETURN ); // mv.visitMaxs( stack , 1 ); mv.visitMaxs( 0, 0 ); mv.visitEnd(); } private void buildContainsValue( ClassWriter cw, String wrapperName, String coreName, ClassDefinition trait, ClassDefinition core, BitSet mask ) { String internalWrapper = BuildUtils.getInternalType( wrapperName ); MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "containsValue", "(" + Type.getDescriptor( Object.class ) + ")Z", null, null ); mv.visitCode(); // null check mv.visitVarInsn( ALOAD, 1 ); Label l99 = new Label(); mv.visitJumpInsn( IFNONNULL, l99 ); for ( FieldDefinition field : core.getFieldsDefinitions() ) { if ( ! BuildUtils.isPrimitive( field.getTypeName() ) ) { TraitFactory.invokeExtractor( mv, wrapperName, trait, core, field ); Label l1 = new Label(); mv.visitJumpInsn( IFNONNULL, l1 ); mv.visitInsn( ICONST_1 ); mv.visitInsn( IRETURN ); mv.visitLabel( l1 ); } } mv.visitVarInsn( ALOAD, 0 ); mv.visitFieldInsn( GETFIELD, internalWrapper, "map", Type.getDescriptor( Map.class ) ); mv.visitInsn( ACONST_NULL ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Map.class ), "containsValue", "(" + Type.getDescriptor( Object.class ) + ")Z" ); mv.visitInsn( IRETURN ); mv.visitLabel( l99 ); // non-null values check for ( FieldDefinition field : core.getFieldsDefinitions() ) { mv.visitVarInsn( ALOAD, 1 ); TraitFactory.invokeExtractor( mv, wrapperName, trait, core, field ); if ( BuildUtils.isPrimitive( field.getTypeName() ) ) { TraitFactory.valueOf( mv, field.getTypeName() ); } mv.visitMethodInsn( INVOKEVIRTUAL, Type.getInternalName( Object.class ), "equals", "(" + Type.getDescriptor( Object.class ) + ")Z" ); Label l0 = new Label(); mv.visitJumpInsn( IFEQ, l0 ); mv.visitInsn( ICONST_1 ); mv.visitInsn( IRETURN ); mv.visitLabel( l0 ); } mv.visitVarInsn( ALOAD, 0 ); mv.visitFieldInsn( GETFIELD, internalWrapper, "map", Type.getDescriptor( Map.class ) ); mv.visitVarInsn( ALOAD, 1 ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Map.class ), "containsValue", "(" + Type.getDescriptor( Object.class ) + ")Z" ); mv.visitInsn( IRETURN ); // mv.visitMaxs( core.getFieldsDefinitions().size() > 0 ? 3 : 2, 2 ); mv.visitMaxs( 0, 0 ); mv.visitEnd(); } protected void invokeContainsKey( MethodVisitor mv, String fieldName ) { mv.visitLdcInsn( fieldName ); mv.visitVarInsn( ALOAD, 1 ); mv.visitMethodInsn( INVOKEVIRTUAL, Type.getInternalName( String.class ), "equals", "(" + Type.getDescriptor( Object.class ) + ")Z" ); Label l0 = new Label(); mv.visitJumpInsn( IFEQ, l0 ); mv.visitInsn( ICONST_1 ); mv.visitInsn( IRETURN ); mv.visitLabel( l0 ); } private void buildContainsKey(ClassWriter cw, String name, String className, ClassDefinition trait, ClassDefinition core, BitSet mask) { String internalWrapper = BuildUtils.getInternalType( name ); MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "containsKey", "(" + Type.getDescriptor( Object.class ) + ")Z", null, null ); mv.visitCode(); for ( FieldDefinition field : core.getFieldsDefinitions() ) { invokeContainsKey( mv, field.getName() ); } mv.visitVarInsn( ALOAD, 0 ); mv.visitFieldInsn( GETFIELD, internalWrapper, "map", Type.getDescriptor( Map.class ) ); mv.visitVarInsn( ALOAD, 1 ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Map.class ), "containsKey", "(" + Type.getDescriptor( Object.class ) + ")Z" ); mv.visitInsn( IRETURN ); // mv.visitMaxs( 2, 2 ); mv.visitMaxs( 0, 0 ); mv.visitEnd(); } private void buildSize( ClassVisitor cw, String wrapperName, String coreName, ClassDefinition trait, ClassDefinition core, BitSet mask ) { String internalWrapper = BuildUtils.getInternalType( wrapperName ); MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "size", "()I", null, null ); mv.visitCode(); mv.visitVarInsn( ALOAD, 0 ); mv.visitFieldInsn( GETFIELD, internalWrapper, "map", Type.getDescriptor( Map.class ) ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Map.class ), "size", "()I" ); int n = core.getFieldsDefinitions().size(); for ( int j = 0; j < n; j++ ) { mv.visitInsn( ICONST_1 ); mv.visitInsn( IADD ); } mv.visitInsn( IRETURN ); // mv.visitMaxs( core.getFieldsDefinitions().size() > 0 ? 2 : 1, 1 ); mv.visitMaxs( 0, 0 ); mv.visitEnd(); } private void buildIsEmpty( ClassVisitor cw, String wrapperName, String coreName, ClassDefinition trait, ClassDefinition core, BitSet mask ) { String internalWrapper = BuildUtils.getInternalType( wrapperName ); boolean hasHardFields = core.getFieldsDefinitions().size() > 0; MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "isEmpty", "()Z", null, null ); mv.visitCode(); if ( ! hasHardFields ) { mv.visitVarInsn( ALOAD, 0 ); mv.visitFieldInsn( GETFIELD, internalWrapper, "map", Type.getDescriptor( Map.class ) ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Map.class ), "isEmpty", "()Z" ); } else { mv.visitInsn( ICONST_0 ); } mv.visitInsn( IRETURN ); // mv.visitMaxs( 1, 1 ); mv.visitMaxs( 0, 0 ); mv.visitEnd(); } private void invokeGet( MethodVisitor mv, String wrapperName, ClassDefinition core, String fieldName, FieldDefinition field ) { mv.visitLdcInsn( fieldName ); mv.visitVarInsn( ALOAD, 1 ); mv.visitMethodInsn( INVOKEVIRTUAL, Type.getInternalName( String.class ), "equals", "(" + Type.getDescriptor( Object.class ) + ")Z" ); Label l0 = new Label(); mv.visitJumpInsn( IFEQ, l0 ); TraitFactory.invokeExtractor( mv, wrapperName, trait, core, field ); if ( BuildUtils.isPrimitive( field.getTypeName() ) ) { TraitFactory.valueOf( mv, field.getTypeName() ); } mv.visitInsn( ARETURN ); mv.visitLabel( l0 ); } private void buildGet( ClassVisitor cw, String wrapperName, String coreName, ClassDefinition trait, ClassDefinition core, BitSet mask ) { String internalWrapper = BuildUtils.getInternalType( wrapperName ); MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "get", "(" + Type.getDescriptor( Object.class ) + ")" + Type.getDescriptor( Object.class ), null, null ); mv.visitCode(); if ( core.getFieldsDefinitions().size() > 0) { for ( FieldDefinition field : core.getFieldsDefinitions() ) { invokeGet( mv, wrapperName, core, field.getName(), field ); } } mv.visitVarInsn( ALOAD, 0 ); mv.visitFieldInsn( GETFIELD, internalWrapper, "map", Type.getDescriptor( Map.class ) ); mv.visitVarInsn( ALOAD, 1 ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Map.class ), "get", "(" + Type.getDescriptor( Object.class ) + ")" + Type.getDescriptor( Object.class ) ); mv.visitInsn( ARETURN ); // mv.visitMaxs( 2, 2 ); mv.visitMaxs( 0, 0 ); mv.visitEnd(); } protected void invokePut( MethodVisitor mv, String wrapperName, ClassDefinition core, String fieldName, FieldDefinition field ) { mv.visitLdcInsn( fieldName ); mv.visitVarInsn( ALOAD, 1 ); mv.visitMethodInsn( INVOKEVIRTUAL, Type.getInternalName( String.class ), "equals", "(" + Type.getDescriptor( Object.class ) + ")Z" ); Label l1 = new Label(); mv.visitJumpInsn( IFEQ, l1 ); mv.visitVarInsn( ALOAD, 2 ); if ( BuildUtils.isPrimitive( field.getTypeName() ) ) { TraitFactory.primitiveValue( mv, field.getTypeName() ); mv.visitVarInsn( BuildUtils.storeType( field.getTypeName() ), 3 ); TraitFactory.invokeInjector( mv, wrapperName, trait, core, field, false, 3 ); } else { TraitFactory.invokeInjector( mv, wrapperName, trait, core, field, false, 2 ); } mv.visitVarInsn( ALOAD, 2 ); mv.visitInsn( ARETURN ); mv.visitLabel( l1 ); } private void buildPut( ClassVisitor cw, String wrapperName, String coreName, ClassDefinition trait, ClassDefinition core, BitSet mask ) { String internalWrapper = BuildUtils.getInternalType( wrapperName ); MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "put", "(" + Type.getDescriptor( String.class ) + Type.getDescriptor( Object.class ) + ")" + Type.getDescriptor( Object.class ), null, null ); mv.visitCode(); if ( core.getFieldsDefinitions().size() > 0) { for ( FieldDefinition field : core.getFieldsDefinitions() ) { invokePut( mv, wrapperName, core, field.getName(), field ); } } mv.visitVarInsn( ALOAD, 0 ); mv.visitFieldInsn( GETFIELD, internalWrapper, "map", Type.getDescriptor( Map.class ) ); mv.visitVarInsn( ALOAD, 1 ); mv.visitVarInsn( ALOAD, 2 ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Map.class ), "put", "(" + Type.getDescriptor( Object.class ) + Type.getDescriptor( Object.class ) + ")" + Type.getDescriptor( Object.class ) ); mv.visitInsn( ARETURN ); // mv.visitMaxs( 4, 5 ); mv.visitMaxs( 0, 0 ); mv.visitEnd(); } private void buildEntryset( ClassVisitor cw, String wrapperName, String coreName, ClassDefinition trait, ClassDefinition core, BitSet mask ) { String internalWrapper = BuildUtils.getInternalType( wrapperName ); MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "entrySet", "()" + Type.getDescriptor( Set.class ), "()Ljava/util/Set<Ljava/util/Map$Entry<Ljava/lang/String;Ljava/lang/Object;>;>;", null); mv.visitCode(); mv.visitTypeInsn( NEW, Type.getInternalName( HashSet.class ) ); mv.visitInsn( DUP ); mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( HashSet.class ), "<init>", "()V" ); mv.visitVarInsn( ASTORE, 1 ); for ( FieldDefinition field : core.getFieldsDefinitions() ) { mv.visitVarInsn( ALOAD, 1 ); mv.visitLdcInsn( field.getName() ); TraitFactory.invokeExtractor( mv, wrapperName, trait, core, field ); if ( BuildUtils.isPrimitive( field.getTypeName() ) ) { TraitFactory.valueOf( mv, field.getTypeName() ); } mv.visitMethodInsn( INVOKESTATIC, Type.getInternalName( TraitProxy.class ), "buildEntry", "(" + Type.getDescriptor( String.class ) + Type.getDescriptor( Object.class ) + ")" + Type.getDescriptor( Map.Entry.class ) ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Set.class ), "add", "(" + Type.getDescriptor( Object.class ) + ")Z" ); mv.visitInsn( POP ); } mv.visitVarInsn( ALOAD, 1 ); mv.visitVarInsn( ALOAD, 0 ); mv.visitFieldInsn( GETFIELD, internalWrapper, "map", Type.getDescriptor( Map.class ) ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Map.class ), "entrySet", "()" + Type.getDescriptor( Set.class ) ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Set.class ), "addAll", "(" + Type.getDescriptor( Collection.class )+ ")Z" ); mv.visitInsn( POP ); mv.visitVarInsn( ALOAD, 1 ); mv.visitInsn( ARETURN ); // mv.visitMaxs( core.getFieldsDefinitions().size() > 0 ? 4 : 2, 2 ); mv.visitMaxs( 0, 0 ); mv.visitEnd(); } private void buildKeyset( ClassVisitor cw, String wrapperName, String coreName, ClassDefinition trait, ClassDefinition core, BitSet mask ) { String internalWrapper = BuildUtils.getInternalType( wrapperName ); MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "keySet", "()" + Type.getDescriptor( Set.class ), "()Ljava/util/Set<Ljava/lang/String;>;", null ); mv.visitCode(); mv.visitTypeInsn( NEW, Type.getInternalName( HashSet.class ) ); mv.visitInsn( DUP ); mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( HashSet.class ), "<init>", "()V" ); mv.visitVarInsn( ASTORE, 1 ); for ( FieldDefinition field : core.getFieldsDefinitions() ) { mv.visitVarInsn( ALOAD, 1 ); mv.visitLdcInsn( field.getName() ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Set.class ), "add", "(" + Type.getDescriptor( Object.class ) + ")Z" ); mv.visitInsn( POP ); } mv.visitVarInsn( ALOAD, 1 ); mv.visitVarInsn( ALOAD, 0 ); mv.visitFieldInsn( GETFIELD, internalWrapper, "map", Type.getDescriptor( Map.class ) ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Map.class ), "keySet", "()" + Type.getDescriptor( Set.class ) ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Set.class ), "addAll", "(" + Type.getDescriptor( Collection.class ) + ")Z" ); mv.visitInsn( POP ); mv.visitVarInsn( ALOAD, 1 ); mv.visitInsn( ARETURN ); // mv.visitMaxs( 2, 2 ); mv.visitMaxs( 0, 0 ); mv.visitEnd(); } private void buildValues( ClassVisitor cw, String wrapperName, String coreName, ClassDefinition trait, ClassDefinition core, BitSet mask ) { String internalWrapper = BuildUtils.getInternalType( wrapperName ); MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "values", "()" + Type.getDescriptor( Collection.class ), "()Ljava/util/Collection<Ljava/lang/Object;>;", null ); mv.visitCode(); mv.visitTypeInsn( NEW, Type.getInternalName( ArrayList.class ) ); mv.visitInsn( DUP ); mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( ArrayList.class ), "<init>", "()V" ); mv.visitVarInsn( ASTORE, 1 ); for ( FieldDefinition field : core.getFieldsDefinitions() ) { mv.visitVarInsn( ALOAD, 1 ); TraitFactory.invokeExtractor( mv, wrapperName, trait, core, field ); if ( BuildUtils.isPrimitive( field.getTypeName() ) ) { TraitFactory.valueOf( mv, field.getTypeName() ); } mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Collection.class ), "add", "(" + Type.getDescriptor( Object.class ) + ")Z" ); mv.visitInsn( POP ); } mv.visitVarInsn( ALOAD, 1 ); mv.visitVarInsn( ALOAD, 0 ); mv.visitFieldInsn( GETFIELD, internalWrapper, "map", Type.getDescriptor( Map.class ) ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Map.class ), "values", "()" + Type.getDescriptor( Collection.class ) ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Collection.class ), "addAll", "(" + Type.getDescriptor( Collection.class ) + ")Z" ); mv.visitInsn( POP ); mv.visitVarInsn( ALOAD, 1 ); mv.visitInsn( ARETURN ); // mv.visitMaxs( core.getFieldsDefinitions().size() > 0 ? 3 : 2, 2); mv.visitMaxs( 0, 0 ); mv.visitEnd(); } public void buildCommonMethods( ClassVisitor cw, String wrapper ) { { MethodVisitor mv = cw.visitMethod( ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "put", "(" + Type.getDescriptor( Object.class ) + Type.getDescriptor( Object.class ) + ")" + Type.getDescriptor( Object.class ), null, null ); mv.visitCode(); mv.visitVarInsn( ALOAD, 0 ); mv.visitVarInsn( ALOAD, 1 ); mv.visitTypeInsn( CHECKCAST, Type.getInternalName( String.class ) ); mv.visitVarInsn( ALOAD, 2 ); mv.visitMethodInsn( INVOKEVIRTUAL, BuildUtils.getInternalType( wrapper ), "put", "(" + Type.getDescriptor( String.class ) + Type.getDescriptor( Object.class ) + ")" + Type.getDescriptor( Object.class ) ); mv.visitInsn( ARETURN ); // mv.visitMaxs( 3, 3 ); mv.visitMaxs( 0, 0 ); mv.visitEnd(); } { MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "equals", "(" + Type.getDescriptor( Object.class ) + ")Z", null, null ); mv.visitCode(); mv.visitVarInsn( ALOAD, 0 ); mv.visitVarInsn( ALOAD, 1 ); Label l0 = new Label(); mv.visitJumpInsn( IF_ACMPNE, l0 ); mv.visitInsn( ICONST_1 ); mv.visitInsn( IRETURN ); mv.visitLabel( l0 ); mv.visitVarInsn( ALOAD, 1 ); mv.visitTypeInsn( CHECKCAST, Type.getInternalName( MapWrapper.class ) ); mv.visitVarInsn( ASTORE, 2 ); mv.visitVarInsn( ALOAD, 0 ); mv.visitFieldInsn( GETFIELD, BuildUtils.getInternalType( wrapper ), "map", Type.getDescriptor( Map.class ) ); mv.visitVarInsn( ALOAD, 2 ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( MapWrapper.class ), "getInnerMap", "()" + Type.getDescriptor( Map.class ) ); mv.visitMethodInsn( INVOKEVIRTUAL, Type.getInternalName( Object.class ), "equals", "(" + Type.getDescriptor( Object.class ) + ")Z" ); mv.visitInsn( IRETURN ); // mv.visitMaxs( 2, 3 ); mv.visitMaxs( 0, 0 ); mv.visitEnd(); } { MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "hashCode", "()I", null, null ); mv.visitCode(); mv.visitVarInsn( ALOAD, 0 ); mv.visitFieldInsn( GETFIELD, BuildUtils.getInternalType( wrapper ), "map", Type.getDescriptor( Map.class ) ); mv.visitMethodInsn( INVOKEVIRTUAL, Type.getInternalName( Object.class ), "hashCode", "()I" ); mv.visitInsn( IRETURN ); // mv.visitMaxs( 1, 1 ); mv.visitMaxs( 0, 0 ); mv.visitEnd(); } { MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "getInnerMap", "()" + Type.getDescriptor( Map.class ), "()Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;", null ); mv.visitCode(); mv.visitVarInsn( ALOAD, 0 ); mv.visitFieldInsn( GETFIELD, BuildUtils.getInternalType( wrapper ), "map", Type.getDescriptor( Map.class ) ); mv.visitInsn( ARETURN ); // mv.visitMaxs( 1, 1 ); mv.visitMaxs( 0, 0 ); mv.visitEnd(); } { MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "putAll", "(" + Type.getDescriptor( Map.class ) + ")V", "(Ljava/util/Map<+Ljava/lang/String;+Ljava/lang/Object;>;)V", null ); mv.visitCode(); mv.visitVarInsn( ALOAD, 1 ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Map.class ), "keySet", "()" + Type.getDescriptor( Set.class ) ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Set.class ), "iterator", "()" + Type.getDescriptor( Iterator.class ) ); mv.visitVarInsn( ASTORE, 2 ); Label l0 = new Label(); mv.visitLabel( l0 ); mv.visitVarInsn( ALOAD, 2 ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Iterator.class ), "hasNext", "()Z" ); Label l1 = new Label(); mv.visitJumpInsn( IFEQ, l1 ); mv.visitVarInsn( ALOAD, 2 ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Iterator.class ), "next", "()" + Type.getDescriptor( Object.class ) ); mv.visitTypeInsn( CHECKCAST, Type.getInternalName( String.class ) ); mv.visitVarInsn( ASTORE, 3 ); mv.visitVarInsn( ALOAD, 0 ); mv.visitVarInsn( ALOAD, 3 ); mv.visitVarInsn( ALOAD, 1 ); mv.visitVarInsn( ALOAD, 3 ); mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( Map.class ), "get", "(" + Type.getDescriptor( Object.class ) + ")" + Type.getDescriptor( Object.class ) ); mv.visitMethodInsn( INVOKEVIRTUAL, BuildUtils.getInternalType( wrapper ), "put", "(" + Type.getDescriptor( String.class ) + Type.getDescriptor( Object.class ) + ")" + Type.getDescriptor( Object.class ) ); mv.visitInsn( POP ); mv.visitJumpInsn( GOTO, l0 ); mv.visitLabel( l1 ); mv.visitInsn( RETURN ); // mv.visitMaxs( 4, 4 ); mv.visitMaxs( 0, 0 ); mv.visitEnd(); } { MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "toString", "()" + Type.getDescriptor( String.class ), null, null ); mv.visitCode(); mv.visitTypeInsn( NEW, Type.getInternalName( StringBuilder.class ) ); mv.visitInsn( DUP ); mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( StringBuilder.class ), "<init>", "()V" ); mv.visitLdcInsn("[["); mv.visitMethodInsn( INVOKEVIRTUAL, Type.getInternalName( StringBuilder.class ), "append", "(" + Type.getDescriptor( String.class ) +")" + Type.getDescriptor( StringBuilder.class ) ); mv.visitVarInsn( ALOAD, 0 ); mv.visitMethodInsn( INVOKEVIRTUAL, BuildUtils.getInternalType( wrapper ), "entrySet", "()" + Type.getDescriptor( Set.class ) ); mv.visitMethodInsn( INVOKEVIRTUAL, Type.getInternalName( StringBuilder.class ), "append", "(" + Type.getDescriptor( Object.class ) + ")" + Type.getDescriptor( StringBuilder.class ) ); mv.visitLdcInsn( "]]" ); mv.visitMethodInsn( INVOKEVIRTUAL, Type.getInternalName( StringBuilder.class ), "append", "(" + Type.getDescriptor( String.class ) +")" + Type.getDescriptor( StringBuilder.class )); mv.visitMethodInsn( INVOKEVIRTUAL, Type.getInternalName( StringBuilder.class ), "toString", "()" + Type.getDescriptor( String.class ) ); mv.visitInsn( ARETURN ); // mv.visitMaxs( 2, 1 ); mv.visitMaxs( 0, 0 ); mv.visitEnd(); } } }