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

com.fasterxml.jackson.module.afterburner.deser.CreatorOptimizer Maven / Gradle / Ivy

Go to download

Experimental extension to Jackson (http://jackson.codehaus.org) used to enhance access functionality using bytecode generation.

The newest version!
package com.fasterxml.jackson.module.afterburner.deser;

import static org.objectweb.asm.Opcodes.*;

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import org.codehaus.jackson.map.deser.ValueInstantiator;
import org.codehaus.jackson.map.deser.std.StdValueInstantiator;
import org.codehaus.jackson.map.introspect.AnnotatedWithParams;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;

import com.fasterxml.jackson.module.afterburner.util.DynamicPropertyAccessorBase;
import com.fasterxml.jackson.module.afterburner.util.MyClassLoader;

/**
 * Helper class that tries to generate {@link ValueInstantiator} class
 * that calls constructors and/or factory methods directly, instead
 * of using Reflection.
 */
public class CreatorOptimizer
    extends DynamicPropertyAccessorBase
{
    protected final Class _valueClass;
    
    protected final MyClassLoader _classLoader;
    
    protected final StdValueInstantiator _originalInstantiator;

    public CreatorOptimizer(Class valueClass, MyClassLoader classLoader,
            StdValueInstantiator orig)
    {
        _valueClass = valueClass;
        _classLoader = classLoader;
        _originalInstantiator = orig;
    }

    public ValueInstantiator createOptimized()
    {
        // for now, only consider need to handle default creator
        AnnotatedWithParams defaultCreator = _originalInstantiator.getDefaultCreator();
        if (defaultCreator != null) {
            AnnotatedElement elem = defaultCreator.getAnnotated();
            if (elem instanceof Constructor) {
                return createSubclass((Constructor) elem, null);
            }
            if (elem instanceof Method) {
                Method m = (Method) elem;
                if (Modifier.isStatic(m.getModifiers())) {
                    return createSubclass(null, m);
                }
            }
        }
        return null;
    }

    protected ValueInstantiator createSubclass(Constructor ctor, Method factory)
    {
        MyClassLoader loader = (_classLoader == null) ?
            new MyClassLoader(_valueClass.getClassLoader(), true) : _classLoader;
        String srcName = _valueClass.getName() + "$Creator4JacksonDeserializer";
        Class impl = null;
        try {
            impl = loader.loadClass(srcName);
        } catch (ClassNotFoundException e) { }
        if (impl == null) {
            byte[] bytecode = generateOptimized(srcName, ctor, factory);
            impl = loader.loadAndResolve(srcName, bytecode);
        }
        ValueInstantiator inst;
        try {
            inst = (ValueInstantiator) impl.newInstance();
        } catch (Exception e) {
            throw new IllegalStateException("Failed to generate accessor class '"+srcName+"': "+e.getMessage(), e);
        }
        return inst;
    }

    protected byte[] generateOptimized(String srcName, Constructor ctor, Method factory)
    {
            ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
            String superClass = internalClassName(OptimizedValueInstantiator.class.getName());
            String generatedClass = internalClassName(srcName);
            
            cw.visit(V1_5, ACC_PUBLIC + ACC_SUPER, generatedClass, null, superClass, null);
            cw.visitSource(srcName + ".java", null);

            // First: must define 2 constructors:
            // (a) default constructor, for creating bogus instance (just calls default instance)
            // (b) copy-constructor which takes StdValueInstantiator instance, passes to superclass
            final String optimizedValueInstDesc = Type.getDescriptor(OptimizedValueInstantiator.class);
            final String stdValueInstDesc = Type.getDescriptor(StdValueInstantiator.class);

            // default (no-arg) constructor:
            MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null);
            mv.visitCode();
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, superClass, "", "()V");
            mv.visitInsn(RETURN);
            mv.visitMaxs(0, 0);
            mv.visitEnd();
            // then single-arg constructor
            mv = cw.visitMethod(ACC_PUBLIC, "", "("+stdValueInstDesc+")V", null, null);
            mv.visitCode();
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitMethodInsn(INVOKESPECIAL, superClass, "", "("+stdValueInstDesc+")V");
            mv.visitInsn(RETURN);
            mv.visitMaxs(0, 0);
            mv.visitEnd();

            // and then non-static factory method to use second constructor (implements base-class method)
            // protected abstract OptimizedValueInstantiator with(StdValueInstantiator src);
            mv = cw.visitMethod(ACC_PUBLIC, "with", "("
                    +stdValueInstDesc+")"+optimizedValueInstDesc, null, null);
            mv.visitCode();
            mv.visitTypeInsn(NEW, generatedClass);
            mv.visitInsn(DUP);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitMethodInsn(INVOKESPECIAL, generatedClass, "", "("+stdValueInstDesc+")V");
            mv.visitInsn(ARETURN);
            mv.visitMaxs(0, 0);
            mv.visitEnd();

            // And then override: public Object createUsingDefault()
            mv = cw.visitMethod(ACC_PUBLIC, "createUsingDefault", "()Ljava/lang/Object;", null, null);
            mv.visitCode();
            
            if (ctor != null) {
                addCreator(mv, ctor);
            } else {
                addCreator(mv, factory);
            }
            mv.visitInsn(ARETURN);
            mv.visitMaxs(0, 0);
            mv.visitEnd();

            cw.visitEnd();
            return cw.toByteArray();
    }

    protected void addCreator(MethodVisitor mv, Constructor ctor)
    {
        String valueClassInternal = Type.getInternalName(ctor.getDeclaringClass());
        mv.visitTypeInsn(NEW, valueClassInternal);
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL, valueClassInternal, "", "()V");
    }

    protected void addCreator(MethodVisitor mv, Method factory)
    {
        Class valueClass = factory.getReturnType();
        mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(factory.getDeclaringClass()),
                factory.getName(), "()"+Type.getDescriptor(valueClass));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy