[jboss-svn-commits] JBL Code SVN: r34617 - in labs/jbossrules/branches/5.1.x/drools-core/src: test/java/org/drools/factmodel and 1 other directory.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Mon Aug 9 21:30:10 EDT 2010


Author: tirelli
Date: 2010-08-09 21:30:10 -0400 (Mon, 09 Aug 2010)
New Revision: 34617

Modified:
   labs/jbossrules/branches/5.1.x/drools-core/src/main/java/org/drools/factmodel/ClassBuilder.java
   labs/jbossrules/branches/5.1.x/drools-core/src/test/java/org/drools/factmodel/ClassBuilderTest.java
Log:
JBRULES-2652: automatically generating constructor with fields for generated beans

Modified: labs/jbossrules/branches/5.1.x/drools-core/src/main/java/org/drools/factmodel/ClassBuilder.java
===================================================================
--- labs/jbossrules/branches/5.1.x/drools-core/src/main/java/org/drools/factmodel/ClassBuilder.java	2010-08-10 01:22:34 UTC (rev 34616)
+++ labs/jbossrules/branches/5.1.x/drools-core/src/main/java/org/drools/factmodel/ClassBuilder.java	2010-08-10 01:30:10 UTC (rev 34617)
@@ -35,7 +35,11 @@
 import java.beans.IntrospectionException;
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
 
+import org.drools.definition.type.FactField;
 import org.mvel2.asm.ClassWriter;
 import org.mvel2.asm.FieldVisitor;
 import org.mvel2.asm.Label;
@@ -170,6 +174,24 @@
         this.buildDefaultConstructor( cw,
                                       classDef );
 
