BulkAccessorFactorypublic class BulkAccessorFactory extends Object A factory of bulk accessors. |
Fields Summary |
---|
private static final String | PACKAGE_NAME_PREFIX | private static final String | BULKACESSOR_CLASS_NAME | private static final String | OBJECT_CLASS_NAME | private static final String | GENERATED_GETTER_NAME | private static final String | GENERATED_SETTER_NAME | private static final String | GET_SETTER_DESC | private static final String | THROWABLE_CLASS_NAME | private static final String | BULKEXCEPTION_CLASS_NAME | private static int | counter | private Class | targetBean | private String[] | getterNames | private String[] | setterNames | private Class[] | types | public String | writeDirectory |
Constructors Summary |
---|
BulkAccessorFactory(Class target, String[] getterNames, String[] setterNames, Class[] types)
this.targetBean = target;
this.getterNames = getterNames;
this.setterNames = setterNames;
this.types = types;
this.writeDirectory = null;
|
Methods Summary |
---|
private void | addDefaultConstructor(javassist.bytecode.ClassFile classfile)Declares a constructor that takes no parameter.
ConstPool cp = classfile.getConstPool();
String cons_desc = "()V";
MethodInfo mi = new MethodInfo( cp, MethodInfo.nameInit, cons_desc );
Bytecode code = new Bytecode( cp, 0, 1 );
// aload_0
code.addAload( 0 );
// invokespecial
code.addInvokespecial( BulkAccessor.class.getName(), MethodInfo.nameInit, cons_desc );
// return
code.addOpcode( Opcode.RETURN );
mi.setCodeAttribute( code.toCodeAttribute() );
mi.setAccessFlags( AccessFlag.PUBLIC );
classfile.addMethod( mi );
| private void | addGetter(javassist.bytecode.ClassFile classfile, java.lang.reflect.Method[] getters)
ConstPool cp = classfile.getConstPool();
int target_type_index = cp.addClassInfo( this.targetBean.getName() );
String desc = GET_SETTER_DESC;
MethodInfo mi = new MethodInfo( cp, GENERATED_GETTER_NAME, desc );
Bytecode code = new Bytecode( cp, 6, 4 );
/* | this | bean | args | raw bean | */
if ( getters.length >= 0 ) {
// aload_1 // load bean
code.addAload( 1 );
// checkcast // cast bean
code.addCheckcast( this.targetBean.getName() );
// astore_3 // store bean
code.addAstore( 3 );
for ( int i = 0; i < getters.length; ++i ) {
if ( getters[i] != null ) {
Method getter = getters[i];
// aload_2 // args
code.addAload( 2 );
// iconst_i // continue to aastore
code.addIconst( i ); // growing stack is 1
Class returnType = getter.getReturnType();
int typeIndex = -1;
if ( returnType.isPrimitive() ) {
typeIndex = FactoryHelper.typeIndex( returnType );
// new
code.addNew( FactoryHelper.wrapperTypes[typeIndex] );
// dup
code.addOpcode( Opcode.DUP );
}
// aload_3 // load the raw bean
code.addAload( 3 );
String getter_desc = RuntimeSupport.makeDescriptor( getter );
String getterName = getter.getName();
if ( this.targetBean.isInterface() ) {
// invokeinterface
code.addInvokeinterface( target_type_index, getterName, getter_desc, 1 );
}
else {
// invokevirtual
code.addInvokevirtual( target_type_index, getterName, getter_desc );
}
if ( typeIndex >= 0 ) { // is a primitive type
// invokespecial
code.addInvokespecial(
FactoryHelper.wrapperTypes[typeIndex],
MethodInfo.nameInit,
FactoryHelper.wrapperDesc[typeIndex]
);
}
// aastore // args
code.add( Opcode.AASTORE );
code.growStack( -3 );
}
}
}
// return
code.addOpcode( Opcode.RETURN );
mi.setCodeAttribute( code.toCodeAttribute() );
mi.setAccessFlags( AccessFlag.PUBLIC );
classfile.addMethod( mi );
| private void | addSetter(javassist.bytecode.ClassFile classfile, java.lang.reflect.Method[] setters)
ConstPool cp = classfile.getConstPool();
int target_type_index = cp.addClassInfo( this.targetBean.getName() );
String desc = GET_SETTER_DESC;
MethodInfo mi = new MethodInfo( cp, GENERATED_SETTER_NAME, desc );
Bytecode code = new Bytecode( cp, 4, 6 );
/* | this | bean | args | i | raw bean | exception | */
if ( setters.length > 0 ) {
int start, end; // required to exception table
// iconst_0 // i
code.addIconst( 0 );
// istore_3 // store i
code.addIstore( 3 );
// aload_1 // load the bean
code.addAload( 1 );
// checkcast // cast the bean into a raw bean
code.addCheckcast( this.targetBean.getName() );
// astore 4 // store the raw bean
code.addAstore( 4 );
/* current stack len = 0 */
// start region to handling exception (BulkAccessorException)
start = code.currentPc();
int lastIndex = 0;
for ( int i = 0; i < setters.length; ++i ) {
if ( setters[i] != null ) {
int diff = i - lastIndex;
if ( diff > 0 ) {
// iinc 3, 1
code.addOpcode( Opcode.IINC );
code.add( 3 );
code.add( diff );
lastIndex = i;
}
}
/* current stack len = 0 */
// aload 4 // load the raw bean
code.addAload( 4 );
// aload_2 // load the args
code.addAload( 2 );
// iconst_i
code.addIconst( i );
// aaload
code.addOpcode( Opcode.AALOAD );
// checkcast
Class[] setterParamTypes = setters[i].getParameterTypes();
Class setterParamType = setterParamTypes[0];
if ( setterParamType.isPrimitive() ) {
// checkcast (case of primitive type)
// invokevirtual (case of primitive type)
this.addUnwrapper( classfile, code, setterParamType );
}
else {
// checkcast (case of reference type)
code.addCheckcast( setterParamType.getName() );
}
/* current stack len = 2 */
String rawSetterMethod_desc = RuntimeSupport.makeDescriptor( setters[i] );
if ( !this.targetBean.isInterface() ) {
// invokevirtual
code.addInvokevirtual( target_type_index, setters[i].getName(), rawSetterMethod_desc );
}
else {
// invokeinterface
Class[] params = setters[i].getParameterTypes();
int size;
if ( params[0].equals( Double.TYPE ) || params[0].equals( Long.TYPE ) ) {
size = 3;
}
else {
size = 2;
}
code.addInvokeinterface( target_type_index, setters[i].getName(), rawSetterMethod_desc, size );
}
}
// end region to handling exception (BulkAccessorException)
end = code.currentPc();
// return
code.addOpcode( Opcode.RETURN );
/* current stack len = 0 */
// register in exception table
int throwableType_index = cp.addClassInfo( THROWABLE_CLASS_NAME );
code.addExceptionHandler( start, end, code.currentPc(), throwableType_index );
// astore 5 // store exception
code.addAstore( 5 );
// new // BulkAccessorException
code.addNew( BULKEXCEPTION_CLASS_NAME );
// dup
code.addOpcode( Opcode.DUP );
// aload 5 // load exception
code.addAload( 5 );
// iload_3 // i
code.addIload( 3 );
// invokespecial // BulkAccessorException.<init>
String cons_desc = "(Ljava/lang/Throwable;I)V";
code.addInvokespecial( BULKEXCEPTION_CLASS_NAME, MethodInfo.nameInit, cons_desc );
// athrow
code.addOpcode( Opcode.ATHROW );
}
else {
// return
code.addOpcode( Opcode.RETURN );
}
mi.setCodeAttribute( code.toCodeAttribute() );
mi.setAccessFlags( AccessFlag.PUBLIC );
classfile.addMethod( mi );
| private void | addUnwrapper(javassist.bytecode.ClassFile classfile, javassist.bytecode.Bytecode code, java.lang.Class type)
int index = FactoryHelper.typeIndex( type );
String wrapperType = FactoryHelper.wrapperTypes[index];
// checkcast
code.addCheckcast( wrapperType );
// invokevirtual
code.addInvokevirtual( wrapperType, FactoryHelper.unwarpMethods[index], FactoryHelper.unwrapDesc[index] );
| BulkAccessor | create()
Method[] getters = new Method[getterNames.length];
Method[] setters = new Method[setterNames.length];
findAccessors( targetBean, getterNames, setterNames, types, getters, setters );
Class beanClass;
try {
ClassFile classfile = make( getters, setters );
ClassLoader loader = this.getClassLoader();
if ( writeDirectory != null ) {
FactoryHelper.writeFile( classfile, writeDirectory );
}
beanClass = FactoryHelper.toClass( classfile, loader, getDomain() );
return ( BulkAccessor ) this.newInstance( beanClass );
}
catch ( Exception e ) {
throw new BulkAccessorException( e.getMessage(), e );
}
| private static java.lang.reflect.Method | findAccessor(java.lang.Class clazz, java.lang.String name, java.lang.Class[] params, int index)
try {
Method method = clazz.getDeclaredMethod( name, params );
if ( Modifier.isPrivate( method.getModifiers() ) ) {
throw new BulkAccessorException( "private property", index );
}
return method;
}
catch ( NoSuchMethodException e ) {
throw new BulkAccessorException( "cannot find an accessor", index );
}
| private static void | findAccessors(java.lang.Class clazz, java.lang.String[] getterNames, java.lang.String[] setterNames, java.lang.Class[] types, java.lang.reflect.Method[] getters, java.lang.reflect.Method[] setters)
int length = types.length;
if ( setterNames.length != length || getterNames.length != length ) {
throw new BulkAccessorException( "bad number of accessors" );
}
Class[] getParam = new Class[0];
Class[] setParam = new Class[1];
for ( int i = 0; i < length; i++ ) {
if ( getterNames[i] != null ) {
Method getter = findAccessor( clazz, getterNames[i], getParam, i );
if ( getter.getReturnType() != types[i] ) {
throw new BulkAccessorException( "wrong return type: " + getterNames[i], i );
}
getters[i] = getter;
}
if ( setterNames[i] != null ) {
setParam[0] = types[i];
setters[i] = findAccessor( clazz, setterNames[i], setParam, i );
}
}
| private java.lang.ClassLoader | getClassLoader()
if ( targetBean != null && targetBean.getName().equals( OBJECT_CLASS_NAME ) ) {
return targetBean.getClassLoader();
}
else {
return getClass().getClassLoader();
}
| private java.security.ProtectionDomain | getDomain()
Class cl;
if ( this.targetBean != null ) {
cl = this.targetBean;
}
else {
cl = this.getClass();
}
return cl.getProtectionDomain();
| private javassist.bytecode.ClassFile | make(java.lang.reflect.Method[] getters, java.lang.reflect.Method[] setters)
String className = targetBean.getName();
// set the name of bulk accessor.
className = className + "_$$_bulkaccess_" + counter++;
if ( className.startsWith( "java." ) ) {
className = "org.javassist.tmp." + className;
}
ClassFile classfile = new ClassFile( false, className, BULKACESSOR_CLASS_NAME );
classfile.setAccessFlags( AccessFlag.PUBLIC );
addDefaultConstructor( classfile );
addGetter( classfile, getters );
addSetter( classfile, setters );
return classfile;
| private java.lang.Object | newInstance(java.lang.Class type)
BulkAccessor instance = ( BulkAccessor ) type.newInstance();
instance.target = targetBean;
int len = getterNames.length;
instance.getters = new String[len];
instance.setters = new String[len];
instance.types = new Class[len];
for ( int i = 0; i < len; i++ ) {
instance.getters[i] = getterNames[i];
instance.setters[i] = setterNames[i];
instance.types[i] = types[i];
}
return instance;
|
|