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

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

package org.sfm.reflect.asm;

import static org.objectweb.asm.Opcodes.AALOAD;
import static org.objectweb.asm.Opcodes.ACC_BRIDGE;
import static org.objectweb.asm.Opcodes.ACC_FINAL;
import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.ACC_SUPER;
import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.ARETURN;
import static org.objectweb.asm.Opcodes.ASTORE;
import static org.objectweb.asm.Opcodes.BIPUSH;
import static org.objectweb.asm.Opcodes.CHECKCAST;
import static org.objectweb.asm.Opcodes.F_SAME;
import static org.objectweb.asm.Opcodes.GETFIELD;
import static org.objectweb.asm.Opcodes.GOTO;
import static org.objectweb.asm.Opcodes.ICONST_0;
import static org.objectweb.asm.Opcodes.ICONST_1;
import static org.objectweb.asm.Opcodes.ICONST_2;
import static org.objectweb.asm.Opcodes.ICONST_3;
import static org.objectweb.asm.Opcodes.ICONST_4;
import static org.objectweb.asm.Opcodes.ICONST_5;
import static org.objectweb.asm.Opcodes.IFNE;
import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
import static org.objectweb.asm.Opcodes.PUTFIELD;
import static org.objectweb.asm.Opcodes.RETURN;
import static org.objectweb.asm.Opcodes.V1_7;

import java.sql.ResultSet;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.sfm.map.FieldMapper;
import org.sfm.reflect.Instantiator;

public class AsmJdbcMapperBuilder {
	public static  byte[] dump (final String className, final FieldMapper[] mappers, final Instantiator instantiator, final Class target) throws Exception {

		ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
		MethodVisitor mv;
		
		final String targetType = AsmUtils.toType(target);
		final String sourceType = AsmUtils.toType(ResultSet.class);
		final String classType = AsmUtils.toType(className);
		final String instantiatorType = AsmUtils.toType(instantiator.getClass());

		cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER + ACC_FINAL, classType, "Ljava/lang/Object;Lorg/sfm/jdbc/JdbcMapper;", "java/lang/Object", new String[] { "org/sfm/jdbc/JdbcMapper" });


