/* * Copyright (c) 2007 Mockito contributors * This program is made available under the terms of the MIT License. */ package org.powermock.api.mockito.repackaged.cglib.reflect; import org.powermock.api.mockito.repackaged.asm.ClassVisitor; import org.powermock.api.mockito.repackaged.asm.Type; import org.powermock.api.mockito.repackaged.cglib.core.AbstractClassGenerator; import org.powermock.api.mockito.repackaged.cglib.core.Constants; import org.powermock.api.mockito.repackaged.cglib.core.ReflectUtils; import org.powermock.api.mockito.repackaged.cglib.core.Signature; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; abstract public class FastClass { private Class type; protected FastClass() { throw new Error("Using the FastClass empty constructor--please report to the cglib-devel mailing list"); } protected FastClass(Class type) { this.type = type; } public static FastClass create(Class type) { return create(type.getClassLoader(),type); } public static FastClass create(ClassLoader loader, Class type) { Generator gen = new Generator(); gen.setType(type); gen.setClassLoader(loader); return gen.create(); } protected static String getSignatureWithoutReturnType(String name, Class[] parameterTypes) { StringBuilder sb = new StringBuilder(); sb.append(name); sb.append('('); for (int i = 0; i < parameterTypes.length; i++) { sb.append(Type.getDescriptor(parameterTypes[i])); } sb.append(')'); return sb.toString(); } public Object invoke(String name, Class[] parameterTypes, Object obj, Object[] args) throws InvocationTargetException { return invoke(getIndex(name, parameterTypes), obj, args); } public Object newInstance() throws InvocationTargetException { return newInstance(getIndex(Constants.EMPTY_CLASS_ARRAY), null); } public Object newInstance(Class[] parameterTypes, Object[] args) throws InvocationTargetException { return newInstance(getIndex(parameterTypes), args); } public FastMethod getMethod(Method method) { return new FastMethod(this, method); } public FastConstructor getConstructor(Constructor constructor) { return new FastConstructor(this, constructor); } public FastMethod getMethod(String name, Class[] parameterTypes) { try { return getMethod(type.getMethod(name, parameterTypes)); } catch (NoSuchMethodException e) { throw new NoSuchMethodError(e.getMessage()); } } public FastConstructor getConstructor(Class[] parameterTypes) { try { return getConstructor(type.getConstructor(parameterTypes)); } catch (NoSuchMethodException e) { throw new NoSuchMethodError(e.getMessage()); } } public String getName() { return type.getName(); } public Class getJavaClass() { return type; } public String toString() { return type.toString(); } public int hashCode() { return type.hashCode(); } public boolean equals(Object o) { if (o == null || !(o instanceof FastClass)) { return false; } return type.equals(((FastClass)o).type); } /** * Return the index of the matching method. The index may be used * later to invoke the method with less overhead. If more than one * method matches (i.e. they differ by return type only), one is * chosen arbitrarily. * @see #invoke(int, Object, Object[]) * @param name the method name * @param parameterTypes the parameter array * @return the index, or <code>-1</code> if none is found. */ abstract public int getIndex(String name, Class[] parameterTypes); /** * Return the index of the matching constructor. The index may be used * later to create a new instance with less overhead. * @see #newInstance(int, Object[]) * @param parameterTypes the parameter array * @return the constructor index, or <code>-1</code> if none is found. */ abstract public int getIndex(Class[] parameterTypes); /** * Invoke the method with the specified index. * @see getIndex(name, Class[]) * @param index the method index * @param obj the object the underlying method is invoked from * @param args the arguments used for the method call * @throws InvocationTargetException if the underlying method throws an exception */ abstract public Object invoke(int index, Object obj, Object[] args) throws InvocationTargetException; /** * Create a new instance using the specified constructor index and arguments. * @see getIndex(Class[]) * @param index the constructor index * @param args the arguments passed to the constructor * @throws InvocationTargetException if the constructor throws an exception */ abstract public Object newInstance(int index, Object[] args) throws InvocationTargetException; abstract public int getIndex(Signature sig); /** * Returns the maximum method index for this class. */ abstract public int getMaxIndex(); public static class Generator extends AbstractClassGenerator { private static final Source SOURCE = new Source(FastClass.class.getName()); private Class type; public Generator() { super(SOURCE); } public void setType(Class type) { this.type = type; } public FastClass create() { setNamePrefix(type.getName()); return (FastClass)super.create(type.getName()); } protected ClassLoader getDefaultClassLoader() { return type.getClassLoader(); } public void generateClass(ClassVisitor v) throws Exception { new FastClassEmitter(v, getClassName(), type); } protected Object firstInstance(Class type) { return ReflectUtils.newInstance(type, new Class[]{ Class.class }, new Object[]{ this.type }); } protected Object nextInstance(Object instance) { return instance; } } }