bloritsch 2003/09/10 09:57:06
Modified: fortress/container/src/impl/org/apache/avalon/fortress/impl/factory
AbstractObjectFactory.java BCELCodeGenerator.java
BCELWrapperGenerator.java
Log:
Updated the BCEL code to properly find the correct method type, and to grab one
instance of a method to wrap.
Revision Changes Path
1.6 +48 -13
avalon/fortress/container/src/impl/org/apache/avalon/fortress/impl/factory/AbstractObjectFactory.java
Index: AbstractObjectFactory.java
===================================================================
RCS file:
/home/cvs/avalon/fortress/container/src/impl/org/apache/avalon/fortress/impl/factory/AbstractObjectFactory.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- AbstractObjectFactory.java 29 May 2003 16:42:44 -0000 1.5
+++ AbstractObjectFactory.java 10 Sep 2003 16:57:06 -0000 1.6
@@ -49,10 +49,7 @@
*/
package org.apache.avalon.fortress.impl.factory;
-import org.apache.avalon.framework.activity.Disposable;
-import org.apache.avalon.framework.activity.Initializable;
-import org.apache.avalon.framework.activity.Startable;
-import org.apache.avalon.framework.activity.Suspendable;
+import org.apache.avalon.framework.activity.*;
import org.apache.avalon.framework.component.Component;
import org.apache.avalon.framework.component.Composable;
import org.apache.avalon.framework.component.Recomposable;
@@ -64,6 +61,7 @@
import org.apache.avalon.framework.logger.Loggable;
import org.apache.avalon.framework.parameters.Parameterizable;
import org.apache.avalon.framework.parameters.Reparameterizable;
+import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.Serviceable;
import org.apache.excalibur.instrument.Instrument;
import org.apache.excalibur.instrument.Instrumentable;
@@ -199,19 +197,19 @@
protected static Class[] guessWorkInterfaces( final Class clazz )
{
final HashSet workInterfaces = new HashSet();
-
+
// Get *all* interfaces
guessWorkInterfaces( clazz, workInterfaces );
// Make sure we have Component in there.
workInterfaces.add( Component.class );
-
+
// Remove the invalid ones.
for ( int j = 0; j < INVALID_INTERFACES.length; j++ )
{
workInterfaces.remove(INVALID_INTERFACES[j]);
}
-
+
return (Class[]) workInterfaces.toArray( new Class[workInterfaces.size()] );
}
@@ -227,14 +225,51 @@
{
if ( null != clazz )
{
- final Class[] interfaces = clazz.getInterfaces();
-
- for ( int i = 0; i < interfaces.length; i++ )
- {
- workInterfaces.add( interfaces[i] );
- }
+ addInterfaces( clazz.getInterfaces(), workInterfaces );
guessWorkInterfaces( clazz.getSuperclass(), workInterfaces );
}
+ }
+
+ /**
+ * Get a list of interfaces to proxy by scanning through
+ * all interfaces a class implements.
+ *
+ * @param interfaces the array of interfaces
+ * @param workInterfaces the set of current work interfaces
+ */
+ private static void addInterfaces( final Class[] interfaces,
+ final Set workInterfaces )
+ {
+ for ( int i = 0; i < interfaces.length; i++ )
+ {
+ workInterfaces.add( interfaces[i] );
+ addInterfaces(interfaces[i].getInterfaces(), workInterfaces);
+ }
+ }
+
+ public static void main(String[] args) throws Exception
+ {
+ BCELWrapperGenerator generator = new BCELWrapperGenerator();
+ Class klass = generator.createWrapper(Test.class);
+ Class[] ifaces = klass.getInterfaces();
+ for(int i =0; i < ifaces.length; i++)
+ {
+ System.out.println(ifaces[i].getName());
+ }
+ }
+
+ public static interface Base extends Executable,Serviceable{};
+ public static interface Extended extends Base{void extend();};
+ public static interface Complicate extends Extended{void complicate();};
+ public static abstract class SuperTest implements Complicate
+ {
+ public final void execute(){}
+ }
+ public static class Test extends SuperTest
+ {
+ public void extend(){}
+ public void complicate(){}
+ public void service(ServiceManager manager){}
}
}
1.5 +156 -76
avalon/fortress/container/src/impl/org/apache/avalon/fortress/impl/factory/BCELCodeGenerator.java
Index: BCELCodeGenerator.java
===================================================================
RCS file:
/home/cvs/avalon/fortress/container/src/impl/org/apache/avalon/fortress/impl/factory/BCELCodeGenerator.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- BCELCodeGenerator.java 30 May 2003 15:39:13 -0000 1.4
+++ BCELCodeGenerator.java 10 Sep 2003 16:57:06 -0000 1.5
@@ -50,15 +50,12 @@
package org.apache.avalon.fortress.impl.factory;
import org.apache.bcel.Constants;
-import org.apache.bcel.classfile.ExceptionTable;
import org.apache.bcel.classfile.Field;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.*;
-import java.util.ArrayList;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
/**
@@ -344,11 +341,7 @@
* </code>
* </pre>
*
- * @param methodName The name of the method to create
- * @param returnType The return type of the method to create
- * @param parameterTypes The array of parameter types of the method to create
- * @param exceptionNames The array of the names of the exceptions the method
- * to create might throw
+ * @param meth The method descriptor
*
* @return Method The [EMAIL PROTECTED]
org.apache.bcel.classfile.Method Method}
* object representing the created method
@@ -356,11 +349,7 @@
* @throws IllegalArgumentException If any of the parameters passed in is null.
* @throws IllegalStateException If this instance is not initialized.
*/
- public Method createMethodWrapper(
- final String methodName,
- final Type returnType,
- final Type[] parameterTypes,
- final String[] exceptionNames )
+ public Method createMethodWrapper( MethodDesc meth )
throws IllegalArgumentException, IllegalStateException
{
if ( !isInitialized() )
@@ -369,10 +358,10 @@
"BCELMethodFieldImplementationGenerator is not initialized.";
throw new IllegalStateException( message );
}
- if ( methodName == null
- || returnType == null
- || parameterTypes == null
- || exceptionNames == null )
+ if ( meth.name == null
+ || meth.returnType == null
+ || meth.parameterTypes == null
+ || meth.exceptionNames == null )
{
final String message = "None of the parameters may be <null>.";
throw new IllegalArgumentException( message );
@@ -381,18 +370,18 @@
final MethodGen mg =
new MethodGen(
Constants.ACC_PUBLIC,
- returnType,
- parameterTypes,
+ meth.returnType,
+ meth.parameterTypes,
null,
- methodName,
+ meth.name,
m_wrapperClassName,
m_instructionList,
m_constPoolGenerator );
// Create throws clause
- for ( int i = 0; i < exceptionNames.length; i++ )
+ for ( int i = 0; i < meth.exceptionNames.length; i++ )
{
- mg.addException( exceptionNames[i] );
+ mg.addException( meth.exceptionNames[i] );
}
// Loading the wrapped class instance onto the stack ...
@@ -408,25 +397,27 @@
// Loading all parameters onto the stack ...
short stackIndex = 1;
// Stack index 0 is occupied by the wrapped class instance.
- for ( int i = 0; i < parameterTypes.length; ++i )
+ for ( int i = 0; i < meth.parameterTypes.length; ++i )
{
m_instructionList.append(
- InstructionFactory.createLoad( parameterTypes[i], stackIndex )
);
- stackIndex += parameterTypes[i].getSize();
+ InstructionFactory.createLoad( meth.parameterTypes[i],
stackIndex ) );
+ stackIndex += meth.parameterTypes[i].getSize();
}
+ findImplementation( meth );
+
// Invoking the specified method with the loaded parameters on
// the wrapped class instance ...
m_instructionList.append(
m_instructionFactory.createInvoke(
- m_classToWrap.getClassName(),
- methodName,
- returnType,
- parameterTypes,
- Constants.INVOKEVIRTUAL ) );
+ meth.implementingClassName,
+ meth.name,
+ meth.returnType,
+ meth.parameterTypes,
+ (meth.isFinal) ? Constants.INVOKENONVIRTUAL :
Constants.INVOKEVIRTUAL ) );
// Creating return statement ...
- m_instructionList.append( InstructionFactory.createReturn( returnType ) );
+ m_instructionList.append( InstructionFactory.createReturn( meth.returnType
) );
mg.setMaxStack();
mg.setMaxLocals();
@@ -434,6 +425,42 @@
return extractMethod( mg );
}
+ private void findImplementation( MethodDesc meth )
+ {
+ JavaClass currentClass = m_classToWrap;
+
+ while ( null != currentClass && null == meth.implementingClassName )
+ {
+ Method[] methList = currentClass.getMethods();
+
+ for (int i = 0; i < methList.length; i++)
+ {
+ boolean isEqual = methList[i].isPublic() &&
!methList[i].isAbstract();
+ isEqual = isEqual && methList[i].getName().equals(meth.name);
+ isEqual = isEqual &&
methList[i].getReturnType().equals(meth.returnType);
+ isEqual = isEqual && methList[i].getArgumentTypes().length ==
meth.parameterTypes.length;
+ Type[] parameterTypes = methList[i].getArgumentTypes();
+ for (int j = 0; isEqual && j < parameterTypes.length; j++)
+ {
+ isEqual = isEqual &&
parameterTypes[j].equals(meth.parameterTypes[j]);
+ }
+
+ if (isEqual)
+ {
+ meth.implementingClassName = currentClass.getClassName();
+ meth.isFinal = methList[i].isFinal();
+ }
+ }
+
+ currentClass = currentClass.getSuperClass();
+ }
+
+ if (null == meth.implementingClassName)
+ {
+ throw new IllegalStateException("No concrete class for the requested
method: " + meth.toString());
+ }
+ }
+
/**
* Create a method declaration/definition of the form
* <pre>
@@ -462,68 +489,49 @@
throw new IllegalArgumentException( message );
}
- return createMethodWrapper(
- methodToWrap.getName(),
- methodToWrap.getReturnType(),
- methodToWrap.getArgumentTypes(),
- methodToWrap.getExceptionTable().getExceptionNames() );
+ return createMethodWrapper( new MethodDesc( methodToWrap ) );
}
/**
* Creates an implementation for the supplied [EMAIL PROTECTED]
org.apache.bcel.classfile.JavaClass JavaClass}
* instance representing an interface.
*
- * @param interfaceToImplement The interface we want to create an
implementation for
+ * @param interfacesToImplement The interfaces we want to create an
implementation for
* @return Method[] An array of [EMAIL PROTECTED]
org.apache.bcel.classfile.Method Method}
* instances representing the interface
implementation.
* @throws IllegalArgumentException If <code>interfaceToImplement</code> is
<code>null</code>
* or does not represent an interface
* @throws IllegalStateException If this instance has not been initialized
*/
- public Method[] createImplementation( final JavaClass interfaceToImplement )
+ public Method[] createImplementation( final JavaClass[] interfacesToImplement )
throws Exception
{
- if ( interfaceToImplement == null )
+ if ( interfacesToImplement == null )
{
final String message = "Interface to implement must not be <null>.";
throw new IllegalArgumentException( message );
}
- if ( !interfaceToImplement.isInterface() )
- {
- final String message =
- "Supplied JavaClass parameter is not an interface.";
- throw new IllegalArgumentException( message );
- }
if ( !isInitialized() )
{
final String message =
"BCELInterfaceImplementationGenerator is not initialized.";
throw new IllegalStateException( message );
}
+ final Set gmList = new HashSet();
- final Method[] interfaceMethods = extractMethods( interfaceToImplement );
- final List gmList = new ArrayList();
+ final MethodDesc[] interfaceMethods = extractMethods( interfacesToImplement
);
for ( int i = 0; i < interfaceMethods.length; ++i )
{
- final Method im = interfaceMethods[i];
+ final MethodDesc im = interfaceMethods[i];
// Skip <clinit> method ...
- if ( im.getName().equals( "<clinit>" ) )
+ if ( im.name.equals( "<clinit>" ) )
{
continue;
}
- // Extract exception names ...
- final ExceptionTable exTable = im.getExceptionTable();
- final String[] exceptionNames = ( exTable == null ? new String[]{
- }
- : exTable.getExceptionNames() );
final Method generatedMethod =
- createMethodWrapper(
- im.getName(),
- im.getReturnType(),
- im.getArgumentTypes(),
- exceptionNames );
+ createMethodWrapper( im );
gmList.add( generatedMethod );
}
@@ -564,37 +572,37 @@
* declared in the supplied [EMAIL PROTECTED]
org.apache.bcel.classfile.JavaClass JavaClass}
* instance. This instance is supposed to represent an interface.
*
- * @param interfaceToImplement The [EMAIL PROTECTED]
org.apache.bcel.classfile.JavaClass JavaClass}
- * instance representing the interface we are
asking for
+ * @param interfacesToImplement The [EMAIL PROTECTED]
org.apache.bcel.classfile.JavaClass JavaClass}
+ * instances representing the interfaces we are
asking for
* its methods.
- * @return Method[] The array of [EMAIL PROTECTED]
org.apache.bcel.classfile.Method Method}s
+ * @return MethodDesc[] The array of [EMAIL PROTECTED]
org.apache.bcel.classfile.Method Method}s
* declared by the interface
* @throws IllegalArgumentException If <code>interfaceToImplement</code> does
not represent an interface
* @throws NullPointerException if the <code>interfaceToImplement</code> is
<code>null</code>
*/
- static Method[] extractMethods( final JavaClass interfaceToImplement )
+ static MethodDesc[] extractMethods( final JavaClass interfacesToImplement[] )
throws Exception
{
- if ( interfaceToImplement == null )
+ if ( interfacesToImplement == null )
{
- final String message = "JavaClass parameter must not be <null>.";
+ final String message = "JavaClass[] parameter must not be <null>.";
throw new NullPointerException( message );
}
- if ( !interfaceToImplement.isInterface() )
- {
- final String message = "JavaClass parameter must be an interface";
- throw new IllegalArgumentException( message );
- }
Set methods = new HashSet();
- extractMethods( interfaceToImplement, methods );
- JavaClass[] interfaces = interfaceToImplement.getInterfaces();
- for ( int i = 0; i < interfaces.length; i++ )
+ for (int x = 0; x < interfacesToImplement.length; x++)
{
- extractMethods( interfaces[i], methods );
+ JavaClass iface = interfacesToImplement[x];
+ if ( !iface.isInterface() )
+ {
+ final String message = "JavaClass parameter must be an interface";
+ throw new IllegalArgumentException( message );
+ }
+
+ extractMethods( iface, methods );
}
- return (Method[]) methods.toArray( new Method[]{} );
+ return (MethodDesc[]) methods.toArray( new MethodDesc[]{} );
}
private static final void extractMethods( final JavaClass interfaceToImplement,
final Set methods )
@@ -602,7 +610,79 @@
Method[] meth = interfaceToImplement.getMethods();
for ( int m = 0; m < meth.length; m++ )
{
- methods.add( meth[m] );
+ MethodDesc desc = new MethodDesc(meth[m]);
+ methods.add( desc );
+ }
+ }
+
+ private static final class MethodDesc
+ {
+ final String name;
+ final Type returnType;
+ final Type[] parameterTypes;
+ String[] exceptionNames;
+ boolean isFinal;
+ String implementingClassName;
+
+ MethodDesc( Method meth )
+ {
+ this(meth.getName(), meth.getReturnType(), meth.getArgumentTypes(),
+ (null == meth.getExceptionTable() ) ? new String[0] :
meth.getExceptionTable().getExceptionNames());
+ }
+
+ MethodDesc(String name, Type returnType, Type[] parameterTypes, String[]
exceptionNames)
+ {
+ this.name = name;
+ this.returnType = returnType;
+ this.parameterTypes = parameterTypes;
+ this.exceptionNames = exceptionNames;
+ isFinal = false;
+ }
+
+ public boolean equals(Object o)
+ {
+ MethodDesc other = (MethodDesc)o;
+ boolean isEqual = name.equals(other.name);
+ isEqual = isEqual && returnType.equals(other.returnType);
+ isEqual = isEqual && parameterTypes.length ==
other.parameterTypes.length;
+
+ for (int i = 0; isEqual && i < parameterTypes.length; i++)
+ {
+ isEqual = isEqual &&
parameterTypes[i].equals(other.parameterTypes[i]);
+ }
+
+ return isEqual;
+ }
+
+ public int hashCode()
+ {
+ int hash = name.hashCode();
+ hash >>>= 5;
+ hash ^= returnType.hashCode();
+
+ for (int i = 0; i < parameterTypes.length; i++)
+ {
+ hash >>>= parameterTypes.length;
+ hash ^= parameterTypes[i].hashCode();
+ }
+
+ return hash;
+ }
+
+ public String toString()
+ {
+ StringBuffer str = new StringBuffer(returnType.getSignature());
+ str.append( " " ).append( name ).append( "(" );
+
+ for(int i = 0; i < parameterTypes.length; i++)
+ {
+ str.append(parameterTypes[i].toString());
+ if (i > 0) str.append(",");
+ }
+
+ str.append("),").append((isFinal) ? "f" : "v");
+
+ return str.toString();
}
}
}
1.12 +5 -9
avalon/fortress/container/src/impl/org/apache/avalon/fortress/impl/factory/BCELWrapperGenerator.java
Index: BCELWrapperGenerator.java
===================================================================
RCS file:
/home/cvs/avalon/fortress/container/src/impl/org/apache/avalon/fortress/impl/factory/BCELWrapperGenerator.java,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- BCELWrapperGenerator.java 6 Jun 2003 00:35:03 -0000 1.11
+++ BCELWrapperGenerator.java 10 Sep 2003 16:57:06 -0000 1.12
@@ -216,7 +216,7 @@
public BCELWrapperGenerator()
{
m_codeGenerator = new BCELCodeGenerator();
- ClassLoader contextClassLoader =
+ ClassLoader contextClassLoader =
Thread.currentThread().getContextClassLoader();
m_repository = new ClassLoaderRepository( contextClassLoader );
m_bcelClassLoader =
@@ -358,15 +358,11 @@
m_codeGenerator.createWrappedClassAccessor() );
// Implement interfaces
- Method[] interfaceMethods;
- for ( int i = 0; i < interfacesToImplement.length; ++i )
+ Method[] interfaceMethods = m_codeGenerator.createImplementation(
interfacesToImplement );
+
+ for ( int j = 0; j < interfaceMethods.length; ++j )
{
- interfaceMethods =
- m_codeGenerator.createImplementation( interfacesToImplement[i] );
- for ( int j = 0; j < interfaceMethods.length; ++j )
- {
- m_classGenerator.addMethod( interfaceMethods[j] );
- }
+ m_classGenerator.addMethod( interfaceMethods[j] );
}
return m_classGenerator.getJavaClass().getBytes();
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]