
org.sfm.reflect.asm.JdbcMapperAsmBuilder Maven / Gradle / Ivy
package org.sfm.reflect.asm;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.sfm.jdbc.impl.AbstractJdbcMapper;
import org.sfm.map.MappingContext;
import org.sfm.map.MappingContextFactory;
import org.sfm.map.RowHandlerErrorHandler;
import org.sfm.map.FieldMapper;
import org.sfm.reflect.Instantiator;
import java.sql.ResultSet;
import static org.objectweb.asm.Opcodes.*;
public class JdbcMapperAsmBuilder {
private static final String ABSTRACT_JDBC_MAPPER_IMPL_TYPE = AsmUtils.toType(AbstractJdbcMapper.class);
private static final String FIELD_MAPPER_TYPE = AsmUtils.toType(FieldMapper.class);
private static final String INSTANTIATOR_TYPE = AsmUtils.toType(Instantiator.class);
private static final String ROW_HANDLER_ERROR_HANDLER_TYPE = AsmUtils.toType(RowHandlerErrorHandler.class);
private static final String mappingContextType = AsmUtils.toType(MappingContext.class);
private static final String mappingContextFactory = AsmUtils.toType(MappingContextFactory.class);
public static byte[] dump (final String className, final FieldMapper[] mappers, final FieldMapper[] constructorMappers, final Class target) throws Exception {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
MethodVisitor mv;
Class sourceClass = ResultSet.class;
final String targetType = AsmUtils.toType(target);
final String sourceType = AsmUtils.toType(sourceClass);
final String classType = AsmUtils.toType(className);
cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, classType, "L" + ABSTRACT_JDBC_MAPPER_IMPL_TYPE + "<" + toTargetTypeDeclaration(targetType) + ">;", ABSTRACT_JDBC_MAPPER_IMPL_TYPE, null);
for(int i = 0; i < mappers.length; i++) {
declareMapperFields(cw, mappers[i], i);
}
for(int i = 0; i < constructorMappers.length; i++) {
declareConstructorMapperFields(cw, constructorMappers[i], i);
}
{
mv = cw.visitMethod(ACC_PUBLIC, "",
"([L" + FIELD_MAPPER_TYPE + ";"
+ "[L" + FIELD_MAPPER_TYPE + ";L"
+ INSTANTIATOR_TYPE + ";L"
+ ROW_HANDLER_ERROR_HANDLER_TYPE + ";L"
+ mappingContextFactory + ";)V",
"([L" + FIELD_MAPPER_TYPE +";[L"
+ FIELD_MAPPER_TYPE +";L"
+ INSTANTIATOR_TYPE + "<" + toTargetTypeDeclaration(targetType) + ">;L"
+ ROW_HANDLER_ERROR_HANDLER_TYPE + ";L"
+ mappingContextFactory + ""
+ ";)V", null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 3);
mv.visitVarInsn(ALOAD, 4);
mv.visitVarInsn(ALOAD, 5);
mv.visitMethodInsn(INVOKESPECIAL, ABSTRACT_JDBC_MAPPER_IMPL_TYPE, "",
"(L" + INSTANTIATOR_TYPE + ";L"
+ ROW_HANDLER_ERROR_HANDLER_TYPE + ";L"
+ mappingContextFactory +";)V", false);
for(int i = 0; i < mappers.length; i++) {
addGetterSetterInit(mv, mappers[i], i, classType);
}
for(int i = 0; i < constructorMappers.length; i++) {
addGConstructorGetterSetterInit(mv, constructorMappers[i], i, classType);
}
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL, "mapFields", "(L" + sourceType + ";" + toTargetTypeDeclaration(targetType) + toTargetTypeDeclaration(mappingContextType) +")V", null, new String[] { "java/lang/Exception" });
mv.visitCode();
for(int i = 0; i < mappers.length; i++) {
generateMappingCall(mv, mappers[i], i, classType, sourceType, targetType);
}
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "mapFields", "(Ljava/lang/Object;Ljava/lang/Object;" + toTargetTypeDeclaration(mappingContextType) + ")V", null, new String[] { "java/lang/Exception" });
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, sourceType);
mv.visitVarInsn(ALOAD, 2);
mv.visitTypeInsn(CHECKCAST, targetType);
mv.visitVarInsn(ALOAD, 3);
mv.visitMethodInsn(INVOKEVIRTUAL, classType, "mapFields", "(L" + sourceType + ";" + toTargetTypeDeclaration(targetType) + toTargetTypeDeclaration(mappingContextType)+ ")V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PROTECTED + ACC_FINAL, "mapToFields", "(L" + sourceType + ";" + toTargetTypeDeclaration(targetType) + toTargetTypeDeclaration(mappingContextType)+ ")V", null, new String[]{"java/lang/Exception"});
mv.visitCode();
for(int i = 0; i < constructorMappers.length; i++) {
generateConstructorMappingCall(mv, constructorMappers[i], i, classType, sourceType, targetType);
}
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitVarInsn(ALOAD, 3);
mv.visitMethodInsn(INVOKEVIRTUAL, classType, "mapFields", "(L" + sourceType + ";" + toTargetTypeDeclaration(targetType) + toTargetTypeDeclaration(mappingContextType)+ ")V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PROTECTED + ACC_BRIDGE + ACC_SYNTHETIC, "mapToFields", "(Ljava/lang/Object;Ljava/lang/Object;" + toTargetTypeDeclaration(mappingContextType) + ")V", null, new String[]{"java/lang/Exception"});
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, sourceType);
mv.visitVarInsn(ALOAD, 2);
mv.visitTypeInsn(CHECKCAST, targetType);
mv.visitVarInsn(ALOAD, 3);
mv.visitMethodInsn(INVOKEVIRTUAL, classType, "mapToFields", "(L" + sourceType + ";" + toTargetTypeDeclaration(targetType)+ toTargetTypeDeclaration(mappingContextType) + ")V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(3, 3);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
mv.visitCode();
mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "", "()V", false);
mv.visitVarInsn(ASTORE, 1);
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getSimpleName", "()Ljava/lang/String;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
mv.visitLdcInsn("{");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
mv.visitInsn(POP);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKESPECIAL, ABSTRACT_JDBC_MAPPER_IMPL_TYPE, "appendToStringBuilder", "(Ljava/lang/StringBuilder;)V", false);
mv.visitVarInsn(ALOAD, 1);
for(int i = 0; i < mappers.length; i++) {
String mapperName = ", mapper" + i + "=";
String mapper = String.valueOf(mappers[i]);
mv.visitLdcInsn(mapperName);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
mv.visitLdcInsn(mapper);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
}
for(int i = 0; i < constructorMappers.length; i++) {
String mapperName = ", constructorMapper" + i + "=";
String mapper = String.valueOf(constructorMappers[i]);
mv.visitLdcInsn(mapperName);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
mv.visitLdcInsn(mapper);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
}
mv.visitLdcInsn("}");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;", false);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
mv.visitInsn(ARETURN);
mv.visitMaxs(2, 1);
mv.visitEnd();
}
cw.visitEnd();
return AsmUtils.writeClassToFile(className, cw.toByteArray());
}
private static String toTargetTypeDeclaration(String targetType) {
if (targetType.startsWith("[")) {
return targetType;
} else {
return "L" + targetType+ ";";
}
}
private static void generateMappingCall(MethodVisitor mv,
FieldMapper mapper, int index, String classType, String sourceType, String targetType) {
generateMappingCall(mv, mapper, index, classType, sourceType, targetType, "mapper");
}
private static void generateConstructorMappingCall(MethodVisitor mv,
FieldMapper mapper, int index, String classType, String sourceType, String targetType) {
generateMappingCall(mv, mapper, index, classType, sourceType, targetType, "constructorMapper");
}
private static void generateMappingCall(MethodVisitor mv, FieldMapper mapper, int index, String classType, String sourceType, String targetType, String variablePrefix) {
if (mapper ==null) return;
Class> mapperClass = AsmUtils.getPublicOrInterfaceClass(mapper.getClass());
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, classType, variablePrefix + index, "L" + AsmUtils.toType(mapperClass) + ";");
mv.visitVarInsn(ALOAD, 1);
mv.visitVarInsn(ALOAD, 2);
mv.visitVarInsn(ALOAD, 3);
if (AsmUtils.isStillGeneric(mapperClass)) {
AsmUtils.invoke(mv, mapperClass, "mapTo", "(Ljava/lang/Object;Ljava/lang/Object;" + toTargetTypeDeclaration(mappingContextType) + ")V");
} else {
AsmUtils.invoke(mv, mapperClass, "mapTo", "(L" + sourceType + ";" + toTargetTypeDeclaration(targetType) + toTargetTypeDeclaration(mappingContextType) + ")V");
}
}
private static void addGetterSetterInit(MethodVisitor mv,
FieldMapper mapper, int index, String classType) {
if (mapper == null) return;
Class> mapperClass = mapper.getClass();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
AsmUtils.addIndex(mv, index);
mv.visitInsn(AALOAD);
mv.visitTypeInsn(CHECKCAST, AsmUtils.toType(mapperClass));
mv.visitFieldInsn(PUTFIELD, classType, "mapper" + index, toTargetTypeDeclaration(AsmUtils.toType(mapperClass)));
}
private static void addGConstructorGetterSetterInit(MethodVisitor mv,
FieldMapper mapper, int index, String classType) {
if (mapper == null) return;
Class> mapperClass = mapper.getClass();
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 2);
AsmUtils.addIndex(mv, index);
mv.visitInsn(AALOAD);
mv.visitTypeInsn(CHECKCAST, AsmUtils.toType(mapperClass));
mv.visitFieldInsn(PUTFIELD, classType, "constructorMapper" + index, toTargetTypeDeclaration(AsmUtils.toType(mapperClass)));
}
private static void declareMapperFields(ClassWriter cw,
FieldMapper mapper, int index) {
if (mapper == null)
return;
FieldVisitor fv;
Class> mapperClass = AsmUtils.getPublicOrInterfaceClass(mapper.getClass());
fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, "mapper" + index, toTargetTypeDeclaration(AsmUtils.toType(mapperClass)), toTargetTypeDeclaration(AsmUtils.toTypeWithParam(mapperClass)), null);
fv.visitEnd();
}
private static void declareConstructorMapperFields(ClassWriter cw,
FieldMapper mapper, int index) {
if (mapper == null)
return;
FieldVisitor fv;
Class> mapperClass = AsmUtils.getPublicOrInterfaceClass(mapper.getClass());
fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, "constructorMapper" + index, toTargetTypeDeclaration(AsmUtils.toType(mapperClass)), toTargetTypeDeclaration(AsmUtils.toTypeWithParam(mapperClass)), null);
fv.visitEnd();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy