All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sfm.reflect.asm.AsmUtils Maven / Gradle / Ivy

package org.sfm.reflect.asm;

import static org.objectweb.asm.Opcodes.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.sfm.reflect.TypeHelper;
public class AsmUtils {

	public static String toType(final Type target) {
		return toType(TypeHelper.toClass(target));
	}
	public static String toType(final Class target) {
		if (target.isPrimitive()) {
			return primitivesType.get(target);
		}
		return toType(getPublicOrInterfaceClass(target).getName());
	}

	public static String toType(final String name) {
		return name.replace('.', '/');
	}
	
	@SuppressWarnings("serial")
	static final Map, Class> wrappers = new HashMap, Class>() {
		{
			  put(boolean.class, Boolean.class);
		      put(byte.class, Byte.class);
		      put(char.class, Character.class);
		      put(double.class, Double.class);
		      put(float.class, Float.class);
		      put(int.class, Integer.class);
		      put(long.class, Long.class);
		      put(short.class, Short.class);
		}
	};
	
	@SuppressWarnings("serial")
	static final Map, String> primitivesType = new HashMap, String>() {
		{
			  put(boolean.class, "Z");
		      put(byte.class, "B");
		      put(char.class, "C");
		      put(double.class, "D");
		      put(float.class, "F");
		      put(int.class, "I");
		      put(long.class, "J");
		      put(short.class, "S");
		}
	};	
	
	@SuppressWarnings("serial")
	static final Map stringToPrimitivesType = new HashMap() {
		{
			  put("Boolean", "Z");
		      put("Byte", "B");
		      put("Character", "C");
		      put("Double", "D");
		      put("Float", "F");
		      put("Int", "I");
		      put("Long", "J");
		      put("Short", "S");
		}
	};
	
	@SuppressWarnings("serial")
	static final Map, Integer> loadOps = new HashMap, Integer>() {
		{
			  put(boolean.class, ILOAD);
		      put(byte.class, ILOAD);
		      put(char.class, ILOAD);
		      put(double.class, DLOAD);
		      put(float.class, FLOAD);
		      put(int.class, ILOAD);
		      put(long.class, LLOAD);
		      put(short.class, ILOAD);
		}
	};	
	@SuppressWarnings("serial")
	static final Map, Integer> defaultValue = new HashMap, Integer>() {
		{
			  put(boolean.class, ICONST_0);
		      put(byte.class, ICONST_0);
		      put(char.class, ICONST_0);
		      put(double.class, DCONST_0);
		      put(float.class, FCONST_0);
		      put(int.class, ICONST_0);
		      put(long.class, LCONST_0);
		      put(short.class, ICONST_0);
		}
	};	
	@SuppressWarnings("serial")
	static final Set> primitivesClassAndWrapper = new HashSet>() {
		{
			addAll(wrappers.keySet());
			addAll(wrappers.values());
		}
	};
	
	
	static File targetDir = null;
	static {
		String targetDirStr = System.getProperty("asm.dump.target.dir");
		if (targetDirStr != null) {
			targetDir = new File(targetDirStr);
			targetDir.mkdirs();
		} 
	}
	
	public static boolean isStillGeneric(Class clazz) {
		clazz = getPublicOrInterfaceClass(clazz);
		final TypeVariable[] typeParameters = clazz.getTypeParameters();
		return typeParameters != null && typeParameters.length > 0;
	}
	
	public static byte[] writeClassToFile (final String classname, final byte[] bytes) throws IOException {
		if (targetDir != null) {
			final int lastIndex = classname.lastIndexOf('.');
			final String filename = classname.substring(lastIndex + 1) + ".class";
			final String directory = classname.substring(0, lastIndex).replace('.', '/');
			final File packageDir = new File(targetDir, directory);
			packageDir.mkdirs();
			
			final FileOutputStream fos = new FileOutputStream(new File(packageDir, filename ));
			try {
				fos.write(bytes);
			} finally {
				fos.close();
			}
		}		
		return bytes;
	}

	public static String toTypeWithParam(Class class1) {
		StringBuilder sb = new StringBuilder();
		
		class1 = getPublicOrInterfaceClass(class1);
		
		sb.append(toType(class1));
		
		TypeVariable[] typeParameters = class1.getTypeParameters();
		
		if (typeParameters != null && typeParameters.length > 0) {
			sb.append("<");
			
			for(TypeVariable t : typeParameters) {
				sb.append("L").append(toType(t.getName())).append(";");
			}
			
			sb.append(">");
		}
		
		return sb.toString();
	}

	public static Type toGenericType(String sig) throws ClassNotFoundException {
		if (sig.length() == 1) {
			switch (sig.charAt(0)) {
			case 'Z': return boolean.class;
			case 'B': return byte.class;
			case 'C': return char.class;
			case 'D': return double.class;
			case 'F': return float.class;
			case 'I': return int.class;
			case 'J': return long.class;
			case 'S': return short.class;
			}
		}
		
		if (sig.startsWith("L")) {
			sig = sig.substring(1);
			if (sig.endsWith(";")) {
				sig = sig.substring(0, sig.length() - 1);
			}
		}
		
		int indexOf = sig.indexOf('<');
		if (indexOf == -1) {
			return Class.forName(sig.replace('/','.'));
		} else {
			final Class rawType = Class.forName(sig.substring(0, indexOf).replace('/','.'));

			final Type[] types = parseTypes(sig.substring(indexOf+ 1, sig.length() - 1));
			
			return new ParameterizedType() {
				
				@Override
				public Type getRawType() {
					return rawType;
				}
				
				@Override
				public Type getOwnerType() {
					return null;
				}
				
				@Override
				public Type[] getActualTypeArguments() {
					return types;
				}
			};
		}
	}

	private static Type[] parseTypes(String sig) throws ClassNotFoundException {
		List types = new ArrayList();
		
		int genericLevel = 0;
		int currentStart = 0;
		for(int i = 0; i < sig.length(); i++) {
			char c = sig.charAt(i);
			switch(c) {
			case '<': genericLevel ++; break;
			case '>': genericLevel --; break;
			case ';' : 
				if (genericLevel == 0) {
					types.add(toGenericType(sig.substring(currentStart, i)));
					currentStart = i;
				} 
				break;
			}
		}
		
		return types.toArray(new Type[] {});
	}
	public static Class getPublicOrInterfaceClass(Class clazz) {
		if (! Modifier.isPublic(clazz.getModifiers()) && ! Modifier.isStatic(clazz.getModifiers())) {
			Class[] interfaces = clazz.getInterfaces();
			if (interfaces != null && interfaces.length > 0) {
				return interfaces[0];
			} else {
				return getPublicOrInterfaceClass(clazz.getSuperclass());
			}
		}
		
		return clazz;
	}

	public static void invoke(MethodVisitor mv, Class target,
			String method, String sig) {
		Class publicClass = getPublicOrInterfaceClass(target);
		boolean isinterface = publicClass.isInterface();
		mv.visitMethodInsn(isinterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL, toType(publicClass), method, sig, isinterface);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy