jdk代理和cglib代理源代码之我见
阅读原文时间:2023年07月11日阅读:1

以前值是读过一遍jdk和cglib的代理,时间长了,都忘记入口在哪里了,值是记得其中的一些重点了,今天写一篇博客,当作是笔记。和以前一样,关键代码,我会用红色标记出来。

首先,先列出我的jdk代理对象和测试代码:

package com.example.gof.proxy;

/**
* 买车接口
*/
public interface BuyCard {
void buycard();
}

package com.example.gof.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class BuyCardDynamicProxy implements InvocationHandler {
private Object object;

public BuyCardDynamicProxy(final Object object) {  
    this.object = object;  
}

/\*\*  
 \*  代理回调的方法,反编译后可以看到调用的是这段代码:super.h.invoke(this, m3, null);  
 \*  m3 = Class.forName("com.example.gof.proxy.BuyCard").getMethod("buycard", new Class\[0\]);  
 \* @param proxy 代理  
 \* @param method  代理调用的而方法  
 \* @param args 调用的方法的参数  
 \* @return  
 \* @throws Throwable  
 \*/  
@Override  
public Object invoke(Object proxy, Method method, Object\[\] args) throws Throwable {  
    System.out.println("动态代理,买车前");  
    Object res= method.invoke(object,args);  
    System.out.println("动态代理,洗刷刷");  
    return res;  
}  

}

package com.example.gof.proxy;

import com.example.gof.proxy.impl.BuyCardImpl;
import sun.misc.ProxyGenerator;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Proxy;

public class TestBuyCardDynamicProxy {
public static void main(String[] args) throws IOException {
BuyCard buyCard = new BuyCardImpl();
BuyCard buyCardProxy = (BuyCard) Proxy.newProxyInstance(BuyCard.class.getClassLoader(),
new Class[]{BuyCard.class}, new BuyCardDynamicProxy(buyCard));
buyCardProxy.buycard();

//下面这段是用于生成字节码分析的
// byte[] classFile= ProxyGenerator.generateProxyClass("$Proxy", new Class[]{BuyCard.class});
// File file=new File("D:\\java\\GoF\\src\\main\\java\\com\\example\\gof\\proxy/$Proxy.class");
// FileOutputStream os=new FileOutputStream(file);
// os.write(classFile);
// os.flush();
// os.close();

}  

}

跟踪进去,查看 Proxy.newProxyInstance(BuyCard.class.getClassLoader() 这个方法,代码如下:

/**
* Returns an instance of a proxy class for the specified interfaces
* that dispatches method invocations to the specified invocation
* handler.
* 返回一个代理类实例,用于调用响应的接口方法
*

{@code Proxy.newProxyInstance} throws
* {@code IllegalArgumentException} for the same reasons that
* {@code Proxy.getProxyClass} does.
*
* @param loader the class loader to define the proxy class
* @param interfaces the list of interfaces for the proxy class
* to implement
* @param h the invocation handler to dispatch method invocations to
* @return a proxy instance with the specified invocation handler of a
* proxy class that is defined by the specified class loader
* and that implements the specified interfaces
* @throws IllegalArgumentException if any of the restrictions on the
* parameters that may be passed to {@code getProxyClass}
* are violated
* @throws SecurityException if a security manager, s, is present
* and any of the following conditions is met:
*

    *
  • the given {@code loader} is {@code null} and * the caller's class loader is not {@code null} and the * invocation of {@link SecurityManager#checkPermission * s.checkPermission} with * {@code RuntimePermission("getClassLoader")} permission * denies access;
  • *
  • for each proxy interface, {@code intf}, * the caller's class loader is not the same as or an * ancestor of the class loader for {@code intf} and * invocation of {@link SecurityManager#checkPackageAccess * s.checkPackageAccess()} denies access to {@code intf};
  • *
  • any of the given proxy interfaces is non-public and the * caller class is not in the same {@linkplain Package runtime package} * as the non-public interface and the invocation of * {@link SecurityManager#checkPermission s.checkPermission} with * {@code ReflectPermission("newProxyInPackage.{package name}")} * permission denies access.
  • *

* @throws NullPointerException if the {@code interfaces} array
* argument or any of its elements are {@code null}, or
* if the invocation handler, {@code h}, is
* {@code null}
*/
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);

    final Class<?>\[\] intfs = interfaces.clone();  
    final SecurityManager sm = System.getSecurityManager();  
    if (sm != null) {  
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);  
    }

    /\*  
     \* Look up or generate the designated proxy class.  
     \* 查找或者生成一个代理对象  
     \*/  
    Class<?> cl = getProxyClass0(loader, intfs);

    /\*  
     \* Invoke its constructor with the designated invocation handler.  
     \*/  
    try {  
        if (sm != null) {  
            checkNewProxyPermission(Reflection.getCallerClass(), cl);  
        }

        final Constructor<?> cons = cl.getConstructor(constructorParams);  
        final InvocationHandler ih = h;  
        if (!Modifier.isPublic(cl.getModifiers())) {  
            AccessController.doPrivileged(new PrivilegedAction<Void>() {  
                public Void run() {  
                    cons.setAccessible(true);  
                    return null;  
                }  
            });  
        }  
        return cons.newInstance(new Object\[\]{h});  
    } catch (IllegalAccessException|InstantiationException e) {  
        throw new InternalError(e.toString(), e);  
    } catch (InvocationTargetException e) {  
        Throwable t = e.getCause();  
        if (t instanceof RuntimeException) {  
            throw (RuntimeException) t;  
        } else {  
            throw new InternalError(t.toString(), t);  
        }  
    } catch (NoSuchMethodException e) {  
        throw new InternalError(e.toString(), e);  
    }  
}

/\*\*  
 \* a cache of proxy classes  
 \*/  
private static final WeakCache<ClassLoader, Class<?>\[\], Class<?>>  
    proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); 

/\*\*  
 \* Generate a proxy class.  Must call the checkProxyAccess method  
 \* to perform permission checks before calling this.  
 \*/  
private static Class<?> getProxyClass0(ClassLoader loader,  
                                       Class<?>... interfaces) {  
    if (interfaces.length > 65535) {  
        throw new IllegalArgumentException("interface limit exceeded");  
    }

    // If the proxy class defined by the given loader implementing  
    // the given interfaces exists, this will simply return the cached copy;  
    // otherwise, it will create the proxy class via the ProxyClassFactory  
    return proxyClassCache.get(loader, interfaces);  
}

上面这个代码当初看了很久,怎么到proxyClassCache.get(loader, interfaces); 就已经生成了代理对象呢。后来百度下,才知道proxyClassCache9 这个对象调用构造参数时候,就生成了二进制文件,核心代码也在这里。继续往下看

/\*\*  
 \* A factory function that generates, defines and returns the proxy class given  
 \* the ClassLoader and array of interfaces.  
 \* 一个工厂函数,它生成、定义并返回给定类加载器和接口数组的代理类。  
 \*/  
private static final class ProxyClassFactory  
    implements BiFunction<ClassLoader, Class<?>\[\], Class<?>>  
{  
    // prefix for all proxy class names  
    private static final String proxyClassNamePrefix = "$Proxy";

    // next number to use for generation of unique proxy class names  
    private static final AtomicLong nextUniqueNumber = new AtomicLong();

    @Override  
    public Class<?> apply(ClassLoader loader, Class<?>\[\] interfaces) {

        Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);  
        for (Class<?> intf : interfaces) {  
            /\*  
             \* Verify that the class loader resolves the name of this  
             \* interface to the same Class object.  
             \*/  
            Class<?> interfaceClass = null;  
            try {  
                interfaceClass = Class.forName(intf.getName(), false, loader);  
            } catch (ClassNotFoundException e) {  
            }  
            if (interfaceClass != intf) {  
                throw new IllegalArgumentException(  
                    intf + " is not visible from class loader");  
            }  
            /\*  
             \* Verify that the Class object actually represents an  
             \* interface.  
             \*/  
            if (!interfaceClass.isInterface()) {  
                throw new IllegalArgumentException(  
                    interfaceClass.getName() + " is not an interface");  
            }  
            /\*  
             \* Verify that this interface is not a duplicate.  
             \*/  
            if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {  
                throw new IllegalArgumentException(  
                    "repeated interface: " + interfaceClass.getName());  
            }  
        }

        String proxyPkg = null;     // package to define proxy class in  
        int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

        /\*  
         \* Record the package of a non-public proxy interface so that the  
         \* proxy class will be defined in the same package.  Verify that  
         \* all non-public proxy interfaces are in the same package.  
         \*/  
        for (Class<?> intf : interfaces) {  
            int flags = intf.getModifiers();  
            if (!Modifier.isPublic(flags)) {  
                accessFlags = Modifier.FINAL;  
                String name = intf.getName();  
                int n = name.lastIndexOf('.');  
                String pkg = ((n == -1) ? "" : name.substring(0, n + 1));  
                if (proxyPkg == null) {  
                    proxyPkg = pkg;  
                } else if (!pkg.equals(proxyPkg)) {  
                    throw new IllegalArgumentException(  
                        "non-public interfaces from different packages");  
                }  
            }  
        }

        if (proxyPkg == null) {  
            // if no non-public proxy interfaces, use com.sun.proxy package  
            proxyPkg = ReflectUtil.PROXY\_PACKAGE + ".";  
        }

        /\*  
         \* Choose a name for the proxy class to generate.  
         \*/  
        long num = nextUniqueNumber.getAndIncrement();  
        String proxyName = proxyPkg + proxyClassNamePrefix + num;

        /\*  
         \* Generate the specified proxy class.  
         \* 生成代理对象  
         \*/  
        byte\[\] proxyClassFile = ProxyGenerator.generateProxyClass(       //生成二进制字节码  
            proxyName, interfaces, accessFlags);  
        try {  
            //加载到jvm里,返回代理对象  
            return defineClass0(loader, proxyName,  
                                proxyClassFile, 0, proxyClassFile.length);  
        } catch (ClassFormatError e) {  
            /\*  
             \* A ClassFormatError here means that (barring bugs in the  
             \* proxy class generation code) there was some other  
             \* invalid aspect of the arguments supplied to the proxy  
             \* class creation (such as virtual machine limitations  
             \* exceeded).  
             \*/  
            throw new IllegalArgumentException(e.toString());  
        }  
    }  
}

继续跟进生成二进制字节码的方法:ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags)

public static byte[] generateProxyClass(final String var0, Class[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
final byte[] var4 = var3.generateClassFile();
if (saveGeneratedFiles) {
AccessController.doPrivileged(new PrivilegedAction() {
public Void run() {
try {
int var1 = var0.lastIndexOf(46);
Path var2;
if (var1 > 0) {
Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
Files.createDirectories(var3);
var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
} else {
var2 = Paths.get(var0 + ".class");
}

                    Files.write(var2, var4, new OpenOption\[0\]);  
                    return null;  
                } catch (IOException var4x) {  
                    throw new InternalError("I/O exception saving generated file: " + var4x);  
                }  
            }  
        });  
    }

    return var4;  
}

由上面可以看见,核心代码,就是生成了二进制字节码文件Files.write(var2, var4, new OpenOption[0]);

为什么我们看不见呢,那是因为被删除了,可以手动生成这个二进制文件(.class后缀的),也就是上面的那段测试代码的例子。

下面是二进制字节码的文件内容:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import com.example.gof.proxy.BuyCard;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy extends Proxy implements BuyCard {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;

public $Proxy(InvocationHandler var1) throws  {  
    super(var1);  
}

public final boolean equals(Object var1) throws  {  
    try {  
        return (Boolean)super.h.invoke(this, m1, new Object\[\]{var1});  
    } catch (RuntimeException | Error var3) {  
        throw var3;  
    } catch (Throwable var4) {  
        throw new UndeclaredThrowableException(var4);  
    }  
}

public final String toString() throws  {  
    try {  
        return (String)super.h.invoke(this, m2, (Object\[\])null);  
    } catch (RuntimeException | Error var2) {  
        throw var2;  
    } catch (Throwable var3) {  
        throw new UndeclaredThrowableException(var3);  
    }  
}

public final void buycard() throws  {  
    try {  
        super.h.invoke(this, m3, (Object\[\])null);  
    } catch (RuntimeException | Error var2) {  
        throw var2;  
    } catch (Throwable var3) {  
        throw new UndeclaredThrowableException(var3);  
    }  
}

public final int hashCode() throws  {  
    try {  
        return (Integer)super.h.invoke(this, m0, (Object\[\])null);  
    } catch (RuntimeException | Error var2) {  
        throw var2;  
    } catch (Throwable var3) {  
        throw new UndeclaredThrowableException(var3);  
    }  
}

static {  
    try {  
        m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));  
        m2 = Class.forName("java.lang.Object").getMethod("toString");  
        m3 = Class.forName("com.example.gof.proxy.BuyCard").getMethod("buycard");  
        m0 = Class.forName("java.lang.Object").getMethod("hashCode");  
    } catch (NoSuchMethodException var2) {  
        throw new NoSuchMethodError(var2.getMessage());  
    } catch (ClassNotFoundException var3) {  
        throw new NoClassDefFoundError(var3.getMessage());  
    }  
}  

}

从上面可以看到,除了自定义的buycard() 方法外,还有toString()、equals()、hashCode() 三个方法。这三个方法是Object 的方法,每个接口、类都会从Object继承这三个方法。当调用buycard()的时候,可以看到调用的是super.h.invoke(xxx) 这样调用的。这里的h,就是我们自定义的,继承了InvocationHandler的类:BuyCardDynamicProxy。

至于invoke方式是怎么调用的,在另外一篇博客https://www.cnblogs.com/drafire/p/9637349.html 继续解析

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

下面看下cglib的代码解读,依然是先贴出测试代码

public class BuyCardCglibProxy implements MethodInterceptor {
private Object target;

public Object getInstance(final Object target) {  
    this.target = target;  
    Enhancer enhancer=new Enhancer();  
    enhancer.setSuperclass(target.getClass());  
    enhancer.setCallback(this);  
    return enhancer.create();  
}

@Override  
public Object intercept(Object o, Method method, Object\[\] objects, MethodProxy methodProxy) throws Throwable {  
    System.out.println("cglib动态代理前");  
    //这里使用的是methodProxy.invokeSuper,而不是method.invoke  
    //代理类调用父类的方法  
    Object res= methodProxy.invokeSuper(o,objects);  
    System.out.println("cglib动态代理后");  
    return res;  
}  

}

package com.example.gof.proxy;

import com.example.gof.proxy.impl.BuyCardImpl;
import org.springframework.cglib.core.DebuggingClassWriter;

public class TestBuyCardCglibProxy {
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, TestBuyCardCglibProxy.class.getClass().getResource("/").getPath() );
BuyCard buyCard=new BuyCardImpl();
BuyCardCglibProxy proxy=new BuyCardCglibProxy();
BuyCardImpl impl= (BuyCardImpl)proxy.getInstance(buyCard);
impl.buycard();
}
}

关键代码在:enhancer.create() 这个方法,跟踪进去,代码如下:

public Object create() {
this.classOnly = false;
this.argumentTypes = null;
return this.createHelper();
}

private Object createHelper() {
this.preValidate();
Object key = KEY_FACTORY.newInstance(this.superclass != null ? this.superclass.getName() : null, ReflectUtils.getNames(this.interfaces), this.filter == ALL_ZERO ? null : new WeakCacheKey(this.filter), this.callbackTypes, this.useFactory, this.interceptDuringConstruction, this.serialVersionUID);
this.currentKey = key;
Object result = super.create(key);
return result;
}

protected Object create(Object key) {
try {
ClassLoader loader = this.getClassLoader(); //获取加载器
Map cache = CACHE;
//从缓存中读取
AbstractClassGenerator.ClassLoaderData data = (AbstractClassGenerator.ClassLoaderData)cache.get(loader);
if (data == null) { //如果缓存没有对应的数据
Class var5 = AbstractClassGenerator.class;
synchronized(AbstractClassGenerator.class) {
cache = CACHE;
data = (AbstractClassGenerator.ClassLoaderData)cache.get(loader);
if (data == null) {
Map newCache = new WeakHashMap(cache);
data = new AbstractClassGenerator.ClassLoaderData(loader); //生成二进制字节码
newCache.put(loader, data);
CACHE = newCache;
}
}
}

        this.key = key;  
        Object obj = data.get(this, this.getUseCache());  
        //生成代理对象  
        return obj instanceof Class ? this.firstInstance((Class)obj) : this.nextInstance(obj);  
    } catch (RuntimeException var9) {  
        throw var9;  
    } catch (Error var10) {  
        throw var10;  
    } catch (Exception var11) {  
        throw new CodeGenerationException(var11);  
    }  
}

public ClassLoaderData(ClassLoader classLoader) {
if (classLoader == null) {
throw new IllegalArgumentException("classLoader == null is not yet supported");
} else {
this.classLoader = new WeakReference(classLoader);
Function load = new Function() {
public Object apply(AbstractClassGenerator gen) {
Class klass = gen.generate(ClassLoaderData.this); //核心代码
return gen.wrapCachedClass(klass);
}
};
this.generatedClasses = new LoadingCache(GET_KEY, load);
}
}

protected Class generate(AbstractClassGenerator.ClassLoaderData data) {
Object save = CURRENT.get();
CURRENT.set(this);

    Class var8;  
    try {  
        ClassLoader classLoader = data.getClassLoader();  
        if (classLoader == null) {  
            throw new IllegalStateException("ClassLoader is null while trying to define class " + this.getClassName() + ". It seems that the loader has been expired from a weak reference somehow. Please file an issue at cglib's issue tracker.");  
        }

        String className;  
        synchronized(classLoader) {  
            className = this.generateClassName(data.getUniqueNamePredicate());  
            data.reserveName(className);  
            this.setClassName(className);  
        }

        Class gen;  
        if (this.attemptLoad) {  
            try {  
                gen = classLoader.loadClass(this.getClassName());  
                Class var25 = gen;  
                return var25;  
            } catch (ClassNotFoundException var20) {  
                ;  
            }  
        }

        byte\[\] b = this.strategy.generate(this);   //核心代码  
        className = ClassNameReader.getClassName(new ClassReader(b));  
        ProtectionDomain protectionDomain = this.getProtectionDomain();  
        synchronized(classLoader) {  
            if (protectionDomain == null) {  
                gen = ReflectUtils.defineClass(className, b, classLoader);  
            } else {  
                gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain);  
            }  
        }

        var8 = gen;  
    } catch (RuntimeException var21) {  
        throw var21;  
    } catch (Error var22) {  
        throw var22;  
    } catch (Exception var23) {  
        throw new CodeGenerationException(var23);  
    } finally {  
        CURRENT.set(save);  
    }

    return var8;  
}

//org\springframework\spring-core\5.0.8.RELEASE\spring-core-5.0.8.RELEASE.jar!\org\springframework\cglib\core\DefaultGeneratorStrategy.class
public byte[] generate(ClassGenerator cg) throws Exception {
DebuggingClassWriter cw = this.getClassVisitor(); //从这里的源代码,可以看出,底层是使用asm包的
this.transform(cg).generateClass(cw);
return this.transform(cw.toByteArray());
}

//org\springframework\spring-core\5.0.8.RELEASE\spring-core-5.0.8.RELEASE.jar!\org\springframework\cglib\core\KeyFactory.class

public void generateClass(ClassVisitor v) {
ClassEmitter ce = new ClassEmitter(v);
Method newInstance = ReflectUtils.findNewInstance(this.keyInterface);
if (!newInstance.getReturnType().equals(Object.class)) {
throw new IllegalArgumentException("newInstance method must return Object");
} else {
Type[] parameterTypes = TypeUtils.getTypes(newInstance.getParameterTypes());
ce.begin_class(46, 1, this.getClassName(), KeyFactory.KEY_FACTORY, new Type[]{Type.getType(this.keyInterface)}, "");
EmitUtils.null_constructor(ce);
EmitUtils.factory_method(ce, ReflectUtils.getSignature(newInstance));
int seed = 0;
CodeEmitter e = ce.begin_method(1, TypeUtils.parseConstructor(parameterTypes), (Type[])null);
e.load_this();
e.super_invoke_constructor();
e.load_this();
List fieldTypeCustomizers = this.getCustomizers(FieldTypeCustomizer.class);

            int i;  
            for(i = 0; i < parameterTypes.length; ++i) {  
                Type parameterType = parameterTypes\[i\];  
                Type fieldType = parameterType;

                Iterator var11;  
                FieldTypeCustomizer customizer;  
                for(var11 = fieldTypeCustomizers.iterator(); var11.hasNext(); fieldType = customizer.getOutType(i, fieldType)) {  
                    customizer = (FieldTypeCustomizer)var11.next();  
                }

                seed += fieldType.hashCode();  
                ce.declare\_field(18, this.getFieldName(i), fieldType, (Object)null);  
                e.dup();  
                e.load\_arg(i);  
                var11 = fieldTypeCustomizers.iterator();

                while(var11.hasNext()) {  
                    customizer = (FieldTypeCustomizer)var11.next();  
                    customizer.customize(e, i, parameterType);  
                }

                e.putfield(this.getFieldName(i));  
            }

            e.return\_value();  
            e.end\_method();  
            e = ce.begin\_method(1, KeyFactory.HASH\_CODE, (Type\[\])null);  
            i = this.constant != 0 ? this.constant : KeyFactory.PRIMES\[Math.abs(seed) % KeyFactory.PRIMES.length\];  
            int hm = this.multiplier != 0 ? this.multiplier : KeyFactory.PRIMES\[Math.abs(seed \* 13) % KeyFactory.PRIMES.length\];  
            e.push(i);

            for(int i = 0; i < parameterTypes.length; ++i) {  
                e.load\_this();  
                e.getfield(this.getFieldName(i));  
                EmitUtils.hash\_code(e, parameterTypes\[i\], hm, this.customizers);  
            }

            e.return\_value();  
            e.end\_method();  
            e = ce.begin\_method(1, KeyFactory.EQUALS, (Type\[\])null);  
            Label fail = e.make\_label();  
            e.load\_arg(0);  
            e.instance\_of\_this();  
            e.if\_jump(153, fail);

            int i;  
            for(i = 0; i < parameterTypes.length; ++i) {  
                e.load\_this();  
                e.getfield(this.getFieldName(i));  
                e.load\_arg(0);  
                e.checkcast\_this();  
                e.getfield(this.getFieldName(i));  
                EmitUtils.not\_equals(e, parameterTypes\[i\], fail, this.customizers);  
            }

            e.push(1);  
            e.return\_value();  
            e.mark(fail);  
            e.push(0);  
            e.return\_value();  
            e.end\_method();  
            e = ce.begin\_method(1, KeyFactory.TO\_STRING, (Type\[\])null);  
            e.new\_instance(Constants.TYPE\_STRING\_BUFFER);  
            e.dup();  
            e.invoke\_constructor(Constants.TYPE\_STRING\_BUFFER);

            for(i = 0; i < parameterTypes.length; ++i) {  
                if (i > 0) {  
                    e.push(", ");  
                    e.invoke\_virtual(Constants.TYPE\_STRING\_BUFFER, KeyFactory.APPEND\_STRING);  
                }

                e.load\_this();  
                e.getfield(this.getFieldName(i));  
                EmitUtils.append\_string(e, parameterTypes\[i\], EmitUtils.DEFAULT\_DELIMITERS, this.customizers);  
            }

            e.invoke\_virtual(Constants.TYPE\_STRING\_BUFFER, KeyFactory.TO\_STRING);  
            e.return\_value();  
            e.end\_method();  
            ce.end\_class();  
        }  
    }