Menu

#5 enhance without calling constructor

open
nobody
None
5
2008-08-24
2008-08-24
luc_p
No

Make able to create enhanced instance of object without calling the object to construct class constructor.

This is usefull to create deserialization of enhanced object, this enable enhance object without default constructor, ensure no methods will be called at construction. In case of deserialization this make able to set the fields state before any method call.

below how it is done by sun native serialization:

/* TestConstruction.class the object to construct class */
constr = ReflectionFactory.getReflectionFactory()
.newConstructorForSerialization(TestConstruction.class,
Object.class.getConstructor(new Class[0]));
/* construct without calling class constructor*/
constr.newInstance();

Discussion

  • Esko Luontola

    Esko Luontola - 2008-11-08

    This feature would be very useful and it should be easy to implement by using Objenesis: http://objenesis.googlecode.com/svn/docs/index.html

     
  • Esko Luontola

    Esko Luontola - 2008-11-08

    I just had a look at CGLIB's sources, and it seems that modifying net.sf.cglib.proxy.Enhancer#emitConstructors would make it possible to generate classes which do not call the superclass's constructor. Objenesis (or ReflectionFactory) can not/need not be used, because CGLIB generates the bytecode by itself with ASM. CGLIB just would need to generate a constructor which calls java.lang.Object's constructor instead of the direct superclass's constructor.

    Here is a proof of concept, that how the constructor should be generated:

    import org.objectweb.asm.ClassWriter;
    import org.objectweb.asm.MethodVisitor;
    import org.objectweb.asm.Opcodes;

    public class Experiment implements Opcodes {

    private static final String CHILD2_CLASS = "$GENERATED$Child2";

    public static void main(String[] args) throws Exception {
    ClassLoader classLoader = new ClassLoader() {
    {
    byte[] child2 = createChild2();
    defineClass(CHILD2_CLASS, child2, 0, child2.length);
    }
    };

    Object child1 = new Child1();
    Object child2 = classLoader.loadClass(CHILD2_CLASS).newInstance();
    Object parent = new Parent();

    System.out.println("child1 = " + child1);
    System.out.println("child2 = " + child2);
    System.out.println("parent = " + parent);
    }

    public static byte[] createChild2() {
    ClassWriter cw = new ClassWriter(0);
    MethodVisitor mv;
    cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, "$GENERATED$Child2", null, "Experiment$Parent", null);
    {
    mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
    mv.visitCode();
    mv.visitVarInsn(ALOAD, 0);
    mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
    mv.visitInsn(RETURN);
    mv.visitMaxs(1, 1);
    mv.visitEnd();
    }
    cw.visitEnd();
    return cw.toByteArray();
    }

    public static class Parent {
    public Parent() {
    System.out.println("Parent's constructor was called");
    System.out.println("getClass() = " + getClass());
    System.out.println("--");
    }
    }

    public static class Child1 extends Parent {
    public Child1() {
    }
    }
    }

     
  • Esko Luontola

    Esko Luontola - 2008-11-08

    Here is the same code a bit better formatted: http://nopaste.info/8289941dc9.html

    For some reason this tracker does not seem to have any way to attach files to comments... :/