Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package com.fasterxml.jackson.module.afterburner.deser;
  
  import static org.codehaus.jackson.org.objectweb.asm.Opcodes.*;
  
  import java.util.List;
  
 
Simple collector used to keep track of properties for which code-generated mutators are needed.
 
 {
     
     
     public PropertyMutatorCollector() { }
     
     /*
     /**********************************************************
     /* Methods for collecting properties
     /**********************************************************
      */
     
         return _add(new SettableIntMethodProperty(propnull.size()));
     }
         return _add(new SettableLongMethodProperty(propnull.size()));
     }
         return _add(new SettableStringMethodProperty(propnull.size()));
     }
         return _add(new SettableObjectMethodProperty(propnull.size()));
     }
 
         return _add(new SettableIntFieldProperty(propnull.size()));
     }
         return _add(new SettableLongFieldProperty(propnull.size()));
     }
         return _add(new SettableStringFieldProperty(propnull.size()));
     }
         return _add(new SettableObjectFieldProperty(propnull.size()));
     }
 
     public boolean isEmpty() {
         return .isEmpty()
             && .isEmpty()
             && .isEmpty()
             && .isEmpty()
             && .isEmpty()
             && .isEmpty()
             && .isEmpty()
             && .isEmpty()
         ;
     }
     
     /*
     /**********************************************************
     /* Code generation; high level
     /**********************************************************
      */

    
Method for building generic mutator class for specified bean type.
 
     public BeanPropertyMutator buildMutator(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() + "$Access4JacksonDeserializer";
         
         String generatedClass = internalClassName(srcName);
        Class<?> accessorClass = null;
        try {
            accessorClass = classLoader.loadClass(srcName);
        } catch (ClassNotFoundException e) { }
        if (accessorClass == null) {
            accessorClass = generateMutatorClass(beanTypeclassLoadersrcNamegeneratedClass);
        }
        try {
            return (BeanPropertyMutatoraccessorClass.newInstance();
        } catch (Exception e) {
            throw new IllegalStateException("Failed to generate accessor class '"+srcName+"': "+e.getMessage(), e);
        }
    }
        
    public Class<?> generateMutatorClass(Class<?> beanType,
            MyClassLoader classLoaderString srcNameString generatedClass)
    {
        ClassWriter cw = new ClassWriter(.);
        String superClass = internalClassName(BeanPropertyMutator.class.getName());
        
        // muchos important: level at least 1.5 to get generics!!!
        cw.visit( + generatedClassnullsuperClassnull);
        cw.visitSource(srcName + ".java"null);
        // add default (no-arg) constructor:
        MethodVisitor mv = cw.visitMethod("<init>""()V"nullnull);
        mv.visitCode();
        mv.visitVarInsn(, 0);
        mv.visitMethodInsn(superClass"<init>""()V");
        mv.visitInsn();
        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()) {
            _addIntSetters(cwbeanClass);
        }
        if (!.isEmpty()) {
            _addLongSetters(cwbeanClass);
        }
        if (!.isEmpty()) {
            _addStringSetters(cwbeanClass);
        }
        if (!.isEmpty()) {
            _addObjectSetters(cwbeanClass);
        }
        cw.visitEnd();
        byte[] byteCode = cw.toByteArray();
        return classLoader.loadAndResolve(srcNamebyteCode);
    }
    
    /*
    /**********************************************************
    /* Code generation; method-based getters
    /**********************************************************
     */
    private static void _addIntSetters(ClassWriter cwList<SettableIntMethodPropertyprops,
            String beanClass)
    {
        MethodVisitor mv = cw.visitMethod("intSetter""(Ljava/lang/Object;II)V"/*generic sig*/nullnull);
        mv.visitCode();
        // first: cast bean to proper type
        mv.visitVarInsn(, 1);
        mv.visitTypeInsn(beanClass);
        mv.visitVarInsn(, 4); // 3 args (0 == this), so 4 is the first local var slot
        // Ok; minor optimization, 4 or less accessors, just do IFs; over that, use switch
        if (props.size() <= 4) {
            _addSettersUsingIf(mvpropsbeanClass, 4, false);
        } else {
            _addSettersUsingSwitch(mvpropsbeanClass, 4, false);
        }
        // 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 _addLongSetters(ClassWriter cwList<SettableLongMethodPropertyprops,
            String beanClass)
    {
        MethodVisitor mv = cw.visitMethod("longSetter""(Ljava/lang/Object;IJ)V"/*generic sig*/nullnull);
        mv.visitCode();
        // first: cast bean to proper type
        mv.visitVarInsn(, 1);
        mv.visitTypeInsn(beanClass);
        mv.visitVarInsn(, 5); // 3 args (0 == this), so 5 is the first local var slot for long
        if (props.size() <= 4) {
            _addSettersUsingIf(mvpropsbeanClass, 5, false);
        } else {
            _addSettersUsingSwitch(mvpropsbeanClass, 5, false);
        }
        // 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 _addStringSetters(ClassWriter cwList<SettableStringMethodPropertyprops,
            String beanClass)
    {
        MethodVisitor mv = cw.visitMethod("stringSetter""(Ljava/lang/Object;ILjava/lang/String;)V"nullnull);
        mv.visitCode();
        // first: cast bean to proper type
        mv.visitVarInsn(, 1);
        mv.visitTypeInsn(beanClass);
        mv.visitVarInsn(, 4); // 3 args (0 == this), so 4 is the first local var slot
        if (props.size() <= 4) {
            _addSettersUsingIf(mvpropsbeanClass, 4, false);
        } else {
            _addSettersUsingSwitch(mvpropsbeanClass, 4, false);
        }
        generateException(mvbeanClassprops.size());
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
    private static void _addObjectSetters(ClassWriter cwList<SettableObjectMethodPropertyprops,
            String beanClass)
    {
        MethodVisitor mv = cw.visitMethod("objectSetter""(Ljava/lang/Object;ILjava/lang/Object;)V"nullnull);
        mv.visitCode();
        // first: cast bean to proper type
        mv.visitVarInsn(, 1);
        mv.visitTypeInsn(beanClass);
        mv.visitVarInsn(, 4); // 3 args (0 == this), so 4 is the first local var slot
        if (props.size() <= 4) {
            _addSettersUsingIf(mvpropsbeanClass, 4, true);
        } else {
            _addSettersUsingSwitch(mvpropsbeanClass, 4, true);
        }
        generateException(mvbeanClassprops.size());
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
    
    /*
    /**********************************************************
    /* Code generation; field-based getters
    /**********************************************************
     */
    
    private static void _addIntFields(ClassWriter cwList<SettableIntFieldPropertyprops,
            String beanClass)
    {
        MethodVisitor mv = cw.visitMethod("intField""(Ljava/lang/Object;II)V"/*generic sig*/nullnull);
        mv.visitCode();
        // first: cast bean to proper type
        mv.visitVarInsn(, 1);
        mv.visitTypeInsn(beanClass);
        mv.visitVarInsn(, 4); // 3 args (0 == this), so 4 is the first local var slot
        // Ok; minor optimization, less than 4 accessors, just do IFs; over that, use switch
        if (props.size() < 4) {
            _addFieldsUsingIf(mvpropsbeanClass, 4, false);
        } else {
            _addFieldsUsingSwitch(mvpropsbeanClass, 4, false);
        }
        // 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<SettableLongFieldPropertyprops,
            String beanClass)
    {
        MethodVisitor mv = cw.visitMethod("longField""(Ljava/lang/Object;IJ)V"nullnull);
        mv.visitCode();
        // first: cast bean to proper type
        mv.visitVarInsn(, 1);
        mv.visitTypeInsn(beanClass);
        mv.visitVarInsn(, 5); // 3 args (0 == this), BUT longs use up 2 slots; hence 5
        if (props.size() < 4) {
            _addFieldsUsingIf(mvpropsbeanClass, 5, false);
        } else {
            _addFieldsUsingSwitch(mvpropsbeanClass, 5, false);
        }
        // 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<SettableStringFieldPropertyprops,
            String beanClass)
    {
        MethodVisitor mv = cw.visitMethod("stringField""(Ljava/lang/Object;ILjava/lang/String;)V"nullnull);
        mv.visitCode();
        mv.visitVarInsn(, 1);
        mv.visitTypeInsn(beanClass);
        mv.visitVarInsn(, 4);
        if (props.size() < 4) {
            _addFieldsUsingIf(mvpropsbeanClass, 4, false);
        } else {
            _addFieldsUsingSwitch(mvpropsbeanClass, 4, false);
        }
        generateException(mvbeanClassprops.size());
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
    private static void _addObjectFields(ClassWriter cwList<SettableObjectFieldPropertyprops,
            String beanClass)
    {
        MethodVisitor mv = cw.visitMethod("objectField""(Ljava/lang/Object;ILjava/lang/Object;)V"nullnull);
        mv.visitCode();
        mv.visitVarInsn(, 1);
        mv.visitTypeInsn(beanClass);
        mv.visitVarInsn(, 4);
        if (props.size() < 4) {
            _addFieldsUsingIf(mvpropsbeanClass, 4, true);
        } else {
            _addFieldsUsingSwitch(mvpropsbeanClass, 4, true);
        }
        generateException(mvbeanClassprops.size());
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
    
    /*
    /**********************************************************
    /* Helper methods, method accessor creation
    /**********************************************************
     */
    private static <T extends OptimizedSettableBeanProperty<T>> void _addSettersUsingIf(MethodVisitor mv,
            List<T> propsString beanClassint loadValueCodeint beanIndex,
            boolean mustCast)
    {
        mv.visitVarInsn(, 2); // load second arg (index)
        Label next = new Label();
        // first: check if 'index == 0'
        mv.visitJumpInsn(next); // "if not zero, goto L (skip stuff)"
        // call first getter:
        mv.visitVarInsn(beanIndex); // load local for cast bean
        mv.visitVarInsn(loadValueCode, 3);
        Method method = (Method) (props.get(0).getMember().getMember());
        Type type = Type.getType(method.getParameterTypes()[0]);
        if (mustCast) {
            mv.visitTypeInsn(type.getInternalName());
        }
        mv.visitMethodInsn(beanClassmethod.getName(), "("+type.getDescriptor()+")V");
        mv.visitInsn();
        // 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(, 2); // load second arg (index)
            mv.visitInsn([i]);
            mv.visitJumpInsn(next);
            mv.visitVarInsn(beanIndex); // load bean
            mv.visitVarInsn(loadValueCode, 3);
            method = (Method) (props.get(i).getMember().getMember());
            type = Type.getType(method.getParameterTypes()[0]);
            if (mustCast) {
                mv.visitTypeInsn(type.getInternalName());
            }
            mv.visitMethodInsn(beanClassmethod.getName(), "("+type.getDescriptor()+")V");
            mv.visitInsn();
        }
        mv.visitLabel(next);
    }
    
    private static <T extends OptimizedSettableBeanProperty<T>> void _addSettersUsingSwitch(MethodVisitor mv,
            List<T> propsString beanClassint loadValueCodeint beanIndex,
            boolean mustCast)
    {
        mv.visitVarInsn(, 2); // load second arg (index)
        Label[] labels = new Label[props.size()];
        for (int i = 0, len = labels.lengthi < len; ++i) {
            labels[i] = new Label();
        }
        Label defaultLabel = new Label();
        mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabellabels);
        for (int i = 0, len = labels.lengthi < len; ++i) {
            mv.visitLabel(labels[i]);
            mv.visitVarInsn(beanIndex); // load bean
            mv.visitVarInsn(loadValueCode, 3);
            Method method = (Method) (props.get(i).getMember().getMember());
            Type type = Type.getType(method.getParameterTypes()[0]);
            if (mustCast) {
                mv.visitTypeInsn(type.getInternalName());
            }
            mv.visitMethodInsn(beanClassmethod.getName(), "("+type.getDescriptor()+")V");
            mv.visitInsn();
        }
        mv.visitLabel(defaultLabel);
    }        
    private static <T extends OptimizedSettableBeanProperty<T>> void _addFieldsUsingIf(MethodVisitor mv,
            List<T> propsString beanClassint loadValueCodeint beanIndex,
            boolean mustCast)
    {
        mv.visitVarInsn(, 2); // load second arg (index)
        Label next = new Label();
        // first: check if 'index == 0'
        mv.visitJumpInsn(next); // "if not zero, goto L (skip stuff)"
        // first field accessor
        mv.visitVarInsn(beanIndex); // load local for cast bean
        mv.visitVarInsn(loadValueCode, 3);
        AnnotatedField field = (AnnotatedFieldprops.get(0).getMember();
        Type type = Type.getType(field.getRawType());
        if (mustCast) {
            mv.visitTypeInsn(type.getInternalName());
        }
        mv.visitFieldInsn(beanClassfield.getName(), type.getDescriptor());
        mv.visitInsn();
        // 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(, 2); // load second arg (index)
            mv.visitInsn([i]);
            mv.visitJumpInsn(next);
            mv.visitVarInsn(beanIndex); // load bean
            mv.visitVarInsn(loadValueCode, 3);
            field = (AnnotatedFieldprops.get(i).getMember();
            type = Type.getType(field.getRawType());
            if (mustCast) {
                mv.visitTypeInsn(type.getInternalName());
            }
            mv.visitFieldInsn(beanClassfield.getName(), type.getDescriptor());
            mv.visitInsn();
        }
        mv.visitLabel(next);
    }        
    private static <T extends OptimizedSettableBeanProperty<T>> void _addFieldsUsingSwitch(MethodVisitor mv,
            List<T> propsString beanClassint loadValueCodeint beanIndex,
            boolean mustCast)
    {
        mv.visitVarInsn(, 2); // load second arg (index)
        Label[] labels = new Label[props.size()];
        for (int i = 0, len = labels.lengthi < len; ++i) {
            labels[i] = new Label();
        }
        Label defaultLabel = new Label();
        mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabellabels);
        for (int i = 0, len = labels.lengthi < len; ++i) {
            mv.visitLabel(labels[i]);
            mv.visitVarInsn(beanIndex); // load bean
            mv.visitVarInsn(loadValueCode, 3); // put 'value' to stack
            AnnotatedField field = (AnnotatedFieldprops.get(i).getMember();
            Type type = Type.getType(field.getRawType());
            if (mustCast) {
                mv.visitTypeInsn(type.getInternalName());
            }
            mv.visitFieldInsn(beanClassfield.getName(), type.getDescriptor());
            mv.visitInsn();
        }
        mv.visitLabel(defaultLabel);
    }        
New to GrepCode? Check out our FAQ X