InvocationTargetException,
InstantiationException,
NoSuchFieldException {
ClassWriter cw = new ClassWriter( ClassWriter.COMPUTE_MAXS );
FieldVisitor fv;
MethodVisitor mv;
// get the method bitmask
BitSet mask = traitRegistry.getFieldMask( getTrait().getName(), core.getDefinedClass().getName() );
String name = TraitFactory.getPropertyWrapperName( getTrait(), core );
String masterName = TraitFactory.getProxyName( getTrait(), core );
String internalWrapper = BuildUtils.getInternalType( name );
String internalProxy = BuildUtils.getInternalType( masterName );
String descrCore = Type.getDescriptor( core.getDefinedClass() );
String internalCore = Type.getInternalName( core.getDefinedClass() );
String internalTrait = Type.getInternalName( getTrait().getDefinedClass() );
Class mixinClass = null;
String mixin = null;
Set<Method> mixinMethods = new HashSet<Method>();
Map<String,Method> mixinGetSet = new HashMap<String,Method>();
try {
if ( getTrait().getDefinedClass() != null ) {
Trait annTrait = getAnnotation( getTrait().getDefinedClass(), Trait.class );
if ( hasImpl( annTrait ) ) {
mixinClass = annTrait.impl();
mixin = mixinClass.getSimpleName().substring(0,1).toLowerCase() + mixinClass.getSimpleName().substring(1);
ClassFieldInspector cfi = new ClassFieldInspector( mixinClass );
for ( Method m : mixinClass.getMethods() ) {
try {
getTrait().getDefinedClass().getMethod(m.getName(), m.getParameterTypes() );
if ( cfi.getGetterMethods().containsValue( m )
|| cfi.getSetterMethods().containsValue( m )) {
mixinGetSet.put( m.getName(), m );
} else {
mixinMethods.add( m );
}
} catch (NoSuchMethodException e) {
}
}
}
}
} catch ( Exception e ) {
e.printStackTrace();
}
cw.visit( V1_5, ACC_PUBLIC + ACC_SUPER,
internalProxy,
null,
Type.getInternalName( proxyBaseClass ),
new String[]{ internalTrait, Type.getInternalName( Serializable.class ) } );
{
fv = cw.visitField( ACC_PRIVATE + ACC_FINAL + ACC_STATIC,
TraitType.traitNameField, Type.getDescriptor( String.class ),
null, null );
fv.visitEnd();
}
{
fv = cw.visitField( ACC_PUBLIC + ACC_FINAL, "object", descrCore, null, null );
fv.visitEnd();
}
{
fv = cw.visitField( ACC_PUBLIC + ACC_FINAL, "map", Type.getDescriptor( Map.class ), "Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;", null );
fv.visitEnd();
}
if ( mixinClass != null ) {
{
fv = cw.visitField( ACC_PRIVATE,
mixin,
BuildUtils.getTypeDescriptor( mixinClass.getName() ),
null, null );
fv.visitEnd();
}
}
{
mv = cw.visitMethod( ACC_STATIC, "<clinit>", "()V", null, null );
mv.visitCode();
mv.visitLdcInsn( Type.getType( Type.getDescriptor( trait.getDefinedClass() ) ) );
mv.visitMethodInsn( INVOKEVIRTUAL,
Type.getInternalName( Class.class ), "getName", "()" + Type.getDescriptor( String.class ) );
mv.visitFieldInsn( PUTSTATIC,
internalProxy,
TraitType.traitNameField,
Type.getDescriptor( String.class ) );
mv.visitInsn( RETURN );
mv.visitMaxs( 0, 0 );
mv.visitEnd();
}
{
mv = cw.visitMethod( ACC_PUBLIC, "<init>", "()V", null, null );
mv.visitCode();
mv.visitVarInsn( ALOAD, 0 );
mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( proxyBaseClass ), "<init>", "()V" );
mv.visitInsn( RETURN );
// mv.visitMaxs( 1, 1 );
mv.visitMaxs( 0, 0 );
mv.visitEnd();
}
{
mv = cw.visitMethod( ACC_PUBLIC, "<init>",
"(" + descrCore + Type.getDescriptor( Map.class ) + Type.getDescriptor( BitSet.class ) + Type.getDescriptor( BitSet.class ) + Type.getDescriptor( boolean.class ) + ")V",
"(" + descrCore + "Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;" + Type.getDescriptor( BitSet.class ) + Type.getDescriptor( BitSet.class ) + Type.getDescriptor( boolean.class ) + ")V", null);
mv.visitCode();
mv.visitVarInsn( ALOAD, 0 );
mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( proxyBaseClass ), "<init>", "()V" );
mv.visitVarInsn( ALOAD, 2 );
Label l0 = new Label();
mv.visitJumpInsn( IFNONNULL, l0 );
mv.visitTypeInsn( NEW, Type.getInternalName( ExternalizableLinkedHashMap.class ) );
mv.visitInsn( DUP );
mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( ExternalizableLinkedHashMap.class ), "<init>", "()V" );
mv.visitVarInsn( ASTORE, 2 );
mv.visitLabel( l0 );
if ( mixinClass != null ) {
try {
Class actualArg = getPossibleConstructor( mixinClass, trait.getDefinedClass() );
mv.visitVarInsn( ALOAD, 0 );
mv.visitTypeInsn( NEW, Type.getInternalName( mixinClass ) );
mv.visitInsn( DUP );
mv.visitVarInsn( ALOAD, 0 );
mv.visitMethodInsn( INVOKESPECIAL,
Type.getInternalName( mixinClass ),
"<init>",
"("+ Type.getDescriptor( actualArg ) + ")V");
mv.visitFieldInsn( PUTFIELD,
internalProxy,
mixin,
Type.getDescriptor( mixinClass ) );
} catch ( NoSuchMethodException nsme ) {
mv.visitVarInsn( ALOAD, 0 );
mv.visitTypeInsn( NEW, Type.getInternalName( mixinClass ) );
mv.visitInsn( DUP );
mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( mixinClass ), "<init>", "()V" );
mv.visitFieldInsn( PUTFIELD,
internalProxy,
mixin,
Type.getDescriptor( mixinClass ) );
}
}
mv.visitVarInsn( ALOAD, 0 );
mv.visitVarInsn( ALOAD, 1 );
mv.visitFieldInsn( PUTFIELD, internalProxy, "object", descrCore );
mv.visitVarInsn( ALOAD, 0 );
mv.visitVarInsn( ALOAD, 2 );
mv.visitFieldInsn( PUTFIELD, internalProxy, "map", Type.getDescriptor( Map.class ) );
mv.visitVarInsn( ALOAD, 0 );
mv.visitVarInsn( ALOAD, 3 );
mv.visitMethodInsn( INVOKEVIRTUAL, internalProxy, "setTypeCode", Type.getMethodDescriptor( Type.VOID_TYPE, new Type[] { Type.getType( BitSet.class ) } ) );
mv.visitVarInsn( ALOAD, 0 );
mv.visitTypeInsn( NEW, internalWrapper );
mv.visitInsn( DUP );
mv.visitVarInsn( ALOAD, 1 );
mv.visitVarInsn( ALOAD, 2 );
mv.visitMethodInsn( INVOKESPECIAL, internalWrapper, "<init>", "(" + descrCore + Type.getDescriptor( Map.class ) + ")V" );
mv.visitFieldInsn( PUTFIELD, internalProxy, "fields", Type.getDescriptor( Map.class ) );
mv.visitVarInsn( ALOAD, 1 );
mv.visitMethodInsn( INVOKEVIRTUAL, internalCore, "_getDynamicProperties", "()" + Type.getDescriptor( Map.class ) );
Label l1 = new Label();
mv.visitJumpInsn( IFNONNULL, l1 );
mv.visitVarInsn( ALOAD, 1 );
mv.visitVarInsn( ALOAD, 2 );
mv.visitMethodInsn( INVOKEVIRTUAL, internalCore, "_setDynamicProperties", "(" + Type.getDescriptor( Map.class ) + ")V" );
mv.visitLabel( l1 );
mv.visitVarInsn( ALOAD, 1 );
mv.visitMethodInsn( INVOKEVIRTUAL, internalCore, "_getTraitMap", "()" + Type.getDescriptor( Map.class ) );
Label l2 = new Label();
mv.visitJumpInsn( IFNONNULL, l2 );
mv.visitVarInsn( ALOAD, 1 );
mv.visitTypeInsn( NEW, Type.getInternalName( TraitTypeMap.class ) );
mv.visitInsn( DUP );
mv.visitTypeInsn( NEW, Type.getInternalName( ExternalizableLinkedHashMap.class ) );
mv.visitInsn( DUP );
mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( ExternalizableLinkedHashMap.class ), "<init>", "()V" );
mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( TraitTypeMap.class ), "<init>", "(" + Type.getDescriptor( Map.class ) + ")V" );
mv.visitMethodInsn( INVOKEVIRTUAL, internalCore, "_setTraitMap", "(" + Type.getDescriptor( Map.class ) + ")V" );
mv.visitLabel( l2 );
// core._setBottomTypeCode()
mv.visitVarInsn( ALOAD, 1 );
mv.visitVarInsn( ALOAD, 4 );
mv.visitMethodInsn( INVOKEVIRTUAL, internalCore, "_setBottomTypeCode", Type.getMethodDescriptor( Type.VOID_TYPE, new Type[] { Type.getType( BitSet.class ) } ) );
// core.addTrait
mv.visitVarInsn( ALOAD, 1 );
mv.visitLdcInsn( trait.getName() );
mv.visitVarInsn( ALOAD, 0 );
mv.visitMethodInsn( INVOKEVIRTUAL, internalCore, "addTrait", Type.getMethodDescriptor( Type.VOID_TYPE, new Type[] { Type.getType( String.class ), Type.getType( Thing.class ) } ) );
mv.visitVarInsn( ALOAD, 0 );
mv.visitVarInsn( ILOAD, 5 );
mv.visitMethodInsn( INVOKESPECIAL, internalProxy, "synchFields", Type.getMethodDescriptor( Type.VOID_TYPE, new Type[] { Type.BOOLEAN_TYPE } ) );
mv.visitInsn( RETURN );
// mv.visitMaxs( 5, 3 );
mv.visitMaxs( 0, 0 );
mv.visitEnd();
}
{
mv = cw.visitMethod( ACC_PUBLIC, "getTraitName", "()" + Type.getDescriptor( String.class ), null, null);
mv.visitCode();
mv.visitFieldInsn( GETSTATIC, internalProxy, TraitType.traitNameField, Type.getDescriptor( String.class ) );
mv.visitInsn( ARETURN );
mv.visitMaxs( 0, 0 );
mv.visitEnd();
}
{
mv = cw.visitMethod( ACC_PUBLIC, "getCore", "()" + descrCore + "", null, null );
mv.visitCode();
mv.visitVarInsn( ALOAD, 0 );
mv.visitFieldInsn( GETFIELD, internalProxy, "object", descrCore );
mv.visitInsn( ARETURN );
// mv.visitMaxs( 1, 1 );
mv.visitMaxs( 0, 0 );
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "getObject", "()" + Type.getDescriptor( TraitableBean.class ), null, null);
mv.visitCode();
mv.visitVarInsn( ALOAD, 0 );
mv.visitFieldInsn( GETFIELD, internalProxy, "object", descrCore );
mv.visitTypeInsn( CHECKCAST, Type.getInternalName( TraitableBean.class ) );
mv.visitInsn( ARETURN );
// mv.visitMaxs( 1, 1 );
mv.visitMaxs( 0, 0 );
mv.visitEnd();
}
{
mv = cw.visitMethod( ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "getCore", "()" + Type.getDescriptor( Object.class ), null, null );
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, internalProxy, "getCore", "()" + descrCore);
mv.visitInsn(ARETURN);
// mv.visitMaxs( 1, 1 );
mv.visitMaxs( 0, 0 );
mv.visitEnd();
}
{
mv = cw.visitMethod( ACC_PUBLIC, "isTop", "()Z", null, null );
mv.visitCode();
mv.visitInsn( Thing.class.equals( trait.getDefinedClass() ) ? ICONST_1 : ICONST_0 );
mv.visitInsn( IRETURN );
mv.visitMaxs( 0, 0 );
mv.visitEnd();
}
{
mv = cw.visitMethod( ACC_PUBLIC, "shed", Type.getMethodDescriptor( Type.VOID_TYPE, new Type[] {} ), null, null );
mv.visitCode();
if ( core.isFullTraiting() ) {
Iterator<FieldDefinition> iter = trait.getFieldsDefinitions().iterator();
for ( int j = 0; j < trait.getFieldsDefinitions().size(); j++ ) {
FieldDefinition fld = iter.next();
boolean hardField = ! TraitRegistry.isSoftField( fld, j, mask );
shedField( mv, fld, internalProxy, trait, core, hardField, j + 2 );
}
}
mv.visitInsn( RETURN );
mv.visitMaxs( 0, 0 );
mv.visitEnd();
}
{
mv = cw.visitMethod( ACC_PUBLIC, "writeExternal", "(" + Type.getDescriptor( ObjectOutput.class ) + ")V", null, new String[] { Type.getInternalName( IOException.class ) } );
mv.visitCode();
mv.visitVarInsn( ALOAD, 1 );
mv.visitVarInsn( ALOAD, 0 );
mv.visitMethodInsn( INVOKEVIRTUAL, internalProxy, "getObject", "()" + Type.getDescriptor( TraitableBean.class ) );
mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( ObjectOutput.class ), "writeObject", "(" + Type.getDescriptor( Object.class ) + ")V" );
mv.visitVarInsn( ALOAD, 1 );
mv.visitVarInsn( ALOAD, 0 );
mv.visitFieldInsn( GETFIELD, internalProxy, "map", Type.getDescriptor( Map.class ) );
mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( ObjectOutput.class ), "writeObject", "(" + Type.getDescriptor( Object.class ) + ")V" );
mv.visitVarInsn( ALOAD, 0 );
mv.visitVarInsn( ALOAD, 1 );
mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( proxyBaseClass ), "writeExternal", "(" + Type.getDescriptor( ObjectOutput.class ) + ")V" );
mv.visitInsn( RETURN );
// mv.visitMaxs( 2, 2 );
mv.visitMaxs( 0, 0 );
mv.visitEnd();
}
{
mv = cw.visitMethod( ACC_PUBLIC, "readExternal", "(" + Type.getDescriptor( ObjectInput.class )+ ")V",
null, new String[] { Type.getInternalName( IOException.class ), Type.getInternalName( ClassNotFoundException.class ) } );
mv.visitCode();
mv.visitVarInsn( ALOAD, 0 );
mv.visitVarInsn( ALOAD, 1 );
mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( ObjectInput.class ), "readObject", "()" + Type.getDescriptor( Object.class ) );
mv.visitTypeInsn( CHECKCAST, internalCore );
mv.visitFieldInsn( PUTFIELD, internalProxy, "object", descrCore );
mv.visitVarInsn( ALOAD, 0 );
mv.visitVarInsn( ALOAD, 1 );
mv.visitMethodInsn( INVOKEINTERFACE, Type.getInternalName( ObjectInput.class ), "readObject", "()" + Type.getDescriptor( Object.class ) );
mv.visitTypeInsn( CHECKCAST, Type.getInternalName( Map.class ) );
mv.visitFieldInsn( PUTFIELD, internalProxy, "map", Type.getDescriptor( Map.class ) );
mv.visitVarInsn( ALOAD, 0 );
mv.visitVarInsn( ALOAD, 1 );
mv.visitMethodInsn( INVOKESPECIAL, Type.getInternalName( proxyBaseClass ), "readExternal", "(" + Type.getDescriptor( ObjectInput.class ) + ")V" );
mv.visitInsn( RETURN );
// mv.visitMaxs( 3, 2 );
mv.visitMaxs( 0, 0 );
mv.visitEnd();
}
int j = 0;
for ( FieldDefinition field : trait.getFieldsDefinitions() ) {
boolean hardField = ! TraitRegistry.isSoftField( field, j++, mask );
if ( core.isFullTraiting() ) {
buildLogicalGetter( cw, field, masterName, trait, core );
if ( hardField ) {
buildHardSetter( cw, field, masterName, trait, core );
} else {
buildSoftSetter( cw, field, masterName, trait, core );
}
} else {
if ( ! hardField ) {
if ( ! mixinGetSet.containsKey( BuildUtils.getterName( field.getName(), field.getTypeName() ) ) ) {
buildSoftGetter( cw, field, masterName, trait, core );
buildSoftSetter( cw, field, masterName, trait, core );
} else {
//
}
} else {
buildHardGetter( cw, field, masterName, trait, core );
buildHardSetter( cw, field, masterName, trait, core );
}
}
}
boolean hasKeys = false;
for ( FactField ff : trait.getFields() ) {
if ( ff.isKey() ) {
hasKeys = true;
break;
}
}
if ( ! hasKeys ) {
buildEqualityMethods( cw, masterName, core.getClassName() );
} else {
buildKeyedEqualityMethods( cw, trait, masterName, core.getClassName() );
}
if ( mixinClass != null ) {
buildMixinMethods( cw, masterName, mixin, mixinClass, mixinMethods );
buildMixinMethods( cw, masterName, mixin, mixinClass, mixinGetSet.values() );
}
buildCommonMethods( cw, masterName, core.getClassName() );
buildExtendedMethods( cw, trait, core, mask );
cw.visitEnd();
return cw.toByteArray();
}