/******************************************************************************* * Copyright (c) 2010 Fraunhofer IWU and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Fraunhofer IWU - initial API and implementation *******************************************************************************/ package net.enilink.composition.asm; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.util.CheckClassAdapter; import org.objectweb.asm.util.TraceClassVisitor; import net.enilink.composition.ClassDefiner; import net.enilink.composition.annotations.ParameterTypes; import net.enilink.composition.asm.meta.ClassInfo; /** * Utility methods for the transformation process. */ public class AsmUtils { protected static Map<ClassLoader, Map<String, ClassInfo>> classInfos = new WeakHashMap<ClassLoader, Map<String, ClassInfo>>(); public static ClassInfo getClassInfo(String className, ClassLoader classLoader) throws Exception { Map<String, ClassInfo> infoMap; synchronized (classInfos) { infoMap = classInfos.get(classLoader); if (infoMap == null) { infoMap = new ConcurrentHashMap<String, ClassInfo>(); classInfos.put(classLoader, infoMap); } } ClassInfo classInfo = infoMap.get(className); if (classInfo == null) { ClassReader reader = createClassReader(className, classLoader); classInfo = new ClassInfo(); reader.accept(classInfo, ClassReader.SKIP_FRAMES); infoMap.put(className, classInfo); } return classInfo; } public static ClassReader createClassReader(String className, ClassLoader classLoader) throws ClassNotFoundException { String classFilename = className.replace('.', '/') + ".class"; InputStream inputStream = classLoader .getResourceAsStream(classFilename); try { return new ClassReader(inputStream); } catch (IOException e) { throw new ClassNotFoundException("Class not found: " + className, e); } } public static Class<?> defineExtendedClass(ClassDefiner definer, ExtendedClassNode classNode) { classNode.endClass(); ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); classNode.accept(classWriter); // printClass(classWriter.toByteArray()); verifyClass(classNode, definer, classWriter.toByteArray()); Class<?> newClass = definer.defineClass( classNode.name.replace('/', '.'), classWriter.toByteArray()); return newClass; } protected static void verifyClass(ExtendedClassNode classNode, ClassDefiner definer, byte[] code) { PrintWriter writer = new PrintWriter(System.err); CheckClassAdapter.verify(new ClassReader(code), definer, false, writer); } protected static void printClass(byte[] code) { ClassReader cr = new ClassReader(code); PrintWriter writer = new PrintWriter(System.err); cr.accept(new TraceClassVisitor(writer), 0); } /** * Returns the class with the given name if it can been loaded by the given * class loader. Otherwise the method returns null. * * @param className * the full name of the class * @param classLoader * the class loader to use * @return the class instance or null */ public static Class<?> findClass(String className, ClassLoader classLoader) { try { return classLoader.loadClass(className); } catch (ClassNotFoundException e) { return null; } } public static <T extends Annotation> T findAnnotation( Class<T> annotationClass, Method method) { T annotation = method.getAnnotation(annotationClass); if (annotation != null) { return annotation; } Method superMethod = findInterfaceOrSuperMethod(method, method .getDeclaringClass().getSuperclass(), method .getDeclaringClass().getInterfaces()); if (superMethod != null && !method.equals(superMethod)) { annotation = findAnnotation(annotationClass, superMethod); } return annotation; } public static Method findInterfaceOrSuperMethod(Method method, Class<?> baseClass, Class<?>... interfaces) { String name = method.getName(); Class<?> type = method.getReturnType(); Class<?>[] types = getParameterTypes(method); Method m = findInterfaceMethod(interfaces, name, type, types); if (m != null) { return m; } m = findSuperMethod(baseClass, name, type, types); if (m != null) { return m; } return method; } public static Class<?>[] getParameterTypes(Method m) { if (m.isAnnotationPresent(ParameterTypes.class)) { return m.getAnnotation(ParameterTypes.class).value(); } return m.getParameterTypes(); } private static Method findSuperMethod(Class<?> base, String name, Class<?> type, Class<?>[] types) { if (base == null) return null; try { Method m = base.getDeclaredMethod(name, types); if (m.getReturnType().equals(type)) { return m; } } catch (NoSuchMethodException e) { // continue } Method m = findSuperMethod(base.getSuperclass(), name, type, types); if (m == null) { return null; } return m; } private static Method findInterfaceMethod(Class<?>[] interfaces, String name, Class<?> type, Class<?>[] types) { for (Class<?> face : interfaces) { try { Method m = face.getDeclaredMethod(name, types); if (m.getReturnType().equals(type)) { return m; } } catch (NoSuchMethodException e) { // continue } Class<?>[] faces = face.getInterfaces(); Method m = findInterfaceMethod(faces, name, type, types); if (m != null) { return m; } } return null; } }