/* * Copyright 2004-2009 the original author or authors. * * 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.compass.core.util.reflection.asm; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import org.compass.core.util.reflection.ReflectionConstructor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; /** * Allows to generate an {@link ReflectionConstructor} implementation based on ASM that does not use * reflection. * * @author kimchy */ public class AsmReflectionConstructorGenerator { final private static String OBJECT_INTERNAL_NAME = Type.getInternalName(Object.class); final private static String[] REFLECTIONCONSTRUCTOR_INTERNAL_NAME = new String[]{Type.getInternalName(ReflectionConstructor.class)}; /** * Allows to generate an {@link ReflectionConstructor} implementation based on ASM that does not use * reflection. */ public static synchronized ReflectionConstructor generateConstructor(Constructor originalCtor) throws NoSuchMethodException { final Class declaringClass = originalCtor.getDeclaringClass(); String ownerClassName = declaringClass.getName(); Constructor[] declaredCtors = declaringClass.getDeclaredConstructors(); int ctorIndex = 0; for (; ctorIndex < declaredCtors.length; ++ctorIndex) { if (declaredCtors[ctorIndex].equals(originalCtor)) break; } String className = ownerClassName + "ConstReflection" + ctorIndex; try { Class definedClass; try {// checks if was already loaded definedClass = declaringClass.getClassLoader().loadClass(className); } catch (ClassNotFoundException e) // need to build a new class { String classInternalName = className.replace('.', '/'); // build internal name for ASM ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(Opcodes.V1_4, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, classInternalName, null, OBJECT_INTERNAL_NAME, REFLECTIONCONSTRUCTOR_INTERNAL_NAME); createConstructor(cw); createNewInstanceMethod(cw, declaringClass); cw.visitEnd(); byte[] b = cw.toByteArray(); definedClass = defineClass(declaringClass.getClassLoader(), className, b); } return (ReflectionConstructor) definedClass.newInstance(); } catch (Exception e) { NoSuchMethodException ex = new NoSuchMethodException("Can't create ASM constructor reflection helper for [" + originalCtor + "]"); ex.initCause(e); throw ex; } } private static void createConstructor(ClassWriter cw) { MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null); mv.visitCode(); mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); } private static void createNewInstanceMethod(ClassWriter cw, Class clz) { MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "newInstance", "()Ljava/lang/Object;", null, null); mv.visitCode(); mv.visitTypeInsn(Opcodes.NEW, Type.getInternalName(clz)); mv.visitInsn(Opcodes.DUP); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(clz), "<init>", "()V"); mv.visitInsn(Opcodes.ARETURN); mv.visitMaxs(2, 1); mv.visitEnd(); } private static Class defineClass(ClassLoader loader, String name, byte[] b) throws Exception { Method defineMethod = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); defineMethod.setAccessible(true); return (Class) defineMethod.invoke(loader, name, b, 0, b.length); } }