Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package com.fasterxml.jackson.module.afterburner.ser;
  
  import java.util.*;
  
  
  import  org.objectweb.asm.*;
 
 import static org.objectweb.asm.Opcodes.*;
 
Simple collector used to keep track of properties for which code-generated accessors are needed.
 
 {
     
     
     public PropertyAccessorCollector() { }
     
     /*
     /**********************************************************
     /* Methods for collecting properties
     /**********************************************************
      */
     
         return _add(new IntMethodPropertyWriter(bpwnull.size(), null));
     }
         return _add(new LongMethodPropertyWriter(bpwnull.size(), null));
     }
         return _add(new StringMethodPropertyWriter(bpwnull.size(), null));
     }
         return _add(new ObjectMethodPropertyWriter(bpwnull.size(), null));
     }
 
         return _add(new IntFieldPropertyWriter(bpwnull.size(), null));
     }
         return _add(new LongFieldPropertyWriter(bpwnull.size(), null));
     }
         return _add(new StringFieldPropertyWriter(bpwnull.size(), null));
     }
         return _add(new ObjectFieldPropertyWriter(bpwnull.size(), null));
     }
     
     public boolean isEmpty() {
         return .isEmpty()
             && .isEmpty()
             && .isEmpty()
             && .isEmpty()
             && .isEmpty()
             && .isEmpty()
             && .isEmpty()
             && .isEmpty()
         ;
     }
     
     /*
     /**********************************************************
     /* Code generation; high level
     /**********************************************************
      */
 
     public BeanPropertyAccessor findAccessor(Class<?> beanType,
             MyClassLoader classLoader)
     {
         // if we weren't passed a class loader, we will base it on value type CL, try to use parent
         if (classLoader == null) {
             classLoader = new MyClassLoader(beanType.getClassLoader(), true);
         }
         
         String srcName = beanType.getName() + "$Access4JacksonSerializer";
         
         String generatedClass = internalClassName(srcName);
         Class<?> accessorClass = null;
         try {
             accessorClass = classLoader.loadClass(srcName);
         } catch (ClassNotFoundException e) { }
        if (accessorClass == null) {
            accessorClass = generateAccessorClass(beanTypeclassLoadersrcNamegeneratedClass);
        }
        try {
            return (BeanPropertyAccessoraccessorClass.newInstance();
        } catch (Exception e) {
            throw new IllegalStateException("Failed to generate accessor class '"+srcName+"': "+e.getMessage(), e);
        }
    }
        
    public Class<?> generateAccessorClass(Class<?> beanType,
            MyClassLoader classLoaderString srcNameString generatedClass)
    {
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        String superClass = internalClassName(BeanPropertyAccessor.class.getName());
        
        // muchos important: level at least 1.5 to get generics!!!
        cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, generatedClassnullsuperClassnull);
        cw.visitSource(srcName + ".java"null);
        // add default (no-arg) constructor:
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>""()V"nullnull);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, superClass"<init>""()V");
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0); // don't care (real values: 1,1)
        mv.visitEnd();
        
        final String beanClass = internalClassName(beanType.getName());
 
        // and then add various accessors; first field accessors:
        if (!.isEmpty()) {
            _addIntFields(cwbeanClass);
        }
        if (!.isEmpty()) {
            _addLongFields(cwbeanClass);
        }
        if (!.isEmpty()) {
            _addStringFields(cwbeanClass);
        }
        if (!.isEmpty()) {
            _addObjectFields(cwbeanClass);
        }
        // and then method accessors:
        if (!.isEmpty()) {
            _addIntGetters(cwbeanClass);
        }
        if (!.isEmpty()) {
            _addLongGetters(cwbeanClass);
        }
        if (!.isEmpty()) {
            _addStringGetters(cwbeanClass);
        }
        if (!.isEmpty()) {
            _addObjectGetters(cwbeanClass);
        }
        cw.visitEnd();
        byte[] byteCode = cw.toByteArray();
        return classLoader.loadAndResolve(srcNamebyteCode);
    }
    /*
    /**********************************************************
    /* Code generation; method-based getters
    /**********************************************************
     */
    private static void _addIntGetters(ClassWriter cwList<IntMethodPropertyWriterprops,
            String beanClass)
    {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "intGetter""(Ljava/lang/Object;I)I"/*generic sig*/nullnull);
        mv.visitCode();
        // first: cast bean to proper type
        mv.visitVarInsn(ALOAD, 1);
        mv.visitTypeInsn(CHECKCAST, beanClass);
        mv.visitVarInsn(ASTORE, 3);
        // Ok; minor optimization, 4 or less accessors, just do IFs; over that, use switch
        if (props.size() <= 4) {
            _addGettersUsingIf(mvpropsbeanClass, IRETURN, );
        } else {
            _addGettersUsingSwitch(mvpropsbeanClass, IRETURN);
        }
        // and if no match, generate exception:
        generateException(mvbeanClassprops.size());
        mv.visitMaxs(0, 0); // don't care (real values: 1,1)
        mv.visitEnd();
    }
    private static void _addLongGetters(ClassWriter cwList<LongMethodPropertyWriterprops,
            String beanClass)
    {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "longGetter""(Ljava/lang/Object;I)J"/*generic sig*/nullnull);
        mv.visitCode();
        // first: cast bean to proper type
        mv.visitVarInsn(ALOAD, 1);
        mv.visitTypeInsn(CHECKCAST, beanClass);
        mv.visitVarInsn(ASTORE, 3);
        if (props.size() < 4) {
            _addGettersUsingIf(mvpropsbeanClass, LRETURN, );
        } else {
            _addGettersUsingSwitch(mvpropsbeanClass, LRETURN);
        }
        // and if no match, generate exception:
        generateException(mvbeanClassprops.size());
        // and that's it
        mv.visitMaxs(0, 0); // don't care (real values: 1,1)
        mv.visitEnd();
    }
    private static void _addStringGetters(ClassWriter cwList<StringMethodPropertyWriterprops,
            String beanClass)
    {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "stringGetter""(Ljava/lang/Object;I)Ljava/lang/String;"/*generic sig*/nullnull);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 1);
        mv.visitTypeInsn(CHECKCAST, beanClass);
        mv.visitVarInsn(ASTORE, 3);
        if (props.size() < 4) {
            _addGettersUsingIf(mvpropsbeanClass, ARETURN, );
        } else {
            _addGettersUsingSwitch(mvpropsbeanClass, ARETURN);
        }
        generateException(mvbeanClassprops.size());
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
    private static void _addObjectGetters(ClassWriter cwList<ObjectMethodPropertyWriterprops,
            String beanClass)
    {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "objectGetter""(Ljava/lang/Object;I)Ljava/lang/Object;"/*generic sig*/nullnull);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 1);
        mv.visitTypeInsn(CHECKCAST, beanClass);
        mv.visitVarInsn(ASTORE, 3);
        if (props.size() < 4) {
            _addGettersUsingIf(mvpropsbeanClass, ARETURN, );
        } else {
            _addGettersUsingSwitch(mvpropsbeanClass, ARETURN);
        }
        generateException(mvbeanClassprops.size());
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
    
    /*
    /**********************************************************
    /* Code generation; field-based getters
    /**********************************************************
     */
    
    private static void _addIntFields(ClassWriter cwList<IntFieldPropertyWriterprops,
            String beanClass)
    {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "intField""(Ljava/lang/Object;I)I"/*generic sig*/nullnull);
        mv.visitCode();
        // first: cast bean to proper type
        mv.visitVarInsn(ALOAD, 1);
        mv.visitTypeInsn(CHECKCAST, beanClass);
        mv.visitVarInsn(ASTORE, 3);
        // Ok; minor optimization, less than 4 accessors, just do IFs; over that, use switch
        if (props.size() < 4) {
            _addFieldsUsingIf(mvpropsbeanClass, IRETURN, );
        } else {
            _addFieldsUsingSwitch(mvpropsbeanClass, IRETURN, "I");
        }
        // and if no match, generate exception:
        generateException(mvbeanClassprops.size());
        mv.visitMaxs(0, 0); // don't care (real values: 1,1)
        mv.visitEnd();
    }
    private static void _addLongFields(ClassWriter cwList<LongFieldPropertyWriterprops,
            String beanClass)
    {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "longField""(Ljava/lang/Object;I)J"/*generic sig*/nullnull);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 1);
        mv.visitTypeInsn(CHECKCAST, beanClass);
        mv.visitVarInsn(ASTORE, 3);
        if (props.size() < 4) {
            _addFieldsUsingIf(mvpropsbeanClass, LRETURN, );
        } else {
            _addFieldsUsingSwitch(mvpropsbeanClass, LRETURN, "J");
        }
        // and if no match, generate exception:
        generateException(mvbeanClassprops.size());
        mv.visitMaxs(0, 0); // don't care (real values: 1,1)
        mv.visitEnd();
    }
    private static void _addStringFields(ClassWriter cwList<StringFieldPropertyWriterprops,
            String beanClass)
    {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "stringField""(Ljava/lang/Object;I)Ljava/lang/String;"nullnull);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 1);
        mv.visitTypeInsn(CHECKCAST, beanClass);
        mv.visitVarInsn(ASTORE, 3);
        if (props.size() < 4) {
            _addFieldsUsingIf(mvpropsbeanClass, ARETURN, );
        } else {
            _addFieldsUsingSwitch(mvpropsbeanClass, ARETURN, "Ljava/lang/String;");
        }
        generateException(mvbeanClassprops.size());
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
    private static void _addObjectFields(ClassWriter cwList<ObjectFieldPropertyWriterprops,
            String beanClass)
    {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "objectField""(Ljava/lang/Object;I)Ljava/lang/Object;"nullnull);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 1);
        mv.visitTypeInsn(CHECKCAST, beanClass);
        mv.visitVarInsn(ASTORE, 3);
        if (props.size() < 4) {
            _addFieldsUsingIf(mvpropsbeanClass, ARETURN, );
        } else {
            _addFieldsUsingSwitch(mvpropsbeanClass, ARETURN, "Ljava/lang/Object;");
        }
        generateException(mvbeanClassprops.size());
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
    
    /*
    /**********************************************************
    /* Helper methods, method accessor creation
    /**********************************************************
     */
    private static <T extends OptimizedBeanPropertyWriter<T>> void _addGettersUsingIf(MethodVisitor mv,
            List<T> propsString beanClassint returnOpcode,
            int[] constantOpcodes)
    {
        mv.visitVarInsn(ILOAD, 2); // load second arg (index)
        Label next = new Label();
        // first: check if 'index == 0'
        mv.visitJumpInsn(IFNE, next); // "if not zero, goto L (skip stuff)"
        // call first getter:
        mv.visitVarInsn(ALOAD, 3); // load local for cast bean
        Method method = (Method) (props.get(0).getMember().getMember());
        mv.visitMethodInsn(INVOKEVIRTUAL, beanClassmethod.getName(), "()"+Type.getDescriptor(method.getReturnType()));
        mv.visitInsn(returnOpcode);
        // And from this point on, loop a bit
        for (int i = 1, len = props.size(); i < len; ++i) {
            mv.visitLabel(next);
            next = new Label();
            mv.visitVarInsn(ILOAD, 2); // load second arg (index)
            mv.visitInsn(constantOpcodes[i]);
            mv.visitJumpInsn(IF_ICMPNE, next);
            mv.visitVarInsn(ALOAD, 3); // load bean
            method = (Method) (props.get(i).getMember().getMember());
            mv.visitMethodInsn(INVOKEVIRTUAL, beanClassmethod.getName(), "()"+Type.getDescriptor(method.getReturnType()));
            mv.visitInsn(returnOpcode);
        }
        mv.visitLabel(next);
    }        
    private static <T extends OptimizedBeanPropertyWriter<T>> void _addGettersUsingSwitch(MethodVisitor mv,
            List<T> propsString beanClassint returnOpcode)
    {
        mv.visitVarInsn(ILOAD, 2); // load second arg (index)
        Label[] labels = new Label[props.size()];
        for (int i = 0, len = labels.length; i < len; ++i) {
            labels[i] = new Label();
        }
        Label defaultLabel = new Label();
        mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabellabels);
        for (int i = 0, len = labels.length; i < len; ++i) {
            mv.visitLabel(labels[i]);
            mv.visitVarInsn(ALOAD, 3); // load bean
            Method method = (Method) (props.get(i).getMember().getMember());
            mv.visitMethodInsn(INVOKEVIRTUAL, beanClassmethod.getName(), "()"+Type.getDescriptor(method.getReturnType()));
            mv.visitInsn(returnOpcode);
        }
        mv.visitLabel(defaultLabel);
    }        
    private static <T extends OptimizedBeanPropertyWriter<T>> void _addFieldsUsingIf(MethodVisitor mv,
            List<T> propsString beanClassint returnOpcode,
            int[] constantOpcodes)
    {
        mv.visitVarInsn(ILOAD, 2); // load second arg (index)
        Label next = new Label();
        // first: check if 'index == 0'
        mv.visitJumpInsn(IFNE, next); // "if not zero, goto L (skip stuff)"
        // first field accessor
        mv.visitVarInsn(ALOAD, 3); // load local for cast bean
        AnnotatedField field = (AnnotatedFieldprops.get(0).getMember();
        mv.visitFieldInsn(GETFIELD, beanClassfield.getName(), Type.getDescriptor(field.getRawType()));
        mv.visitInsn(returnOpcode);
        // And from this point on, loop a bit
        for (int i = 1, len = props.size(); i < len; ++i) {
            mv.visitLabel(next);
            next = new Label();
            mv.visitVarInsn(ILOAD, 2); // load second arg (index)
            mv.visitInsn(constantOpcodes[i]);
            mv.visitJumpInsn(IF_ICMPNE, next);
            mv.visitVarInsn(ALOAD, 3); // load bean
            field = (AnnotatedFieldprops.get(i).getMember();
            mv.visitFieldInsn(GETFIELD, beanClassfield.getName(), Type.getDescriptor(field.getRawType()));
            mv.visitInsn(returnOpcode);
        }
        mv.visitLabel(next);
    }        
    private static <T extends OptimizedBeanPropertyWriter<T>> void _addFieldsUsingSwitch(MethodVisitor mv,
            List<T> propsString beanClassint returnOpcodeString fieldSignature)
    {
        mv.visitVarInsn(ILOAD, 2); // load second arg (index)
        Label[] labels = new Label[props.size()];
        for (int i = 0, len = labels.length; i < len; ++i) {
            labels[i] = new Label();
        }
        Label defaultLabel = new Label();
        mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabellabels);
        for (int i = 0, len = labels.length; i < len; ++i) {
            mv.visitLabel(labels[i]);
            mv.visitVarInsn(ALOAD, 3); // load bean
            AnnotatedField field = (AnnotatedFieldprops.get(i).getMember();
            mv.visitFieldInsn(GETFIELD, beanClassfield.getName(), Type.getDescriptor(field.getRawType()));
            mv.visitInsn(returnOpcode);
        }
        mv.visitLabel(defaultLabel);
    }        
New to GrepCode? Check out our FAQ X