You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by jc...@apache.org on 2005/08/31 20:59:51 UTC

svn commit: r265552 - in /jakarta/commons/sandbox/proxy/trunk/src: java/org/apache/commons/proxy/factory/ java/org/apache/commons/proxy/factory/javassist/ test/org/apache/commons/proxy/factory/ test/org/apache/commons/proxy/factory/javassist/ test/org/...

Author: jcarman
Date: Wed Aug 31 11:59:43 2005
New Revision: 265552

URL: http://svn.apache.org/viewcvs?rev=265552&view=rev
Log:
Improved test coverage/refactored JavassistProxyFactory for better maintainability.

Added:
    jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistMethodInvocation.java   (with props)
    jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistUtils.java   (with props)
    jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/util/DuplicateEcho.java   (with props)
Modified:
    jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/AbstractProxyFactory.java
    jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistProxyFactory.java
    jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/AbstractProxyFactoryTestCase.java
    jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/javassist/TestJavassistProxyFactory.java
    jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/util/Echo.java
    jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/util/EchoImpl.java

Modified: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/AbstractProxyFactory.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/AbstractProxyFactory.java?rev=265552&r1=265551&r2=265552&view=diff
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/AbstractProxyFactory.java (original)
+++ jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/AbstractProxyFactory.java Wed Aug 31 11:59:43 2005
@@ -22,6 +22,13 @@
 import org.apache.commons.proxy.DelegateProvider;
 import org.apache.commons.proxy.ProxyFactory;
 
+import java.lang.reflect.Method;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Arrays;
+
 /**
  * A helpful superclass for {@link org.apache.commons.proxy.ProxyFactory} implementations.
  *
@@ -51,5 +58,70 @@
     public Object createDelegatingProxy( DelegateProvider targetProvider, Class... proxyInterfaces )
     {
         return createDelegatingProxy( Thread.currentThread().getContextClassLoader(), targetProvider, proxyInterfaces );
+    }
+
+    protected Method[] getImplementationMethods( Class... proxyInterfaces )
+    {
+        final Set<MethodSignature> signatures = new HashSet<MethodSignature>();
+        final List<Method> resultingMethods = new LinkedList<Method>();
+        for( int i = 0; i < proxyInterfaces.length; i++ )
+        {
+            Class proxyInterface = proxyInterfaces[i];
+            final Method[] methods = proxyInterface.getDeclaredMethods();
+            for( int j = 0; j < methods.length; j++ )
+            {
+                final MethodSignature signature = new MethodSignature( methods[j] );
+                if( !signatures.contains( signature ) )
+                {
+                    signatures.add( signature );
+                    resultingMethods.add( methods[j] );
+                }
+            }
+        }
+        final Method[] results = new Method[resultingMethods.size()];
+        return resultingMethods.toArray( results );
+    }
+
+    private static class MethodSignature
+    {
+        private final String name;
+        private final List<Class> parameterTypes;
+
+        public MethodSignature( Method method )
+        {
+            this.name = method.getName();
+            this.parameterTypes = Arrays.<Class>asList( method.getParameterTypes() );
+        }
+
+        public boolean equals( Object o )
+        {
+            if( this == o )
+            {
+                return true;
+            }
+            if( o == null || getClass() != o.getClass() )
+            {
+                return false;
+            }
+            final MethodSignature that = ( MethodSignature ) o;
+            if( name != null ? !name.equals( that.name ) : that.name != null )
+            {
+                return false;
+            }
+            if( parameterTypes != null ? !parameterTypes.equals( that.parameterTypes ) :
+                that.parameterTypes != null )
+            {
+                return false;
+            }
+            return true;
+        }
+
+        public int hashCode()
+        {
+            int result;
+            result = ( name != null ? name.hashCode() : 0 );
+            result = 29 * result + ( parameterTypes != null ? parameterTypes.hashCode() : 0 );
+            return result;
+        }
     }
 }

Added: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistMethodInvocation.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistMethodInvocation.java?rev=265552&view=auto
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistMethodInvocation.java (added)
+++ jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistMethodInvocation.java Wed Aug 31 11:59:43 2005
@@ -0,0 +1,237 @@
+/* $Id$
+ *
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.proxy.factory.javassist;
+
+import javassist.CannotCompileException;
+import javassist.CtClass;
+import javassist.CtConstructor;
+import javassist.CtMethod;
+import org.aopalliance.intercept.MethodInvocation;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Method;
+import java.util.WeakHashMap;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Arrays;
+
+/**
+ * @author James Carman
+ * @version 1.0
+ */
+public abstract class JavassistMethodInvocation implements MethodInvocation
+{
+    protected final Method method;
+    protected final Object target;
+    protected final Object[] arguments;
+
+    public JavassistMethodInvocation( Method method, Object target, Object[] arguments )
+    {
+        this.method = method;
+        this.target = target;
+        this.arguments = ( arguments == null || arguments.length == 0 ? null : arguments );
+    }
+
+    public Method getMethod()
+    {
+        return method;
+    }
+
+    public Object[] getArguments()
+    {
+        return arguments;
+    }
+
+    public Object getThis()
+    {
+        return target;
+    }
+
+    public AccessibleObject getStaticPart()
+    {
+        return method;
+    }
+
+    private static final WeakHashMap invocationClassCache = new WeakHashMap();
+
+    public synchronized static Class getMethodInvocationClass( ClassLoader classLoader, Method interfaceMethod )
+            throws CannotCompileException
+    {
+        final CacheKey key = new CacheKey( classLoader, interfaceMethod );
+        Class invocationClass = ( Class ) invocationClassCache.get( key );
+        if( invocationClass == null )
+        {
+            final CtClass ctClass = JavassistUtils.createClass(
+                    interfaceMethod.getDeclaringClass().getSimpleName() + "_" + interfaceMethod.getName() +
+                    "_invocation",
+                    JavassistMethodInvocation.class );
+            final CtConstructor constructor = new CtConstructor(
+                    JavassistUtils.resolve( new Class[]{Method.class, Object.class, Object[].class} ), ctClass );
+            constructor.setBody( "{\n\tsuper($$);\n}" );
+            ctClass.addConstructor( constructor );
+            final CtMethod proceedMethod = new CtMethod( JavassistUtils.resolve( Object.class ), "proceed",
+                                                         JavassistUtils.resolve( new Class[0] ), ctClass );
+            final Class[] argumentTypes = interfaceMethod.getParameterTypes();
+            final StringBuffer proceedBody = new StringBuffer( "{\n" );
+            if( !Void.TYPE.equals( interfaceMethod.getReturnType() ) )
+            {
+                proceedBody.append( "\treturn " );
+            }
+            else
+            {
+                proceedBody.append( "\t" );
+            }
+            proceedBody.append( "( (" );
+            proceedBody.append( interfaceMethod.getDeclaringClass().getName() );
+            proceedBody.append( " )target )." );
+            proceedBody.append( interfaceMethod.getName() );
+            proceedBody.append( "(" );
+            for( int i = 0; i < argumentTypes.length; ++i )
+            {
+                proceedBody.append( "(" );
+                proceedBody.append( argumentTypes[i].getName() );
+                proceedBody.append( ")arguments[" );
+                proceedBody.append( i );
+                proceedBody.append( "]" );
+                if( i != argumentTypes.length - 1 )
+                {
+                    proceedBody.append( ", " );
+                }
+            }
+            proceedBody.append( ");\n" );
+            if( Void.TYPE.equals( interfaceMethod.getReturnType() ) )
+            {
+                proceedBody.append( "\treturn null;\n" );
+            }
+            proceedBody.append( "}" );
+            proceedMethod.setBody( proceedBody.toString() );
+            ctClass.addMethod( proceedMethod );
+            invocationClass = ctClass.toClass( classLoader );
+            invocationClassCache.put( key, invocationClass );
+        }
+        return invocationClass;
+    }
+
+    private static class CacheKey
+    {
+        private final ClassLoader classLoader;
+        private final Method method;
+
+        public CacheKey( ClassLoader classLoader, Method method )
+        {
+            this.classLoader = classLoader;
+            this.method = method;
+        }
+
+        public boolean equals( Object o )
+        {
+            if( this == o )
+            {
+                return true;
+            }
+            if( o == null || getClass() != o.getClass() )
+            {
+                return false;
+            }
+            final CacheKey cacheKey = ( CacheKey ) o;
+            if( classLoader != null ? !classLoader.equals( cacheKey.classLoader ) : cacheKey.classLoader != null )
+            {
+                return false;
+            }
+            if( method != null ? !method.equals( cacheKey.method ) : cacheKey.method != null )
+            {
+                return false;
+            }
+            return true;
+        }
+
+        public int hashCode()
+        {
+            int result;
+            result = ( classLoader != null ? classLoader.hashCode() : 0 );
+            result = 29 * result + ( method != null ? method.hashCode() : 0 );
+            return result;
+        }
+    }
+
+    public static Method[] getImplementationMethods( Class... proxyInterfaces )
+    {
+        final Set<MethodSignature> signatures = new HashSet<MethodSignature>();
+        final List<Method> resultingMethods = new LinkedList<Method>();
+        for( int i = 0; i < proxyInterfaces.length; i++ )
+        {
+            Class proxyInterface = proxyInterfaces[i];
+            final Method[] methods = proxyInterface.getDeclaredMethods();
+            for( int j = 0; j < methods.length; j++ )
+            {
+                final MethodSignature signature = new MethodSignature( methods[j] );
+                if( !signatures.contains( signature ) )
+                {
+                    signatures.add( signature );
+                    resultingMethods.add( methods[j] );
+                }
+            }
+        }
+        final Method[] results = new Method[resultingMethods.size()];
+        return resultingMethods.toArray( results );
+    }
+
+    private static class MethodSignature
+    {
+        private final String name;
+        private final List<Class> parameterTypes;
+
+        public MethodSignature( Method method )
+        {
+            this.name = method.getName();
+            this.parameterTypes = Arrays.<Class>asList( method.getParameterTypes() );
+        }
+
+        public boolean equals( Object o )
+        {
+            if( this == o )
+            {
+                return true;
+            }
+            if( o == null || getClass() != o.getClass() )
+            {
+                return false;
+            }
+            final MethodSignature that = ( MethodSignature ) o;
+            if( name != null ? !name.equals( that.name ) : that.name != null )
+            {
+                return false;
+            }
+            if( parameterTypes != null ? !parameterTypes.equals( that.parameterTypes ) :
+                that.parameterTypes != null )
+            {
+                return false;
+            }
+            return true;
+        }
+
+        public int hashCode()
+        {
+            int result;
+            result = ( name != null ? name.hashCode() : 0 );
+            result = 29 * result + ( parameterTypes != null ? parameterTypes.hashCode() : 0 );
+            return result;
+        }
+    }
+}

Propchange: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistMethodInvocation.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistMethodInvocation.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistProxyFactory.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistProxyFactory.java?rev=265552&r1=265551&r2=265552&view=diff
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistProxyFactory.java (original)
+++ jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistProxyFactory.java Wed Aug 31 11:59:43 2005
@@ -17,21 +17,19 @@
 package org.apache.commons.proxy.factory.javassist;
 
 import javassist.CannotCompileException;
-import javassist.ClassPool;
 import javassist.CtClass;
 import javassist.CtConstructor;
-import javassist.CtField;
 import javassist.CtMethod;
-import javassist.NotFoundException;
 import org.aopalliance.intercept.MethodInterceptor;
-import org.aopalliance.intercept.MethodInvocation;
 import org.apache.commons.proxy.DelegateProvider;
-import org.apache.commons.proxy.exception.DelegateProviderException;
 import org.apache.commons.proxy.exception.ProxyFactoryException;
 import org.apache.commons.proxy.factory.AbstractProxyFactory;
 
-import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
 
 /**
  * A <a href="http://www.jboss.org/products/javassist">Javassist</a>-based {@link org.apache.commons.proxy.ProxyFactory}
@@ -42,303 +40,180 @@
  */
 public class JavassistProxyFactory extends AbstractProxyFactory
 {
-    private static int classNumber = 0;
-    private static final ClassPool classPool = ClassPool.getDefault();
-
-    private void addField( Class fieldType, String fieldName, CtClass enclosingClass )
-    {
-        try
-        {
-            enclosingClass.addField( new CtField( resolve( fieldType ), fieldName, enclosingClass ) );
-        }
-        catch( CannotCompileException e )
-        {
-            throw new ProxyFactoryException( "Unable to add field named " + fieldName + " of type " +
-                                             fieldType.getName() + " to class " + enclosingClass.getName(), e );
-        }
-    }
+    private static HashMap<ProxyClassDescriptor, Class> delegatingProxyClassCache = new HashMap<ProxyClassDescriptor, Class>();
+    private static HashMap<ProxyClassDescriptor, Class> interceptingProxyClassCache = new HashMap<ProxyClassDescriptor, Class>();
 
     public Object createInterceptingProxy( ClassLoader classLoader, Object target, MethodInterceptor interceptor,
                                            Class... proxyInterfaces )
     {
-        try
+        synchronized( interceptingProxyClassCache )
         {
-            final CtClass proxyClass = createClass();
-            addField( target.getClass(), "target", proxyClass );
-            addField( MethodInterceptor.class, "interceptor", proxyClass );
-            final CtConstructor proxyConstructor = new CtConstructor(
-                    resolve( new Class[]{target.getClass(), MethodInterceptor.class} ), proxyClass );
-            proxyConstructor.setBody( "{ this.target = $1;\nthis.interceptor = $2; }" );
-            proxyClass.addConstructor( proxyConstructor );
-            for( Class proxyInterface : proxyInterfaces )
-            {
-                proxyClass.addInterface( resolve( proxyInterface ) );
-                final Method[] methods = proxyInterface.getMethods();
-                for( int i = 0; i < methods.length; ++i )
+            final Method[] methods = getImplementationMethods( proxyInterfaces );
+            final ProxyClassDescriptor key = new ProxyClassDescriptor( methods, classLoader );
+            Class clazz = interceptingProxyClassCache.get( key );
+            if( clazz == null )
+            {
+                log.debug( "Generating intercepting proxy class for interfaces " + Arrays.asList( proxyInterfaces ) +
+                           " using class loader " + classLoader + "..." );
+                try
+                {
+                    final CtClass proxyClass = JavassistUtils.createClass();
+                    JavassistUtils.addInterfaces( proxyClass, proxyInterfaces );
+                    JavassistUtils.addField( Method[].class, "methods", proxyClass );
+                    JavassistUtils.addField( Object.class, "target", proxyClass );
+                    JavassistUtils.addField( MethodInterceptor.class, "interceptor", proxyClass );
+                    final CtConstructor proxyConstructor = new CtConstructor(
+                            JavassistUtils.resolve(
+                                    new Class[]{Method[].class, Object.class, MethodInterceptor.class} ),
+                            proxyClass );
+                    proxyConstructor
+                            .setBody( "{\n\tthis.methods = $1;\n\tthis.target = $2;\n\tthis.interceptor = $3; }" );
+                    proxyClass.addConstructor( proxyConstructor );
+                    for( int i = 0; i < methods.length; ++i )
+                    {
+                        final CtMethod method = new CtMethod( JavassistUtils.resolve( methods[i].getReturnType() ),
+                                                              methods[i].getName(),
+                                                              JavassistUtils.resolve( methods[i].getParameterTypes() ),
+                                                              proxyClass );
+                        final Class invocationClass = JavassistMethodInvocation
+                                .getMethodInvocationClass( classLoader, methods[i] );
+                        final String body = "{\n\t return ( $r ) interceptor.invoke( new " + invocationClass.getName() +
+                                            "( methods[" + i + "], target, $args ) );\n }";
+                        method.setBody( body );
+                        proxyClass.addMethod( method );
+                    }
+                    clazz = proxyClass.toClass( classLoader );
+                    interceptingProxyClassCache.put( key, clazz );
+                }
+                catch( CannotCompileException e )
                 {
-                    final CtMethod method = new CtMethod( resolve( methods[i].getReturnType() ), methods[i].getName(),
-                                                          resolve( methods[i].getParameterTypes() ), proxyClass );
-                    final Class invocationClass = createMethodInvocationClass( methods[i], target.getClass(),
-                                                                               classLoader );
-                    final String body = "{\n\t return ( $r ) interceptor.invoke( new " + invocationClass.getName() +
-                                        "( target, $$ ) );\n }";
-                    log.debug( method.getName() + "() method body:\n" + body );
-                    method.setBody( body );
-                    proxyClass.addMethod( method );
+                    throw new ProxyFactoryException( "Could not compile class.", e );
                 }
             }
-            final Class clazz = proxyClass.toClass( classLoader );
-            return clazz.getConstructor( target.getClass(), MethodInterceptor.class )
-                    .newInstance( target, interceptor );
-        }
-        catch( CannotCompileException e )
-        {
-            throw new ProxyFactoryException( "Could not compile class.", e );
-        }
-        catch( NoSuchMethodException e )
-        {
-            throw new ProxyFactoryException( "Could not find constructor in generated proxy class.", e );
-        }
-        catch( Exception e )
-        {
-            throw new ProxyFactoryException( "Unable to instantiate proxy from generated proxy class.", e );
+            try
+            {
+                return clazz.getConstructor( Method[].class, Object.class, MethodInterceptor.class )
+                        .newInstance( methods, target, interceptor );
+            }
+            catch( Exception e )
+            {
+                throw new ProxyFactoryException( "Unable to instantiate proxy class instance.", e );
+
+            }
         }
     }
 
-    private Class createMethodInvocationClass( Method method, Class targetClass, ClassLoader classLoader )
+    public Object createDelegatingProxy( ClassLoader classLoader, DelegateProvider targetProvider,
+                                         Class... proxyInterfaces )
     {
-        try
+        synchronized( delegatingProxyClassCache )
         {
-            final CtClass invocationClass = createClass();
-            invocationClass.addInterface( resolve( MethodInvocation.class ) );
-            addField( method.getDeclaringClass(), "target", invocationClass );
-            addField( Object[].class, "arguments", invocationClass );
-            final Class[] argumentTypes = method.getParameterTypes();
-            final Class[] constructorArgs = new Class[argumentTypes.length + 1];
-            constructorArgs[0] = targetClass;
-            for( int i = 0; i < argumentTypes.length; i++ )
-            {
-                constructorArgs[i + 1] = argumentTypes[i];
-            }
-            final CtConstructor constructor = new CtConstructor( resolve( constructorArgs ), invocationClass );
-            final StringBuffer constructorBody = new StringBuffer( "{\n" );
-            constructorBody.append( "\tthis.target = $1;\n" );
-            if( argumentTypes.length == 0 )
-            {
-                constructorBody.append( "\tthis.arguments = null;\n" );
+            final Method[] methods = getImplementationMethods( proxyInterfaces );
+            final ProxyClassDescriptor key = new ProxyClassDescriptor( methods, classLoader );
+            Class clazz = delegatingProxyClassCache.get( key );
+            if( clazz == null )
+            {
+                log.debug( "Generating delegating proxy class for interfaces " + Arrays.asList( proxyInterfaces ) +
+                           " using class loader " + classLoader + "..." );
+                try
+                {
+                    final CtClass proxyClass = JavassistUtils.createClass();
+                    JavassistUtils.addField( DelegateProvider.class, "provider", proxyClass );
+                    final CtConstructor proxyConstructor = new CtConstructor(
+                            JavassistUtils.resolve( new Class[]{DelegateProvider.class} ),
+                            proxyClass );
+                    proxyConstructor.setBody( "{ this.provider = $1; }" );
+                    proxyClass.addConstructor( proxyConstructor );
+                    addMethods( proxyInterfaces, proxyClass, new DelegatingMethodBodyProvider() );
+                    clazz = proxyClass.toClass( classLoader );
+                    delegatingProxyClassCache.put( key, clazz );
+                }
+                catch( CannotCompileException e )
+                {
+                    throw new ProxyFactoryException( "Could not compile class.", e );
+                }
             }
-            else
+            try
             {
-                constructorBody.append( "\tthis.arguments = new Object[" );
-                constructorBody.append( argumentTypes.length );
-                constructorBody.append( "];\n" );
+                return clazz.getConstructor( DelegateProvider.class ).newInstance( targetProvider );
             }
-            for( int i = 0; i < argumentTypes.length; i++ )
+            catch( Exception e )
             {
-                constructorBody.append( "\tthis.arguments[" );
-                constructorBody.append( i );
-                constructorBody.append( "] = $" );
-                constructorBody.append( i + 2 );
-                constructorBody.append( ";\n" );
+                throw new ProxyFactoryException( "Unable to instantiate proxy from generated proxy class.", e );
             }
-            constructorBody.append( "}" );
-            log.debug( "Constructor body:\n" + constructorBody );
-            constructor.setBody( constructorBody.toString() );
-            invocationClass.addConstructor( constructor );
-            // proceed()...
-            final CtMethod proceedMethod = new CtMethod( resolve( Object.class ), "proceed", new CtClass[0],
-                                                         invocationClass );
-            final String proceedBody = generateProceedBody( method, argumentTypes );
-            log.debug( "Proceed method body:\n" + proceedBody );
-            proceedMethod.setBody( proceedBody.toString() );
-            invocationClass.addMethod( proceedMethod );
-            addGetMethodMethod( invocationClass, argumentTypes, method );
-            addGetArgumentsMethod( invocationClass );
-            addGetStaticPartMethod( invocationClass );
-            addGetThisMethod( invocationClass );
-            return invocationClass.toClass( classLoader );
-        }
-        catch( CannotCompileException e )
-        {
-            throw new ProxyFactoryException( "Could not compile Javassist generated class.", e );
         }
     }
 
-    private void addGetMethodMethod( CtClass invocationClass, Class[] argumentTypes, Method method )
+    private void addMethods( Class[] proxyInterfaces, CtClass proxyClass, MethodBodyProvider methodBodyProvider )
             throws CannotCompileException
     {
-        final CtMethod getMethodMethod = new CtMethod( resolve( Method.class ), "getMethod", resolve( new Class[0] ),
-                                                       invocationClass );
-        final StringBuffer getMethodBody = new StringBuffer();
-        getMethodBody.append( "{\n\tfinal Class[] parameterTypes = new Class[" );
-        getMethodBody.append( argumentTypes.length );
-        getMethodBody.append( "];\n" );
-        for( int i = 0; i < argumentTypes.length; ++i )
+        JavassistUtils.addInterfaces( proxyClass, proxyInterfaces );
+        final Method[] methods = getImplementationMethods( proxyInterfaces );
+        for( int i = 0; i < methods.length; ++i )
         {
-            getMethodBody.append( "\tparameterTypes[" );
-            getMethodBody.append( i );
-            getMethodBody.append( "] = " );
-            getMethodBody.append( argumentTypes[i].getName() );
-            getMethodBody.append( ".class;\n" );
+            final Method method = methods[i];
+            final CtMethod ctMethod = new CtMethod( JavassistUtils.resolve( method.getReturnType() ),
+                                                    method.getName(),
+                                                    JavassistUtils.resolve( method.getParameterTypes() ),
+                                                    proxyClass );
+            ctMethod.setBody( methodBodyProvider.getMethodBody( method ) );
+            proxyClass.addMethod( ctMethod );
         }
-        getMethodBody.append( "\ttry\n\t{\n\t\treturn " );
-        getMethodBody.append( method.getDeclaringClass().getName() );
-        getMethodBody.append( ".class.getMethod(\"" );
-        getMethodBody.append( method.getName() );
-        getMethodBody
-                .append( "\", parameterTypes );\n\t}\n\tcatch( NoSuchMethodException e )\n\t{\n\t\treturn null;\n\t}" );
-        getMethodBody.append( "}" );
-        log.debug( "getMethod() body:\n" + getMethodBody.toString() );
-        getMethodMethod.setBody( getMethodBody.toString() );
-        invocationClass.addMethod( getMethodMethod );
     }
 
-    private void addGetStaticPartMethod( CtClass invocationClass ) throws CannotCompileException
+    private interface MethodBodyProvider
     {
-        final CtMethod getStaticPartMethod = new CtMethod( resolve( AccessibleObject.class ), "getStaticPart",
-                                                           resolve( new Class[0] ), invocationClass );
-        final String getStaticPartBody = "{\n\treturn getMethod();\n}";
-        log.debug( "getStaticPart() body:\n" + getStaticPartBody );
-        getStaticPartMethod.setBody( getStaticPartBody );
-        invocationClass.addMethod( getStaticPartMethod );
+        public String getMethodBody( Method method );
     }
 
-    private void addGetThisMethod( CtClass invocationClass ) throws CannotCompileException
+    private class DelegatingMethodBodyProvider implements MethodBodyProvider
     {
-        final CtMethod getThisMethod = new CtMethod( resolve( Object.class ), "getThis", resolve( new Class[0] ),
-                                                     invocationClass );
-        final String getThisMethodBody = "{\n\treturn target;\n}";
-        log.debug( "getThis() body:\n" + getThisMethodBody );
-        getThisMethod.setBody( getThisMethodBody );
-        invocationClass.addMethod( getThisMethod );
+        public String getMethodBody( Method method )
+        {
+            return "{ return ( $r ) ( ( " + method.getDeclaringClass().getName() + " )provider.getDelegate() )." +
+                   method.getName() + "($$); }";
+        }
     }
 
-    private void addGetArgumentsMethod( CtClass invocationClass ) throws CannotCompileException
+    private static class ProxyClassDescriptor
     {
-        final CtMethod method = new CtMethod( resolve( Object[].class ), "getArguments", resolve( new Class[0] ),
-                                              invocationClass );
-        final String body = "{\n\treturn arguments;\n}";
-        log.debug( "getArguments() body:\n" + body );
-        method.setBody( body );
-        invocationClass.addMethod( method );
-    }
+        private final List<Method> methods;
+        private final ClassLoader classLoader;
 
-    private String generateProceedBody( Method method, Class[] argumentTypes )
-    {
-        final StringBuffer proceedBody = new StringBuffer( "{\n" );
-        if( !Void.TYPE.equals( method.getReturnType() ) )
-        {
-            proceedBody.append( "\treturn " );
-        }
-        else
+        public ProxyClassDescriptor( Method[] methods, ClassLoader classLoader )
         {
-            proceedBody.append( "\t" );
+            this.methods = new ArrayList<Method>( Arrays.asList( methods ) );
+            this.classLoader = classLoader;
         }
-        proceedBody.append( "target." );
-        proceedBody.append( method.getName() );
-        proceedBody.append( "(" );
-        for( int i = 0; i < argumentTypes.length; ++i )
+
+        public boolean equals( Object o )
         {
-            proceedBody.append( "(" );
-            proceedBody.append( argumentTypes[i].getName() );
-            proceedBody.append( ")arguments[" );
-            proceedBody.append( i );
-            proceedBody.append( "]" );
-            if( i != argumentTypes.length - 1 )
+            if( this == o )
             {
-                proceedBody.append( ", " );
+                return true;
             }
-        }
-        proceedBody.append( ");\n" );
-        if( Void.TYPE.equals( method.getReturnType() ) )
-        {
-            proceedBody.append( "\treturn null;\n" );
-        }
-        proceedBody.append( "}" );
-        return proceedBody.toString();
-    }
-
-    public Object createDelegatingProxy( ClassLoader classLoader, DelegateProvider targetProvider,
-                                         Class... proxyInterfaces )
-    {
-        try
-        {
-            final CtClass proxyClass = createClass();
-            final CtField providerField = new CtField( resolve( targetProvider.getClass() ), "provider", proxyClass );
-            proxyClass.addField( providerField );
-            final CtConstructor proxyConstructor = new CtConstructor( resolve( new Class[]{targetProvider.getClass()} ),
-                                                                      proxyClass );
-            proxyConstructor.setBody( "{ this.provider = $1; }" );
-            proxyClass.addConstructor( proxyConstructor );
-            for( Class proxyInterface : proxyInterfaces )
+            if( o == null || getClass() != o.getClass() )
             {
-                proxyClass.addInterface( resolve( proxyInterface ) );
-                final Method[] methods = proxyInterface.getMethods();
-                for( int i = 0; i < methods.length; ++i )
-                {
-                    final CtMethod method = new CtMethod( resolve( methods[i].getReturnType() ), methods[i].getName(),
-                                                          resolve( methods[i].getParameterTypes() ), proxyClass );
-                    method.setBody( "{ return ( $r ) ( ( " + proxyInterface.getName() + " )provider.getDelegate() )." +
-                                    methods[i].getName() + "($$); }" );
-                    proxyClass.addMethod( method );
-                }
+                return false;
             }
-            final Class clazz = proxyClass.toClass( classLoader );
-            return clazz.getConstructor( targetProvider.getClass() ).newInstance( targetProvider );
-        }
-        catch( CannotCompileException e )
-        {
-            throw new ProxyFactoryException( "Could not compile class.", e );
-        }
-        catch( NoSuchMethodException e )
-        {
-            throw new ProxyFactoryException( "Could not find constructor in generated proxy class.", e );
-        }
-        catch( Exception e )
-        {
-            throw new ProxyFactoryException( "Unable to instantiate proxy from generated proxy class.", e );
-        }
-    }
-
-    public static CtClass resolve( Class clazz )
-    {
-        try
-        {
-            return classPool.get( getJavaClassName( clazz ) );
-        }
-        catch( NotFoundException e )
-        {
-            throw new DelegateProviderException(
-                    "Unable to find class " + clazz.getName() + " in default Javassist class pool.", e );
-        }
-    }
-
-    public static CtClass[] resolve( Class[] classes )
-    {
-        final CtClass[] ctClasses = new CtClass[classes.length];
-        for( int i = 0; i < ctClasses.length; ++i )
-        {
-            ctClasses[i] = resolve( classes[i] );
+            final ProxyClassDescriptor that = ( ProxyClassDescriptor ) o;
+            if( classLoader != null ? !classLoader.equals( that.classLoader ) : that.classLoader != null )
+            {
+                return false;
+            }
+            if( methods != null ? !methods.equals( that.methods ) : that.methods != null )
+            {
+                return false;
+            }
+            return true;
         }
-        return ctClasses;
-    }
-
-    public static CtClass createClass()
-    {
-        return createClass( Object.class );
-    }
 
-    public static CtClass createClass( Class superclass )
-    {
-        return classPool.makeClass( "JavassistProxyFactoryGenerated_" + ( ++classNumber ), resolve( superclass ) );
-    }
-
-    public static String getJavaClassName( Class inputClass )
-    {
-        if( inputClass.isArray() )
+        public int hashCode()
         {
-            return getJavaClassName( inputClass.getComponentType() ) + "[]";
+            int result;
+            result = ( methods != null ? methods.hashCode() : 0 );
+            result = 29 * result + ( classLoader != null ? classLoader.hashCode() : 0 );
+            return result;
         }
-        return inputClass.getName();
     }
 }

Added: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistUtils.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistUtils.java?rev=265552&view=auto
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistUtils.java (added)
+++ jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistUtils.java Wed Aug 31 11:59:43 2005
@@ -0,0 +1,105 @@
+/* $Id$
+ *
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.proxy.factory.javassist;
+
+import javassist.CannotCompileException;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.NotFoundException;
+import org.apache.commons.proxy.exception.DelegateProviderException;
+
+/**
+ * @author James Carman
+ * @version 1.0
+ */
+public class JavassistUtils
+{
+    private static int classNumber = 0;
+    private static final ClassPool classPool = ClassPool.getDefault();
+    public static final String DEFAULT_BASE_NAME = "JavassistUtilsGenerated";
+
+    public static void addInterfaces( CtClass ctClass, Class... proxyInterfaces )
+    {
+        for( int i = 0; i < proxyInterfaces.length; i++ )
+        {
+            Class proxyInterface = proxyInterfaces[i];
+            ctClass.addInterface( resolve( proxyInterface ) );
+        }
+    }
+
+    public static void addField( Class fieldType, String fieldName, CtClass enclosingClass ) throws
+                                                                                             CannotCompileException
+    {
+        enclosingClass.addField( new CtField( resolve( fieldType ), fieldName, enclosingClass ) );
+
+    }
+
+    public static CtClass resolve( Class clazz )
+    {
+        try
+        {
+            return classPool.get( getJavaClassName( clazz ) );
+        }
+        catch( NotFoundException e )
+        {
+            throw new DelegateProviderException(
+                    "Unable to find class " + clazz.getName() + " in default Javassist class pool.", e );
+        }
+    }
+
+    public static CtClass[] resolve( Class[] classes )
+    {
+        final CtClass[] ctClasses = new CtClass[classes.length];
+        for( int i = 0; i < ctClasses.length; ++i )
+        {
+            ctClasses[i] = resolve( classes[i] );
+        }
+        return ctClasses;
+    }
+
+    public static CtClass createClass()
+    {
+        return createClass( DEFAULT_BASE_NAME );
+    }
+
+    public static CtClass createClass( Class superclass )
+    {
+        return createClass( DEFAULT_BASE_NAME, superclass );
+    }
+
+    public static CtClass createClass( String baseName )
+    {
+        return createClass( baseName, Object.class );
+    }
+
+    public synchronized static CtClass createClass( String baseName, Class superclass )
+    {
+        return classPool.makeClass( baseName + "_" + classNumber++, resolve( superclass ) );
+    }
+
+    public static String getJavaClassName( Class inputClass )
+    {
+        if( inputClass.isArray() )
+        {
+            return getJavaClassName( inputClass.getComponentType() ) + "[]";
+        }
+        return inputClass.getName();
+    }
+
+
+}

Propchange: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/sandbox/proxy/trunk/src/java/org/apache/commons/proxy/factory/javassist/JavassistUtils.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/AbstractProxyFactoryTestCase.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/AbstractProxyFactoryTestCase.java?rev=265552&r1=265551&r2=265552&view=diff
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/AbstractProxyFactoryTestCase.java (original)
+++ jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/AbstractProxyFactoryTestCase.java Wed Aug 31 11:59:43 2005
@@ -19,14 +19,19 @@
 import org.aopalliance.intercept.MethodInvocation;
 import org.apache.commons.proxy.ProxyFactory;
 import static org.apache.commons.proxy.provider.ProviderUtils.*;
+import org.apache.commons.proxy.provider.ConstantProvider;
 import org.apache.commons.proxy.util.AbstractTestCase;
 import org.apache.commons.proxy.util.Echo;
 import org.apache.commons.proxy.util.EchoImpl;
 import org.apache.commons.proxy.util.SuffixMethodInterceptor;
+import org.apache.commons.proxy.util.DuplicateEcho;
 
 import java.io.IOException;
 import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.List;
+import java.util.LinkedList;
 
 /**
  * @author James Carman
@@ -34,14 +39,23 @@
  */
 public abstract class AbstractProxyFactoryTestCase extends AbstractTestCase
 {
-    private final ProxyFactory factory;
+    protected final ProxyFactory factory;
 
     protected AbstractProxyFactoryTestCase( ProxyFactory factory )
     {
         this.factory = factory;
     }
 
-    public void testCreateProxy()
+    public void testDelegatingProxyInterfaceOrder()
+    {
+        final Echo echo = ( Echo ) factory.createDelegatingProxy( singletonProvider( beanProvider( EchoImpl.class ) ), Echo.class, DuplicateEcho.class );
+        final List expected = new LinkedList( Arrays.asList( Echo.class, DuplicateEcho.class ) );
+        final List actual = new LinkedList( Arrays.asList( echo.getClass().getInterfaces() ) );
+        actual.retainAll( expected );  // Doesn't alter order!
+        assertEquals( expected, actual );
+    }
+
+    public void testCreateDelegatingProxy()
     {
         final Echo echo = ( Echo ) factory.createDelegatingProxy( singletonProvider( beanProvider( EchoImpl.class ) ), Echo.class );
         echo.echo();
@@ -49,6 +63,12 @@
         assertEquals( "ab", echo.echoBack( "a", "b" ) );
     }
 
+    public void testPrimitiveParameter()
+    {
+        final Echo echo = ( Echo ) factory.createDelegatingProxy( singletonProvider( beanProvider( EchoImpl.class ) ), Echo.class );
+        assertEquals( 1, echo.echoBack( 1 ) );
+    }
+
     public void testCreateInterceptorProxy()
     {
         final Echo target = ( Echo ) factory.createDelegatingProxy( singletonProvider( beanProvider( EchoImpl.class ) ), Echo.class );
@@ -80,6 +100,41 @@
         assertEquals( Echo.class.getMethod( "echoBack", String.class, String.class ), tester.method );
     }
 
+    public void testMethodInvocationDuplicateMethods() throws Exception
+    {
+        final MethodInvocationTester tester = new MethodInvocationTester();
+        final EchoImpl target = new EchoImpl();
+        final Echo proxy = ( Echo ) factory.createInterceptingProxy( target, tester, Echo.class, DuplicateEcho.class );
+        proxy.echoBack( "hello" );
+        assertEquals( Echo.class.getMethod( "echoBack", String.class ), tester.method );
+    }
+
+
+    public void testMethodInvocationClassCaching() throws Exception
+    {
+        final MethodInvocationTester tester = new MethodInvocationTester();
+        final EchoImpl target = new EchoImpl();
+        final Echo proxy = ( Echo ) factory.createInterceptingProxy( target, tester, Echo.class );
+        proxy.echoBack( "hello1" );
+        final Class invocationClass1 = tester.invocationClass;
+        proxy.echoBack( "hello2" );
+        assertEquals( invocationClass1, tester.invocationClass );
+    }
+
+    public void testDelegatingProxyClassCaching() throws Exception
+    {
+        final Echo proxy1 = ( Echo ) factory.createDelegatingProxy( constantProvider( new EchoImpl() ), Echo.class );
+        final Echo proxy2 = ( Echo ) factory.createDelegatingProxy( constantProvider( new EchoImpl() ), Echo.class );
+        assertEquals( proxy1.getClass(), proxy2.getClass() );
+    }
+
+    public void testInterceptingProxyClassCaching() throws Exception
+    {
+        final Echo proxy1 = ( Echo ) factory.createInterceptingProxy( new EchoImpl(), new NoOpMethodInterceptor(), Echo.class );
+        final Echo proxy2 = ( Echo ) factory.createInterceptingProxy( new EchoImpl(), new NoOpMethodInterceptor(), Echo.class );
+        assertEquals( proxy1.getClass(), proxy2.getClass() );
+    }
+
     public void testProxyWithCheckedException() throws Exception
     {
         final Echo proxy = ( Echo ) factory.createDelegatingProxy( constantProvider( new EchoImpl() ), Echo.class );
@@ -172,6 +227,7 @@
         private Method method;
         private Object target;
         private AccessibleObject staticPart;
+        private Class invocationClass;
 
         public Object invoke( MethodInvocation methodInvocation ) throws Throwable
         {
@@ -179,6 +235,7 @@
             this.method = methodInvocation.getMethod();
             this.target = methodInvocation.getThis();
             this.staticPart = methodInvocation.getStaticPart();
+            this.invocationClass = methodInvocation.getClass();
             return methodInvocation.proceed();
         }
     }

Modified: jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/javassist/TestJavassistProxyFactory.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/javassist/TestJavassistProxyFactory.java?rev=265552&r1=265551&r2=265552&view=diff
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/javassist/TestJavassistProxyFactory.java (original)
+++ jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/factory/javassist/TestJavassistProxyFactory.java Wed Aug 31 11:59:43 2005
@@ -16,6 +16,12 @@
 package org.apache.commons.proxy.factory.javassist;
 
 import org.apache.commons.proxy.factory.AbstractProxyFactoryTestCase;
+import org.apache.commons.proxy.util.Echo;
+import org.apache.commons.proxy.util.DuplicateEcho;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.LinkedList;
 
 /**
  * @author James Carman

Added: jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/util/DuplicateEcho.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/util/DuplicateEcho.java?rev=265552&view=auto
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/util/DuplicateEcho.java (added)
+++ jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/util/DuplicateEcho.java Wed Aug 31 11:59:43 2005
@@ -0,0 +1,26 @@
+/* $Id$
+ *
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.proxy.util;
+
+/**
+ * @author James Carman
+ * @version 1.0
+ */
+public interface DuplicateEcho
+{
+    public String echoBack( String message );
+}

Propchange: jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/util/DuplicateEcho.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/util/DuplicateEcho.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/util/Echo.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/util/Echo.java?rev=265552&r1=265551&r2=265552&view=diff
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/util/Echo.java (original)
+++ jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/util/Echo.java Wed Aug 31 11:59:43 2005
@@ -25,6 +25,7 @@
 {
     public String echoBack( String message );
     public String echoBack( String message1, String message2 );
+    public int echoBack( int i );
     public void echo();
 
     public void ioException() throws IOException;

Modified: jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/util/EchoImpl.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/util/EchoImpl.java?rev=265552&r1=265551&r2=265552&view=diff
==============================================================================
--- jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/util/EchoImpl.java (original)
+++ jakarta/commons/sandbox/proxy/trunk/src/test/org/apache/commons/proxy/util/EchoImpl.java Wed Aug 31 11:59:43 2005
@@ -21,7 +21,7 @@
  * @author James Carman
  * @version 1.0
  */
-public class EchoImpl implements Echo
+public class EchoImpl implements Echo, DuplicateEcho
 {
     public String echoBack( String message )
     {
@@ -31,6 +31,11 @@
     public String echoBack( String message1, String message2 )
     {
         return message1 + message2;
+    }
+
+    public int echoBack( int i )
+    {
+        return i;
     }
 
     public void echo()



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org