org.simpleflatmapper.reflect.asm.AsmUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sfm-reflect Show documentation
Show all versions of sfm-reflect Show documentation
Java library to map flat record - ResultSet, csv - to java object with minimum configuration and low footprint.
package org.simpleflatmapper.reflect.asm;
import org.simpleflatmapper.ow2asm.MethodVisitor;
import org.simpleflatmapper.ow2asm.Opcodes;
import org.simpleflatmapper.ow2asm.signature.SignatureReader;
import org.simpleflatmapper.ow2asm.signature.SignatureVisitor;
import org.simpleflatmapper.util.Consumer;
import org.simpleflatmapper.util.ErrorHelper;
import org.simpleflatmapper.util.Predicate;
import org.simpleflatmapper.util.TypeHelper;
import org.simpleflatmapper.reflect.ParameterizedTypeImpl;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.*;
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 static org.simpleflatmapper.ow2asm.Opcodes.ALOAD;
import static org.simpleflatmapper.ow2asm.Opcodes.ASTORE;
import static org.simpleflatmapper.ow2asm.Opcodes.BIPUSH;
import static org.simpleflatmapper.ow2asm.Opcodes.DCONST_0;
import static org.simpleflatmapper.ow2asm.Opcodes.DLOAD;
import static org.simpleflatmapper.ow2asm.Opcodes.DRETURN;
import static org.simpleflatmapper.ow2asm.Opcodes.DSTORE;
import static org.simpleflatmapper.ow2asm.Opcodes.FCONST_0;
import static org.simpleflatmapper.ow2asm.Opcodes.FLOAD;
import static org.simpleflatmapper.ow2asm.Opcodes.FRETURN;
import static org.simpleflatmapper.ow2asm.Opcodes.FSTORE;
import static org.simpleflatmapper.ow2asm.Opcodes.ICONST_0;
import static org.simpleflatmapper.ow2asm.Opcodes.ICONST_1;
import static org.simpleflatmapper.ow2asm.Opcodes.ICONST_2;
import static org.simpleflatmapper.ow2asm.Opcodes.ICONST_3;
import static org.simpleflatmapper.ow2asm.Opcodes.ICONST_4;
import static org.simpleflatmapper.ow2asm.Opcodes.ICONST_5;
import static org.simpleflatmapper.ow2asm.Opcodes.ILOAD;
import static org.simpleflatmapper.ow2asm.Opcodes.IRETURN;
import static org.simpleflatmapper.ow2asm.Opcodes.ISTORE;
import static org.simpleflatmapper.ow2asm.Opcodes.LCONST_0;
import static org.simpleflatmapper.ow2asm.Opcodes.LLOAD;
import static org.simpleflatmapper.ow2asm.Opcodes.LRETURN;
import static org.simpleflatmapper.ow2asm.Opcodes.LSTORE;
import static org.simpleflatmapper.ow2asm.Opcodes.SIPUSH;
public class AsmUtils {
public static final String ASM_DUMP_TARGET_DIR = "asm.dump.target.dir";
public static final Type[] EMPTY_TYPE_ARRAY = new Type[0];
public static final int API;
static {
API = Opcodes.ASM9;
}
static final Map, Class>> wrappers = new HashMap, Class>>();
static {
wrappers.put(boolean.class, Boolean.class);
wrappers.put(byte.class, Byte.class);
wrappers.put(char.class, Character.class);
wrappers.put(double.class, Double.class);
wrappers.put(float.class, Float.class);
wrappers.put(int.class, Integer.class);
wrappers.put(long.class, Long.class);
wrappers.put(short.class, Short.class);
wrappers.put(void.class, Void.class);
}
static final Map, String> primitivesType = new HashMap, String>();
static {
primitivesType.put(boolean.class, "Z");
primitivesType.put(byte.class, "B");
primitivesType.put(char.class, "C");
primitivesType.put(double.class, "D");
primitivesType.put(float.class, "F");
primitivesType.put(int.class, "I");
primitivesType.put(long.class, "J");
primitivesType.put(short.class, "S");
primitivesType.put(void.class, "V");
}
static final Map stringToPrimitivesType = new HashMap();
static {
stringToPrimitivesType.put("Boolean", "Z");
stringToPrimitivesType.put("Byte", "B");
stringToPrimitivesType.put("Character", "C");
stringToPrimitivesType.put("Double", "D");
stringToPrimitivesType.put("Float", "F");
stringToPrimitivesType.put("Int", "I");
stringToPrimitivesType.put("Long", "J");
stringToPrimitivesType.put("Short", "S");
}
static final Map, Integer> loadOps = new HashMap, Integer>();
static {
loadOps.put(boolean.class, ILOAD);
loadOps.put(byte.class, ILOAD);
loadOps.put(char.class, ILOAD);
loadOps.put(double.class, DLOAD);
loadOps.put(float.class, FLOAD);
loadOps.put(int.class, ILOAD);
loadOps.put(long.class, LLOAD);
loadOps.put(short.class, ILOAD);
}
static final Map, Integer> storeOps = new HashMap, Integer>();
static {
storeOps.put(boolean.class, ISTORE);
storeOps.put(byte.class, ISTORE);
storeOps.put(char.class, ISTORE);
storeOps.put(double.class, DSTORE);
storeOps.put(float.class, FSTORE);
storeOps.put(int.class, ISTORE);
storeOps.put(long.class, LSTORE);
storeOps.put(short.class, ISTORE);
}
static final Map, Integer> returnOps = new HashMap, Integer>();
static {
returnOps.put(boolean.class, IRETURN);
returnOps.put(byte.class, IRETURN);
returnOps.put(char.class, IRETURN);
returnOps.put(double.class, DRETURN);
returnOps.put(float.class, FRETURN);
returnOps.put(int.class, IRETURN);
returnOps.put(long.class, LRETURN);
returnOps.put(short.class, IRETURN);
}
static final Map, Integer> defaultValue = new HashMap, Integer>();
static {
defaultValue.put(boolean.class, ICONST_0);
defaultValue.put(byte.class, ICONST_0);
defaultValue.put(char.class, ICONST_0);
defaultValue.put(double.class, DCONST_0);
defaultValue.put(float.class, FCONST_0);
defaultValue.put(int.class, ICONST_0);
defaultValue.put(long.class, LCONST_0);
defaultValue.put(short.class, ICONST_0);
}
static final Set> primitivesClassAndWrapper = new HashSet>();
static {
primitivesClassAndWrapper.addAll(wrappers.keySet());
primitivesClassAndWrapper.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 String toAsmType(final String name) {
return name.replace('.', '/');
}
public static String toAsmType(final Type type) {
if (TypeHelper.isPrimitive(type)) {
return primitivesType.get(TypeHelper.toClass(type));
}
return toAsmType(TypeHelper.toClass(type).getName());
}
public static String toTargetTypeDeclaration(Type targetType) {
if (TypeHelper.isPrimitive(targetType)) {
return primitivesType.get(TypeHelper.toClass(targetType));
}
return toTargetTypeDeclaration(AsmUtils.toAsmType(targetType));
}
public static String toTargetTypeDeclaration(String targetType) {
if (targetType.startsWith("[")) {
return targetType;
} else {
return "L" + targetType+ ";";
}
}
public static String toGenericAsmType(final Type type) {
StringBuilder sb = new StringBuilder();
sb.append(toAsmType(type));
Type[] typeParameters = null;
if (type instanceof ParameterizedType) {
typeParameters = ((ParameterizedType) type).getActualTypeArguments();
}
if (typeParameters != null && typeParameters.length > 0) {
sb.append("<");
for(Type t : typeParameters) {
sb.append(toTargetTypeDeclaration(toGenericAsmType(t)));
}
sb.append(">");
}
return sb.toString();
}
public static byte[] writeClassToFile (final String className, final byte[] bytes) throws IOException {
return writeClassToFileInDir(className, bytes, AsmUtils.targetDir);
}
public static byte[] writeClassToFileInDir(String className, byte[] bytes, File targetDir) throws IOException {
if (targetDir != null) {
_writeClassToFileInDir(className, bytes, targetDir);
}
return bytes;
}
private static void _writeClassToFileInDir(String className, byte[] bytes, File targetDir) throws IOException {
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();
}
}
public static Type toGenericType(String sig, List genericTypeNames, Type target) throws ClassNotFoundException {
ClassLoader classLoader = TypeHelper.getClassLoader(target, Thread.currentThread().getContextClassLoader());
SignatureReader reader = new SignatureReader(sig);
final List types = new ArrayList();
TypeCreator typeCreator = new TypeCreator(new Consumer() {
@Override
public void accept(Type t) {
types.add(t);
}
}, classLoader, genericTypeNames, target) {
};
reader.accept(typeCreator);
typeCreator.visitEnd();
return types.get(0);
}
private static class TypeCreator extends SignatureVisitor {
final Consumer consumer;
final ClassLoader classLoader;
private final List genericTypeNames;
private final Type target;
protected Type type;
final List arguments = new ArrayList();
boolean flushed = false;
public TypeCreator(Consumer consumer, ClassLoader classLoader, List genericTypeNames, Type target) {
super(AsmUtils.API);
this.consumer = consumer;
this.classLoader = classLoader;
this.genericTypeNames = genericTypeNames;
this.target = target;
}
@Override
public void visitFormalTypeParameter(String name) {
super.visitFormalTypeParameter(name);
}
@Override
public SignatureVisitor visitParameterType() {
return super.visitParameterType();
}
@Override
public void visitBaseType(char descriptor) {
switch (descriptor) {
case 'Z': type = (boolean.class); break;
case 'B': type = (byte.class);break;
case 'C': type = ( char.class);break;
case 'D': type = ( double.class);break;
case 'F': type = ( float.class);break;
case 'I': type = ( int.class);break;
case 'J': type = ( long.class);break;
case 'S': type = ( short.class);break;
default: throw new IllegalArgumentException("Unexpected primitiv " + descriptor);
}
visitEnd();
}
@Override
public void visitTypeVariable(String name) {
int i = genericTypeNames.indexOf(name);
if (i >= 0 && target instanceof ParameterizedType) {
Type resolvedType = ((ParameterizedType) target).getActualTypeArguments()[i];
consumer.accept(resolvedType);
}
}
@Override
public SignatureVisitor visitArrayType() {
return new TypeCreator(new Consumer() {
@Override
public void accept(Type type) {
consumer.accept(Array.newInstance(TypeHelper.toClass(type), 0).getClass());
}
}, classLoader, genericTypeNames, target);
}
@Override
public void visitClassType(String name) {
try {
type = (Class.forName(name.replace('/','.'), true, classLoader));
} catch (ClassNotFoundException e) {
ErrorHelper.rethrow(e);
}
}
@Override
public SignatureVisitor visitTypeArgument(char wildcard) {
return new TypeCreator(new Consumer() {
@Override
public void accept(Type type) {
arguments.add(type);
}
}, classLoader, genericTypeNames, target);
}
@Override
public void visitEnd() {
if (flushed) return;
flushed = true;
if (arguments.isEmpty()) {
consumer.accept(type);
} else {
consumer.accept(new ParameterizedTypeImpl(TypeHelper.toClass(type), arguments.toArray(EMPTY_TYPE_ARRAY)));
}
}
}
public static Type findClosestPublicTypeExposing(Type type, Class> expose) {
return findTypeInHierarchy(type, new TypeIsPublicAndImplement(expose));
}
public static Type findTypeInHierarchy(Type type, Predicate predicate) {
if (predicate.test(type)) {
return type;
}
// check interfaces
Class