Skip to content

REPO: Replace current metadata solution with a bytecode generated subclass in a classloader solution #9

@jasonewall

Description

@jasonewall

Here is a really basic example using Javassist as the bytecode generator.

import ca.thejayvm.playground.java8.Person;
import javassist.*;

import java.lang.reflect.Modifier;

/**
 * Created by jason on 14-11-16.
 */
public class JavassistMain {
    public static void main(String[] args) throws NotFoundException, CannotCompileException, IllegalAccessException, InstantiationException {
        Class<? extends Person> personMetaClass = createClass();
        Person peep = personMetaClass.newInstance();
        peep.setFirstName("Jason");
        peep.setLastName("Wall");
        System.out.println(peep.getFirstName());
        InvocationTracker tracker = (InvocationTracker)peep;
        tracker.getInvocations().forEach(System.out::println);
    }

    @SuppressWarnings("unchecked")
    public static Class<? extends Person> createClass() throws NotFoundException, CannotCompileException {
        return getCtClass().toClass();
    }

    private static CtClass getCtClass() throws NotFoundException, CannotCompileException {
        ClassPool pool = ClassPool.getDefault();
        CtClass list = pool.get(java.util.List.class.getName());
        CtClass invocationTracker = pool.get(InvocationTracker.class.getName());
        CtClass subClass = pool.makeClass(Person.class.getName() + "Meta");
        final CtClass superClass = pool.get(Person.class.getName());
        subClass.setSuperclass(superClass);
        subClass.setInterfaces(new CtClass[]{ invocationTracker });
        subClass.setModifiers(Modifier.PUBLIC);

        CtField invocations = CtField.make("public java.util.List invocations = new java.util.ArrayList();", subClass);
        subClass.addField(invocations);

        CtMethod getInvocations = CtNewMethod.make(list, "getInvocations", new CtClass[]{}, new CtClass[]{}, "{ return invocations; }", subClass);
        subClass.addMethod(getInvocations);

        CtMethod setFirstName = CtNewMethod.make("public void setFirstName(String s) { invocations.add(\"firstName\"); super.setFirstName(s); }", subClass);
        subClass.addMethod(setFirstName);
        return subClass;
    }
}

The Metadata classloader also needs to be a child of the hex ClassLoader layer. It also needs to be cached at that level so it probably cannot be a singleton. An individual application will probably be responsible for declaring and storing its own metadata cache.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions