Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
BEGIN LICENSE BLOCK ***** Version: EPL 1.0/GPL 2.0/LGPL 2.1 The contents of this file are subject to the Eclipse Public License Version 1.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.eclipse.org/legal/epl-v10.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyright (C) 2006 Kresten Krab Thorup <krab@gnu.org> Alternatively, the contents of this file may be used under the terms of either of the GNU General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the LGPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of either the GPL or the LGPL, and not to allow others to use your version of this file under the terms of the EPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL or the LGPL. If you do not delete the provisions above, a recipient may use your version of this file under the terms of any one of the EPL, the GPL or the LGPL. END LICENSE BLOCK ***
 
 
 package org.jruby.javasupport.proxy;
 
 import java.util.Map;
 import java.util.Set;
 
 import org.jruby.Ruby;
 import  org.objectweb.asm.ClassVisitor;
 import  org.objectweb.asm.ClassWriter;
 import  org.objectweb.asm.FieldVisitor;
 import  org.objectweb.asm.Label;
 import  org.objectweb.asm.Opcodes;
 import  org.objectweb.asm.Type;
 import  org.objectweb.asm.commons.GeneratorAdapter;
 
 public class JavaProxyClassFactory {
     private static final Logger LOG = LoggerFactory.getLogger("JavaProxyClassFactory");
 
     private static final Type JAVA_LANG_CLASS_TYPE = Type.getType(Class.class);
 
     private static final Type[] EMPTY_TYPE_ARR = new Type[0];
 
     private static final org.objectweb.asm.commons.Method HELPER_GET_PROXY_CLASS_METHOD = org.objectweb.asm.commons.Method
             .getMethod(JavaProxyClass.class.getName()
                     + " initProxyClass(java.lang.Class)");
 
     private static final org.objectweb.asm.commons.Method CLASS_FORNAME_METHOD = org.objectweb.asm.commons.Method
             .getMethod("java.lang.Class forName(java.lang.String)");
 
     private static final String INVOCATION_HANDLER_FIELD_NAME = "__handler";
 
     private static final String PROXY_CLASS_FIELD_NAME = "__proxy_class";
 
     private static final Class[] EMPTY_CLASS_ARR = new Class[0];
 
     private static final Type INVOCATION_HANDLER_TYPE = Type
             .getType(JavaProxyInvocationHandler.class);
 
     private static final Type PROXY_METHOD_TYPE = Type
             .getType(JavaProxyMethod.class);
 
     private static final Type PROXY_CLASS_TYPE = Type
             .getType(JavaProxyClass.class);
 
     private static final org.objectweb.asm.commons.Method INVOCATION_HANDLER_INVOKE_METHOD = org.objectweb.asm.commons.Method
             .getMethod("java.lang.Object invoke(java.lang.Object, "
                     + .getClassName()
                     + ", java.lang.Object[])");
 
     private static final Type PROXY_HELPER_TYPE = Type
             .getType(InternalJavaProxyHelper.class);
 
     private static final org.objectweb.asm.commons.Method PROXY_HELPER_GET_METHOD = org.objectweb.asm.commons.Method
             .getMethod(.getClassName() + " initProxyMethod("
                     + JavaProxyClass.class.getName()
                     + ",java.lang.String,java.lang.String,boolean)");
    private static final Type JAVA_PROXY_TYPE = Type
            .getType(InternalJavaProxy.class);
    private static int counter;
    private static Method defineClass_method// statically initialized below
    
    public static final String PROXY_CLASS_FACTORY = ..load();    
    private static synchronized int nextId() {
        return ++;
    }
    
    public static JavaProxyClassFactory createFactory() {
        JavaProxyClassFactory factory = null;
        if ( != null) {
            try {
                Class clazz = Class.forName();
                Object instance = clazz.newInstance();
                if (instance instanceof JavaProxyClassFactory) {
                    factory = (JavaProxyClassFactoryinstance;
                    .info("Created proxy class factory: " + factory);
                } else {
                    .error("Invalid proxy class factory: " + instance);
                }
            } catch (ClassNotFoundException e) {
                .error("ClassNotFoundException creating proxy class factory: " + e);
            } catch (InstantiationException e) {
                .error("InstantiationException creating proxy class factory: " + e);
            } catch (IllegalAccessException e) {
                .error("IllegalAccessException creating proxy class factory: " + e);
            }
        }
        
        if (factory == nullfactory = new JavaProxyClassFactory();
        
        return factory;
    }
    
    public JavaProxyClass newProxyClass(Ruby runtimeClassLoader loader,
            String targetClassNameClass superClassClass[] interfacesSet names)
            throws InvocationTargetException {
        if (loader == nullloader = JavaProxyClassFactory.class.getClassLoader();
        if (superClass == nullsuperClass = Object.class;
        if (interfaces == nullinterfaces = ;
        Set key = new HashSet();
        key.add(superClass);
        for (int i = 0; i < interfaces.lengthi++) {
            key.add(interfaces[i]);
        }
        // add (potentially) overridden names to the key.
        if (names != nullkey.addAll(names);
        Map<Set<?>, JavaProxyClassproxyCache =
                runtime.getJavaSupport().getJavaProxyClassCache();
        JavaProxyClass proxyClass = proxyCache.get(key);
        if (proxyClass == null) {
            if (targetClassName == null) {
                // We always prepend an org.jruby.proxy package to the beginning
                // because java and javax packages are protected and signed
                // jars prevent us generating new classes with those package
                // names. See JRUBY-2439.
                String pkg = proxyPackageName(superClass);
                String fullName = superClass.getName();
                int ix = fullName.lastIndexOf('.');
                String cName = fullName;
                if(ix != -1) {
                    cName = fullName.substring(ix+1);
                }
                targetClassName = pkg + "." + cName + "$Proxy" + nextId();
            }
            validateArgs(runtimetargetClassNamesuperClass);
            Type selfType = Type.getType("L" + toInternalClassName(targetClassName) + ";");
            proxyClass = generate(loadertargetClassNamesuperClass,
                    interfacescollectMethods(superClassinterfacesnames), selfType);
            proxyCache.put(keyproxyClass);
        }
        return proxyClass;
    }
    private JavaProxyClass generate(ClassLoader loaderString targetClassName,
            Class superClassClass[] interfaces
            Map<MethodKeyMethodDatamethods, Type selfType) {
        ClassWriter cw = beginProxyClass(targetClassNamesuperClassinterfaces);
        GeneratorAdapter clazzInit = createClassInitializer(selfTypecw);
        generateConstructors(superClassselfTypecw);
        generateGetProxyClass(selfTypecw);
        generateGetInvocationHandler(selfTypecw);
        generateProxyMethods(superClassmethodsselfTypecwclazzInit);
        // finish class initializer
        clazzInit.returnValue();
        clazzInit.endMethod();
        // end class
        cw.visitEnd();
        Class clazz = invokeDefineClass(loaderselfType.getClassName(), cw.toByteArray());
        // trigger class initialization for the class
        try {
            Field proxy_class = clazz.getDeclaredField();
            proxy_class.setAccessible(true);
            return (JavaProxyClassproxy_class.get(clazz);
        } catch (Exception ex) {
            InternalError ie = new InternalError();
            ie.initCause(ex);
            throw ie;
        }
    }
    static {
        AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
                try {
                     = ClassLoader.class.getDeclaredMethod(
                            "defineClass"new Class[] { String.class,
                                    byte[].classint.classint.classProtectionDomain.class });
                } catch (Exception e) {
                    // should not happen!
                    e.printStackTrace();
                    return null;
                }
                .setAccessible(true);
                return null;
            }
        });
    }
    protected Class invokeDefineClass(ClassLoader loaderString classNamebyte[] data) {
        try {
            /* DEBUGGING
             * try { FileOutputStream o = new
             * FileOutputStream(targetClassName.replace( '/', '.') + ".class");
             * o.write(data); o.close(); } catch (IOException ex) {
             * ex.printStackTrace(); }
             */            
            return (Class.invoke(loadernew Object[] { classNamedata,
                            Integer.valueOf(0), Integer.valueOf(data.length), JavaProxyClassFactory.class.getProtectionDomain() });
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        } catch (InvocationTargetException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
    }
    private ClassWriter beginProxyClass(final String className,
            final Class superClassfinal Class[] interfaces) {
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        // start class
        cw.visit(Opcodes.V1_3, Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_SUPER, 
                toInternalClassName(className), /*signature*/ null
                toInternalClassName(superClass), 
                interfaceNamesForProxyClass(interfaces));
        cw.visitField(Opcodes.ACC_PRIVATE, ,
                .getDescriptor(), nullnull).visitEnd();
        cw.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC,
                .getDescriptor(), null,
                null).visitEnd();
        return cw;
    }
    
    private String[] interfaceNamesForProxyClass(final Class[] interfaces) {
        String[] interfaceNames = new String[interfaces.length + 1];
        
        for (int i = 0; i < interfaces.lengthi++) {
            interfaceNames[i] = toInternalClassName(interfaces[i]);
        }
        interfaceNames[interfaces.length] = toInternalClassName(InternalJavaProxy.class);
        
        return interfaceNames;
    }
    private void generateProxyMethods(Class superClass
            Map<MethodKeyMethodDatamethods, Type selfType, ClassVisitor cw,
            GeneratorAdapter clazzInit) {
        for (MethodData mdmethods.values()) {
            Type superClassType = Type.getType(superClass);
            generateProxyMethod(selfTypesuperClassTypecwclazzInitmd);
        }
    }
    private void generateGetInvocationHandler(Type selfType, ClassVisitor cw) {
        // make getter for handler
        GeneratorAdapter gh = new GeneratorAdapter(Opcodes.ACC_PUBLIC,
                new org.objectweb.asm.commons.Method("___getInvocationHandler",
                        ), null,
                cw);
        gh.loadThis();
        gh.getField(selfType);
        gh.returnValue();
        gh.endMethod();
    }
    private void generateGetProxyClass(Type selfType, ClassVisitor cw) {
        // make getter for proxy class
        GeneratorAdapter gpc = new GeneratorAdapter(Opcodes.ACC_PUBLIC,
                new org.objectweb.asm.commons.Method("___getProxyClass",
                        ), null,
                cw);
        gpc.getStatic(selfType);
        gpc.returnValue();
        gpc.endMethod();
    }
    private void generateConstructors(Class superClass, Type selfType, ClassVisitor cw) {
        Constructor[] cons = superClass.getDeclaredConstructors();
        
        for (int i = 0; i < cons.lengthi++) {
            // if the constructor is private, pretend it doesn't exist
            if (Modifier.isPrivate(cons[i].getModifiers())) continue;
            // otherwise, define everything and let some of them fail at invocation
            generateConstructor(selfTypecons[i], cw);
        }
    }
    private GeneratorAdapter createClassInitializer(Type selfType, ClassVisitor cw) {
        GeneratorAdapter clazzInit = new GeneratorAdapter(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC,
                new org.objectweb.asm.commons.Method("<clinit>", Type.VOID_TYPE, ), 
                nullcw);
        clazzInit.visitLdcInsn(selfType.getClassName());
        clazzInit.invokeStatic();
        clazzInit.invokeStatic();
        clazzInit.dup();
        clazzInit.putStatic(selfType);
        
        return clazzInit;
    }
    private void generateProxyMethod(Type selfType, Type superType,
            ClassVisitor cw, GeneratorAdapter clazzInitMethodData md) {
        if (!md.generateProxyMethod()) return;
        org.objectweb.asm.commons.Method m = md.getMethod();
        Type[] ex = toType(md.getExceptions());
        String field_name = "__mth$" + md.getName() + md.scrambledSignature();
        // create static private method field
        FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, 
                field_name.getDescriptor(), nullnull);
        fv.visitEnd();
        clazzInit.dup();
        clazzInit.push(m.getName());
        clazzInit.push(m.getDescriptor());
        clazzInit.push(md.isImplemented());
        clazzInit.invokeStatic();
        clazzInit.putStatic(selfTypefield_name);
        org.objectweb.asm.commons.Method sm = new org.objectweb.asm.commons.Method(
                "__super$" + m.getName(), m.getReturnType(), m
                        .getArgumentTypes());
        //
        // construct the proxy method
        //
        GeneratorAdapter ga = new GeneratorAdapter(Opcodes.ACC_PUBLIC, mnull,
                excw);
        ga.loadThis();
        ga.getField(selfType,
                );
        // if the method is extending something, then we have
        // to test if the handler is initialized...
        if (md.isImplemented()) {
            ga.dup();
            Label ok = ga.newLabel();
            ga.ifNonNull(ok);
            ga.loadThis();
            ga.loadArgs();
            ga.invokeConstructor(superTypem);
            ga.returnValue();
            ga.mark(ok);
        }
        ga.loadThis();
        ga.getStatic(selfTypefield_name);
        if (m.getArgumentTypes().length == 0) {
            // load static empty array
            ga.getStatic("NO_ARGS", Type
                    .getType(Object[].class));
        } else {
            // box arguments
            ga.loadArgArray();
        }
        Label before = ga.mark();
        ga.invokeInterface(,
                );
        Label after = ga.mark();
        ga.unbox(m.getReturnType());
        ga.returnValue();
        // this is a simple rethrow handler
        Label rethrow = ga.mark();
        ga.visitInsn(Opcodes.ATHROW);
        for (int i = 0; i < ex.length; i++) {
            ga.visitTryCatchBlock(beforeafterrethrowex[i].getInternalName());
        }
        ga.visitTryCatchBlock(beforeafterrethrow"java/lang/Error");
        ga.visitTryCatchBlock(beforeafterrethrow"java/lang/RuntimeException");
        Type thr = Type.getType(Throwable.class);
        Label handler = ga.mark();
        Type udt = Type.getType(UndeclaredThrowableException.class);
        int loc = ga.newLocal(thr);
        ga.storeLocal(locthr);
        ga.newInstance(udt);
        ga.dup();
        ga.loadLocal(locthr);
        ga.invokeConstructor(udt, org.objectweb.asm.commons.Method
                .getMethod("void <init>(java.lang.Throwable)"));
        ga.throwException();
        ga.visitTryCatchBlock(beforeafterhandler"java/lang/Throwable");
        ga.endMethod();
        //
        // construct the super-proxy method
        //
        if (md.isImplemented()) {
            GeneratorAdapter ga2 = new GeneratorAdapter(Opcodes.ACC_PUBLIC, sm,
                    nullexcw);
            ga2.loadThis();
            ga2.loadArgs();
            ga2.invokeConstructor(superTypem);
            ga2.returnValue();
            ga2.endMethod();
        }
    }
    private Class[] generateConstructor(Type selfTypeConstructor constructor, ClassVisitor cw) {
        Class[] superConstructorParameterTypes = constructor.getParameterTypes();
        Class[] newConstructorParameterTypes = new Class[superConstructorParameterTypes.length + 1];
        System.arraycopy(superConstructorParameterTypes, 0,
                newConstructorParameterTypes, 0,
                superConstructorParameterTypes.length);
        newConstructorParameterTypes[superConstructorParameterTypes.length] = JavaProxyInvocationHandler.class;
        int access = Opcodes.ACC_PUBLIC;
        String name1 = "<init>";
        String signature = null;
        Class[] superConstructorExceptions = constructor.getExceptionTypes();
        org.objectweb.asm.commons.Method super_m = new org.objectweb.asm.commons.Method(
                name1, Type.VOID_TYPE, toType(superConstructorParameterTypes));
        org.objectweb.asm.commons.Method m = new org.objectweb.asm.commons.Method(
                name1, Type.VOID_TYPE, toType(newConstructorParameterTypes));
        GeneratorAdapter ga = new GeneratorAdapter(accessmsignature,
                toType(superConstructorExceptions), cw);
        ga.loadThis();
        ga.loadArgs(0, superConstructorParameterTypes.length);
        ga.invokeConstructor(Type.getType(constructor.getDeclaringClass()),
                super_m);
        ga.loadThis();
        ga.loadArg(superConstructorParameterTypes.length);
        ga.putField(selfType,
                );
        // do a void return
        ga.returnValue();
        ga.endMethod();
        
        return newConstructorParameterTypes;
    }
    private static String toInternalClassName(Class clazz) {
        return toInternalClassName(clazz.getName());
    }
    private static String toInternalClassName(String name) {
        return name.replace('.''/');
    }
    private static Type[] toType(Class[] parameterTypes) {
        Type[] result = new Type[parameterTypes.length];
        for (int i = 0; i < result.length; i++) {
            result[i] = Type.getType(parameterTypes[i]);
        }
        return result;
    }
    private static Map<MethodKeyMethodDatacollectMethods(Class superClassClass[] interfacesSet names) {
        Map<MethodKeyMethodDatamethods = new HashMap<MethodKeyMethodData>();
        
        HashSet allClasses = new HashSet();
        addClass(allClassesmethodssuperClassnames);
        addInterfaces(allClassesmethodsinterfacesnames);
        
        return methods;
    }
    static class MethodData {
        Set methods = new HashSet();
        final Method mostSpecificMethod;
        final Class[] mostSpecificParameterTypes;
        boolean hasPublicDecl = false;
        MethodData(Method method) {
            this. = method;
             = method.getDeclaringClass().isInterface()
                    || Modifier.isPublic(method.getModifiers());
        }
        public String scrambledSignature() {
            StringBuilder sb = new StringBuilder();
            Class[] parms = getParameterTypes();
            for (int i = 0; i < parms.lengthi++) {
                sb.append('$');
                String name = parms[i].getName();
                name = name.replace('[''1');
                name = name.replace('.''_');
                name = name.replace(';''2');
                sb.append(name);
            }
            return sb.toString();
        }
        public Class getDeclaringClass() {
            return .getDeclaringClass();
        }
        public org.objectweb.asm.commons.Method getMethod() {
            return new org.objectweb.asm.commons.Method(getName(), Type
                    .getType(getReturnType()), getType(getParameterTypes()));
        }
        private Type[] getType(Class[] parameterTypes) {
            Type[] result = new Type[parameterTypes.length];
            for (int i = 0; i < parameterTypes.lengthi++) {
                result[i] = Type.getType(parameterTypes[i]);
            }
            return result;
        }
        private String getName() {
            return .getName();
        }
        private Class[] getParameterTypes() {
            return ;
        }
        public Class[] getExceptions() {
            Set all = new HashSet();
            Iterator it = .iterator();
            while (it.hasNext()) {
                Method m = (Methodit.next();
                Class[] ex = m.getExceptionTypes();
                for (int i = 0; i < ex.lengthi++) {
                    Class exx = ex[i];
                    if (all.contains(exx)) {
                        continue;
                    }
                    boolean add = true;
                    Iterator it2 = all.iterator();
                    while (it2.hasNext()) {
                        Class de = (Classit2.next();
                        if (de.isAssignableFrom(exx)) {
                            add = false;
                            break;
                        } else if (exx.isAssignableFrom(de)) {
                            it2.remove();
                            add = true;
                        }
                    }
                    if (add) {
                        all.add(exx);
                    }
                }
            }
            return (Class[]) all.toArray(new Class[all.size()]);
        }
        public boolean generateProxyMethod() {
            return !isFinal() && !isPrivate();
        }
        public void add(Method method) {
            .add(method);
             |= Modifier.isPublic(method.getModifiers());
        }
        Class getReturnType() {
            return .getReturnType();
        }
        boolean isFinal() {
            if (.getDeclaringClass().isInterface()) {
                return false;
            }
            int mod = .getModifiers();
            return Modifier.isFinal(mod);
        }
        boolean isPrivate() {
            if (.getDeclaringClass().isInterface()) {
                return false;
            }
            int mod = .getModifiers();
            return Modifier.isPrivate(mod);
        }
        boolean isImplemented() {
            if (.getDeclaringClass().isInterface()) {
                return false;
            }
            int mod = .getModifiers();
            return !Modifier.isAbstract(mod);
        }
    }
    static class MethodKey {
        private String name;
        private Class[] arguments;
        MethodKey(Method m) {
            this. = m.getName();
            this. = m.getParameterTypes();
        }
        @Override
        public boolean equals(Object obj) {
            if (obj instanceof MethodKey) {
                MethodKey key = (MethodKeyobj;
                return .equals(key.name)
                        && Arrays.equals(key.arguments);
            }
            return false;
        }
        @Override
        public int hashCode() {
            return .hashCode();
        }
    }
    private static void addInterfaces(Set allClassesMap methods,
            Class[] interfacesSet names) {
        for (int i = 0; i < interfaces.lengthi++) {
            addInterface(allClassesmethodsinterfaces[i], names);
        }
    }
    private static void addInterface(Set allClassesMap methods,
            Class interfazeSet names) {
        if (allClasses.add(interfaze)) {
            addMethods(methodsinterfazenames);
            addInterfaces(allClassesmethodsinterfaze.getInterfaces(), names);
        }
    }
    private static void addMethods(Map methodsClass classOrInterfaceSet names) {
        Method[] mths = classOrInterface.getDeclaredMethods();
        for (int i = 0; i < mths.lengthi++) {
            if (names == null || names.contains(mths[i].getName())) {
                addMethod(methodsmths[i]);
            }
        }
    }
    private static void addMethod(Map methodsMethod method) {
        int acc = method.getModifiers();
        
        if (Modifier.isStatic(acc) || Modifier.isPrivate(acc)) {
            return;
        }
        MethodKey mk = new MethodKey(method);
        MethodData md = (MethodDatamethods.get(mk);
        if (md == null) {
            md = new MethodData(method);
            methods.put(mkmd);
        }
        md.add(method);
    }
    private static void addClass(Set allClassesMap methodsClass clazzSet names) {
        if (allClasses.add(clazz)) {
            addMethods(methodsclazznames);
            Class superClass = clazz.getSuperclass();
            if (superClass != null) {
                addClass(allClassesmethodssuperClassnames);
            }
            addInterfaces(allClassesmethodsclazz.getInterfaces(), names);
        }
    }
    private static void validateArgs(Ruby runtimeString targetClassNameClass superClass) {
        if (Modifier.isFinal(superClass.getModifiers())) {
            throw runtime.newTypeError("cannot extend final class " + superClass.getName());
        }
        if(!hasPublicOrProtectedConstructors(superClass)) {
            throw runtime.newTypeError("class " + superClass.getName() + " doesn't have any public or private constructors");
        }
        String targetPackage = packageName(targetClassName);
        String pkg = targetPackage.replace('.''/');
        if (pkg.startsWith("java")) {
            throw runtime.newTypeError("cannot add classes to package " + pkg);
        }
        Package p = Package.getPackage(pkg);
        if (p != null) {
            if (p.isSealed()) {
                throw runtime.newTypeError("package " + p + " is sealed");
            }
        }
    }
    private static boolean hasPublicOrProtectedConstructors(Class superClass) {
        Constructor[] constructors = superClass.getDeclaredConstructors();
        boolean hasPublicOrProtectedConstructors = false;
        for (Constructor constructor : constructors) {
            if (Modifier.isPublic(constructor.getModifiers())
                    || Modifier.isProtected(constructor.getModifiers())) {
                hasPublicOrProtectedConstructors = true;
            }
        }
        return hasPublicOrProtectedConstructors;
    }
    private static String packageName(String clazzName) {
        int idx = clazzName.lastIndexOf('.');
        if (idx == -1) {
            return "";
        } else {
            return clazzName.substring(0, idx);
        }
    }
    private static String proxyPackageName(Class clazz) {
        String clazzName = clazz.getName();
        int idx = clazzName.lastIndexOf('.');
        if (idx == -1) {
            return "org.jruby.proxy";
        } else {
            return "org.jruby.proxy." + clazzName.substring(0, idx);
        }
    }
New to GrepCode? Check out our FAQ X