+        // Building constructor with all fields
+        this.buildConstructorWithFields( cw,
+                                         classDef,
+                                         classDef.getFieldsDefinitions() );
+
+        // Building constructor with key fields only
+        List<FieldDefinition> keys = new LinkedList<FieldDefinition>();
+        for ( FieldDefinition fieldDef : classDef.getFieldsDefinitions() ) {
+            if ( fieldDef.isKey() ) {
+                keys.add( fieldDef );
+            }
+        }
+        if ( !keys.isEmpty() ) {
+            this.buildConstructorWithFields( cw,
+                                             classDef,
+                                             keys );
+        }
+
         // Building methods
         for ( FieldDefinition fieldDef : classDef.getFieldsDefinitions() ) {
             this.buildGetMethod( cw,
@@ -202,8 +224,8 @@
     private void buildClassHeader(ClassWriter cw,
                                   ClassDefinition classDef) {
         String[] original = classDef.getInterfaces();
-        String[] interfaces = new String[ original.length ];
-        for( int i = 0; i < original.length; i++ ) {
+        String[] interfaces = new String[original.length];
+        for ( int i = 0; i < original.length; i++ ) {
             interfaces[i] = getInternalType( original[i] );
         }
         // Building class header
@@ -283,6 +305,94 @@
     }
 
     /**
+     * Creates a constructor that takes and assigns values to all 
+     * fields in the order they are declared.
+     *
+     * @param cw
+     * @param classDef
+     */
+    private void buildConstructorWithFields(ClassWriter cw,
+                                            ClassDefinition classDef,
+                                            Collection<FieldDefinition> fieldDefs) {
+        MethodVisitor mv;
+        // Building  constructor
+        {
+            Type[] params = new Type[fieldDefs.size()];
+            int index = 0;
+            for ( FieldDefinition field : fieldDefs ) {
+                params[index++] = Type.getType( getTypeDescriptor( field.getTypeName() ) );
+            }
+
+            mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
+                                 "<init>",
+                                 Type.getMethodDescriptor( Type.VOID_TYPE,
+                                                           params ),
+                                 null,
+                                 null );
+            mv.visitCode();
+            Label l0 = null;
+            if ( this.debug ) {
+                l0 = new Label();
+                mv.visitLabel( l0 );
+            }
+            mv.visitVarInsn( Opcodes.ALOAD,
+                             0 );
+            mv.visitMethodInsn( Opcodes.INVOKESPECIAL,
+                                Type.getInternalName( Object.class ),
+                                "<init>",
+                                Type.getMethodDescriptor( Type.VOID_TYPE,
+                                                          new Type[]{} ) );
+
+            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( 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++;
+                }
+                mv.visitFieldInsn( Opcodes.PUTFIELD,
+                                   getInternalType( classDef.getClassName() ),
+                                   field.getName(),
+                                   getTypeDescriptor( field.getTypeName() ) );
+
+            }
+
+            mv.visitInsn( Opcodes.RETURN );
+            Label l1 = null;
+            if ( this.debug ) {
+                l1 = new Label();
+                mv.visitLabel( l1 );
+                mv.visitLocalVariable( "this",
+                                       getTypeDescriptor( classDef.getClassName() ),
+                                       null,
+                                       l0,
+                                       l1,
+                                       0 );
+                for ( FieldDefinition field : classDef.getFieldsDefinitions() ) {
+                    Label l11 = new Label();
+                    mv.visitLabel( l11 );
+                    mv.visitLocalVariable( field.getName(),
+                                           getTypeDescriptor( field.getTypeName() ),
+                                           null,
+                                           l0,
+                                           l1,
+                                           0 );
+                }
+            }
+            mv.visitMaxs( 0,
+                          0 );
+            mv.visitEnd();
+        }
+    }
+
+    /**
      * Creates the set method for the given field definition
      *
      * @param cw
@@ -824,11 +934,12 @@
                                    getTypeDescriptor( field.getTypeName() ) );
 
                 if ( 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 ),
-                                                                  new Type[]{Type.getType( getTypeDescriptor( field.getTypeName() ) )} ) );
+                                                                  new Type[]{Type.getType( getTypeDescriptor( type ) )} ) );
                 } else {
                     mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
                                         Type.getInternalName( StringBuilder.class ),

Modified: labs/jbossrules/branches/5.1.x/drools-core/src/test/java/org/drools/factmodel/ClassBuilderTest.java
===================================================================
--- labs/jbossrules/branches/5.1.x/drools-core/src/test/java/org/drools/factmodel/ClassBuilderTest.java	2010-08-10 01:22:34 UTC (rev 34616)
+++ labs/jbossrules/branches/5.1.x/drools-core/src/test/java/org/drools/factmodel/ClassBuilderTest.java	2010-08-10 01:30:10 UTC (rev 34617)
@@ -21,6 +21,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.Serializable;
+import java.lang.reflect.Constructor;
 import java.util.Date;
 import java.util.jar.JarEntry;
 import java.util.jar.JarOutputStream;
@@ -67,11 +68,11 @@
 
             Class clazz = builder.buildAndLoadClass( classDef );
             intDef.setReadWriteAccessor( store.getAccessor( clazz,
-                                                        intDef.getName(),
-                                                        classLoader ) );
+                                                            intDef.getName(),
+                                                            classLoader ) );
             stringDef.setReadWriteAccessor( store.getAccessor( clazz,
-                                                           stringDef.getName(),
-                                                           classLoader ) );
+                                                               stringDef.getName(),
+                                                               classLoader ) );
 
             byte[] data = builder.buildClass( classDef );
 
@@ -161,26 +162,26 @@
 
             Class clazz = builder.buildAndLoadClass( classDef );
             long1Def.setReadWriteAccessor( store.getAccessor( clazz,
-                                                          long1Def.getName(),
-                                                          classLoader ) );
+                                                              long1Def.getName(),
+                                                              classLoader ) );
             long2Def.setReadWriteAccessor( store.getAccessor( clazz,
-                                                          long2Def.getName(),
-                                                          classLoader ) );
+                                                              long2Def.getName(),
+                                                              classLoader ) );
             doubleDef.setReadWriteAccessor( store.getAccessor( clazz,
-                                                           doubleDef.getName(),
-                                                           classLoader ) );
+                                                               doubleDef.getName(),
+                                                               classLoader ) );
             intDef.setReadWriteAccessor( store.getAccessor( clazz,
-                                                        intDef.getName(),
-                                                        classLoader ) );
+                                                            intDef.getName(),
+                                                            classLoader ) );
             strDef.setReadWriteAccessor( store.getAccessor( clazz,
-                                                        strDef.getName(),
-                                                        classLoader ) );
+                                                            strDef.getName(),
+                                                            classLoader ) );
             dateDef.setReadWriteAccessor( store.getAccessor( clazz,
-                                                         dateDef.getName(),
-                                                         classLoader ) );
+                                                             dateDef.getName(),
+                                                             classLoader ) );
             str2Def.setReadWriteAccessor( store.getAccessor( clazz,
-                                                         str2Def.getName(),
-                                                         classLoader ) );
+                                                             str2Def.getName(),
+                                                             classLoader ) );
 
             Object x = clazz.newInstance();
             Object y = clazz.newInstance();
@@ -271,11 +272,11 @@
 
             Class clazz = builder.buildAndLoadClass( classDef );
             intDef.setReadWriteAccessor( store.getAccessor( clazz,
-                                                        intDef.getName(),
-                                                        classLoader ) );
+                                                            intDef.getName(),
+                                                            classLoader ) );
             strDef.setReadWriteAccessor( store.getAccessor( clazz,
-                                                        strDef.getName(),
-                                                        classLoader ) );
+                                                            strDef.getName(),
+                                                            classLoader ) );
 
             Object x = clazz.newInstance();
 
@@ -334,26 +335,26 @@
 
             Class clazz = builder.buildAndLoadClass( classDef );
             long1Def.setReadWriteAccessor( store.getAccessor( clazz,
-                                                          long1Def.getName(),
-                                                          classLoader ) );
+                                                              long1Def.getName(),
+                                                              classLoader ) );
             long2Def.setReadWriteAccessor( store.getAccessor( clazz,
-                                                          long2Def.getName(),
-                                                          classLoader ) );
+                                                              long2Def.getName(),
+                                                              classLoader ) );
             doubleDef.setReadWriteAccessor( store.getAccessor( clazz,
-                                                           doubleDef.getName(),
-                                                           classLoader ) );
+                                                               doubleDef.getName(),
+                                                               classLoader ) );
             intDef.setReadWriteAccessor( store.getAccessor( clazz,
-                                                        intDef.getName(),
-                                                        classLoader ) );
+                                                            intDef.getName(),
+                                                            classLoader ) );
             strDef.setReadWriteAccessor( store.getAccessor( clazz,
-                                                        strDef.getName(),
-                                                        classLoader ) );
+                                                            strDef.getName(),
+                                                            classLoader ) );
             dateDef.setReadWriteAccessor( store.getAccessor( clazz,
-                                                         dateDef.getName(),
-                                                         classLoader ) );
+                                                             dateDef.getName(),
+                                                             classLoader ) );
             str2Def.setReadWriteAccessor( store.getAccessor( clazz,
-                                                         str2Def.getName(),
-                                                         classLoader ) );
+                                                             str2Def.getName(),
+                                                             classLoader ) );
 
             Object x = clazz.newInstance();
 
@@ -389,4 +390,114 @@
 
     }
 
+    public void testConstructorWithFields() {
+        try {
+            ClassBuilder builder = new ClassBuilder();
+
+            ClassDefinition classDef = new ClassDefinition( "org.drools.TestClass5",
+                                                            null,
+                                                            new String[]{} );
+
+            String[] types = new String[]{"byte", "short", "int", "long", "float", "double", "char", "java.lang.String", "boolean"};
+            FieldDefinition[] fields = new FieldDefinition[types.length];
+            for ( int i = 0; i < types.length; i++ ) {
+                String attrName = types[i].substring( types[i].lastIndexOf( '.' ) + 1 );
+                attrName = attrName.substring( 0,
+                                               1 ).toLowerCase() + attrName.substring( 1 ) + "Attr";
+                fields[i] = new FieldDefinition( attrName, // attr name
+                                                 types[i], // attr type
+                                                 i % 2 == 0 ); // half of them are key
+                classDef.addField( fields[i] );
+            }
+
+            Class< ? > clazz = builder.buildAndLoadClass( classDef );
+
+            for ( FieldDefinition field : fields ) {
+                field.setReadWriteAccessor( store.getAccessor( clazz,
+                                                               field.getName(),
+                                                               classLoader ) );
+            }
+
+            Constructor< ? >[] cons = clazz.getConstructors();
+
+            Assert.assertEquals( 3,
+                                 cons.length );
+            for ( Constructor< ? > c : cons ) {
+                Class< ? >[] ptypes = c.getParameterTypes();
+                if ( ptypes.length == 0 ) {
+                    // default constructor
+                } else if ( ptypes.length == fields.length ) {
+                    // constructor with fields
+                    for ( int i = 0; i < ptypes.length; i++ ) {
+                        if ( !ptypes[i].equals( fields[i].getType() ) ) {
+                            Assert.fail( "Wrong parameter in constructor. index=" + i + " expected=" + fields[i].getType() + " found=" + ptypes[i] );
+                        }
+                    }
+
+                    // test actual invocation
+                    Object instance = c.newInstance( (byte) 1,
+                                                     (short) 2,
+                                                     3,
+                                                     4l,
+                                                     5.0f,
+                                                     6.0d,
+                                                     'a',
+                                                     "xyz",
+                                                     true );
+
+                    assertEquals( (byte) 1,
+                                  fields[0].getValue( instance ) );
+                    assertEquals( (short) 2,
+                                  fields[1].getValue( instance ) );
+                    assertEquals( 3,
+                                  fields[2].getValue( instance ) );
+                    assertEquals( 4l,
+                                  fields[3].getValue( instance ) );
+                    assertEquals( 5.0f,
+                                  fields[4].getValue( instance ) );
+                    assertEquals( 6.0d,
+                                  fields[5].getValue( instance ) );
+                    assertEquals( 'a',
+                                  fields[6].getValue( instance ) );
+                    assertEquals( "xyz",
+                                  fields[7].getValue( instance ) );
+                    assertEquals( true,
+                                  fields[8].getValue( instance ) );
+                } else if ( ptypes.length == ( fields.length / 2 +1 ) ) { // as defined in the beginning of the test
+                    // constructor with key fields
+                    int i = 0;
+                    for ( FieldDefinition field : fields ) {
+                        if ( field.isKey() && !ptypes[i++].equals( field.getType() ) ) {
+                            Assert.fail( "Wrong parameter in constructor. index=" + i + " expected=" + field.getType() + " found=" + ptypes[i] );
+                        }
+                    }
+                    // test actual invocation
+                    Object instance = c.newInstance( (byte) 1,
+                                                     3,
+                                                     5.0f,
+                                                     'a',
+                                                     true );
+
+                    assertEquals( (byte) 1,
+                                  fields[0].getValue( instance ) );
+                    assertEquals( 3,
+                                  fields[2].getValue( instance ) );
+                    assertEquals( 5.0f,
+                                  fields[4].getValue( instance ) );
+                    assertEquals( 'a',
+                                  fields[6].getValue( instance ) );
+                    assertEquals( true,
+                                  fields[8].getValue( instance ) );
+                    
+                } else {
+                    Assert.fail( "Unexpected constructor: " + c.toString() );
+                }
+            }
+
+        } catch ( Exception e ) {
+            e.printStackTrace();
+            Assert.fail( "Unexpected Exception: " + e.getMessage() );
+        }
+
+    }
 }



More information about the jboss-svn-commits mailing list