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

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

Go to download

Java library to map flat record - ResultSet, csv - to java object with minimum configuration and low footprint.

There is a newer version: 1.10.3
Show newest version
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 - 2024 Weber Informatics LLC | Privacy Policy