		for(int i = 0; i < mappers.length; i++) {
			declareMapperFields(cw,  mappers[i], targetType, sourceType, i);  
		}
		FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, "instantiator", "L" + instantiatorType + ";", "L" + AsmUtils.toTypeWithParam(instantiator.getClass()) + ";", null);
		fv.visitEnd();

		{
			mv = cw.visitMethod(ACC_PUBLIC, "", "([Lorg/sfm/map/FieldMapper;Lorg/sfm/reflect/Instantiator;)V", "([Lorg/sfm/map/FieldMapper;Lorg/sfm/reflect/Instantiator;)V", null);

			mv.visitCode();
			mv.visitVarInsn(ALOAD, 0);
			mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false);
			
			
			for(int i = 0; i < mappers.length; i++) {
				addGetterSetterInit(mv,  mappers[i], i, classType); 
			}
			
			mv.visitVarInsn(ALOAD, 0);
			mv.visitVarInsn(ALOAD, 2);
			mv.visitTypeInsn(CHECKCAST, instantiatorType);
			mv.visitFieldInsn(PUTFIELD, classType, "instantiator", "L" + instantiatorType+ ";");
			
			mv.visitInsn(RETURN);
			mv.visitMaxs(3, 3);
			mv.visitEnd();
		}
		{
			
			mv = cw.visitMethod(ACC_PUBLIC, "map", "(L" + sourceType + ";)L" + targetType + ";", null, new String[] { "java/lang/Exception" });
			mv.visitCode();
			mv.visitVarInsn(ALOAD, 0);
			mv.visitFieldInsn(GETFIELD, classType, "instantiator", "L" + instantiatorType + ";");
			mv.visitVarInsn(ALOAD, 1);
			if (AsmUtils.isStillGeneric(instantiator.getClass())) {
				mv.visitMethodInsn(INVOKEVIRTUAL, instantiatorType, "newInstance", "(Ljava/lang/Object;)Ljava/lang/Object;", false);
			} else {
				mv.visitMethodInsn(INVOKEVIRTUAL, instantiatorType, "newInstance", "(L" + sourceType + ";)L" + targetType + ";", false);
			}
			mv.visitTypeInsn(CHECKCAST, targetType);
			mv.visitVarInsn(ASTORE, 2);

			for(int i = 0; i < mappers.length; i++) {
				generateMappingCall(mv, mappers[i], i, classType, sourceType, targetType);
			}
			
			mv.visitVarInsn(ALOAD, 2);
			mv.visitInsn(ARETURN);
			
			mv.visitMaxs(3, 3);
			mv.visitEnd();
		}
		
		{
			mv = cw.visitMethod(ACC_PUBLIC + ACC_BRIDGE + ACC_SYNTHETIC, "map", "(Ljava/lang/Object;)Ljava/lang/Object;", null, new String[] { "java/lang/Exception" });
			mv.visitCode();
			mv.visitVarInsn(ALOAD, 0);
			mv.visitVarInsn(ALOAD, 1);
			mv.visitTypeInsn(CHECKCAST, sourceType);
			mv.visitMethodInsn(INVOKEVIRTUAL, classType, "map", "(L" + sourceType + ";)L" + targetType + ";", false);
			mv.visitInsn(ARETURN);
			mv.visitMaxs(2, 2);
			mv.visitEnd();
		}
		
		{
			mv = cw.visitMethod(ACC_PUBLIC, "forEach", "(Ljava/sql/ResultSet;Lorg/sfm/utils/Handler;)Lorg/sfm/utils/Handler;", ";>(L" + sourceType + ";TH;)TH;", new String[] { "java/lang/Exception" });
			mv.visitCode();
			Label l1 = new Label();
			mv.visitJumpInsn(GOTO, l1);
			Label l2 = new Label();
			mv.visitLabel(l2);
			mv.visitFrame(F_SAME, 0, null, 0, null);
			mv.visitVarInsn(ALOAD, 0);
			mv.visitVarInsn(ALOAD, 1);
			mv.visitMethodInsn(INVOKEVIRTUAL, classType, "map", "(L" + sourceType + ";)L" + targetType + ";", false);
			mv.visitVarInsn(ASTORE, 3);
			mv.visitVarInsn(ALOAD, 2);
			mv.visitVarInsn(ALOAD, 3);
			mv.visitMethodInsn(INVOKEINTERFACE, "org/sfm/utils/Handler", "handle", "(Ljava/lang/Object;)V", true);
			mv.visitLabel(l1);
			mv.visitFrame(F_SAME, 0, null, 0, null);
			mv.visitVarInsn(ALOAD, 1);
			mv.visitMethodInsn(INVOKEINTERFACE, "java/sql/ResultSet", "next", "()Z", true);
			mv.visitJumpInsn(IFNE, l2);
			mv.visitVarInsn(ALOAD, 2);
			mv.visitInsn(ARETURN);
			mv.visitMaxs(2, 4);
			mv.visitEnd();
			}

		cw.visitEnd();

		return AsmUtils.writeClassToFile(className, cw.toByteArray());
	}

	private static  void generateMappingCall(MethodVisitor mv,
			FieldMapper mapper, int index, String classType, String sourceType, String targetType) {
		Class mapperClass = mapper.getClass();
		mv.visitVarInsn(ALOAD, 0);
		mv.visitFieldInsn(GETFIELD, classType, "mapper" + index, "L" +  AsmUtils.toType(mapperClass) + ";");
		mv.visitVarInsn(ALOAD, 1);
		mv.visitVarInsn(ALOAD, 2);
		
		if (AsmUtils.isStillGeneric(mapperClass)) {
			mv.visitMethodInsn(INVOKEVIRTUAL, AsmUtils.toType(mapperClass), "map", "(Ljava/lang/Object;Ljava/lang/Object;)V", false);
		} else {
			mv.visitMethodInsn(INVOKEVIRTUAL, AsmUtils.toType(mapperClass), "map", "(L" + sourceType + ";L" + targetType +";)V", false);
		}

	}

	private static  void addGetterSetterInit(MethodVisitor mv,
			FieldMapper mapper, int index, String classType) {
		Class mapperClass = mapper.getClass();
		
		mv.visitVarInsn(ALOAD, 0);
		mv.visitVarInsn(ALOAD, 1);
		addIndex(mv, index);
		mv.visitInsn(AALOAD);
		mv.visitTypeInsn(CHECKCAST, AsmUtils.toType(mapperClass));
		mv.visitFieldInsn(PUTFIELD, classType, "mapper" + index, "L" +  AsmUtils.toType(mapperClass) +";");

	}

	private static  void declareMapperFields(ClassWriter cw,
			FieldMapper mapper, String targetType, String sourceType, int index) {
		FieldVisitor fv;
		Class mapperClass = mapper.getClass();
		
		fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, "mapper" + index, "L" + AsmUtils.toType(mapperClass) + ";", "L" + AsmUtils.toTypeWithParam(mapperClass) + ";", null);
		fv.visitEnd();

	}

	private static void addIndex(MethodVisitor mv, int i) {
		switch(i) {
		case 0:
			mv.visitInsn(ICONST_0);
			return;
		case 1:
			mv.visitInsn(ICONST_1);
			return;
		case 2:
			mv.visitInsn(ICONST_2);
			return;
		case 3:
			mv.visitInsn(ICONST_3);
			return;
		case 4:
			mv.visitInsn(ICONST_4);
			return;
		case 5:
			mv.visitInsn(ICONST_5);
			return;
		default:
			mv.visitIntInsn(BIPUSH, i);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy