[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