Example usage for org.objectweb.asm.tree ClassNode visitField

List of usage examples for org.objectweb.asm.tree ClassNode visitField

Introduction

In this page you can find the example usage for org.objectweb.asm.tree ClassNode visitField.

Prototype

@Override
    public FieldVisitor visitField(final int access, final String name, final String descriptor,
            final String signature, final Object value) 

Source Link

Usage

From source file:nova.core.wrapper.mc.forge.v17.asm.lib.ComponentInjector.java

License:Open Source License

private Class<? extends T> construct(List<Class<? extends Component>> components) {

    // Map components to specified wrapped interfaces
    Map<Class<?>, Class<? extends Component>> intfComponentMap = new HashMap<>();
    for (Class<? extends Component> component : components) {
        for (Passthrough pt : component.getAnnotationsByType(Passthrough.class)) {
            Class<?> intf;/* w  ww. j ava  2s.  co m*/
            try {
                intf = Class.forName(pt.value());
            } catch (ClassNotFoundException exec) {
                throw new ClassLoaderUtil.ClassLoaderException(
                        "Invalid passthrough \"%s\" on component %s, the specified interface doesn't exist.",
                        pt.value(), component);
            }
            if (!intf.isAssignableFrom(component)) {
                throw new ClassLoaderUtil.ClassLoaderException(
                        "Invalid passthrough \"%s\" on component %s, the specified interface isn't implemented.",
                        pt.value(), component);
            }
            if (intfComponentMap.containsKey(intf)) {
                throw new ClassLoaderUtil.ClassLoaderException(
                        "Duplicate Passthrough interface found: %s (%s, %s)", pt.value(), component,
                        intfComponentMap.get(intf));
            }
            intfComponentMap.put(intf, component);
        }
    }

    // Create new ClassNode from cached bytes
    ClassNode clazzNode = new ClassNode();
    String name = Type.getInternalName(baseClazz);
    String classname = name + "_$$_NOVA_" + cache.size();

    // Inject block field
    clazzNode.visit(V1_8, ACC_PUBLIC | ACC_SUPER, classname, null, name,
            intfComponentMap.keySet().stream().map(Type::getInternalName).toArray(s -> new String[s]));
    clazzNode.visitField(ACC_PRIVATE | ACC_FINAL, "$$_provider", Type.getDescriptor(ComponentProvider.class),
            null, null).visitEnd();

    // Add constructors
    for (Constructor<?> constructor : baseClazz.getConstructors()) {
        int mod = constructor.getModifiers();
        String descr = Type.getConstructorDescriptor(constructor);

        if (Modifier.isFinal(mod) || Modifier.isPrivate(mod)) {
            continue;
        }
        MethodVisitor mv = clazzNode.visitMethod(mod, "<init>", descr, null,
                ASMHelper.getExceptionTypes(constructor));

        // Call super constructor
        mv.visitCode();
        // load this
        mv.visitVarInsn(ALOAD, 0);
        Class<?>[] parameters = constructor.getParameterTypes();
        for (int i = 0; i < constructor.getParameterCount(); i++) {
            // variables
            mv.visitVarInsn(Type.getType(parameters[i]).getOpcode(ILOAD), i + 1);
        }
        mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(baseClazz), "<init>", descr, false);
        // return
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    // Add methods
    for (Class<?> intf : intfComponentMap.keySet()) {
        // Create class constant
        Type clazzConst = Type.getType(intf.getClass());

        for (Method m : intf.getMethods()) {
            boolean isVoid = m.getReturnType() == null;
            String descr = Type.getMethodDescriptor(m);

            MethodVisitor mv = clazzNode.visitMethod(ACC_PUBLIC, m.getName(), descr, null,
                    ASMHelper.getExceptionTypes(m));
            mv.visitCode();

            // load block instance
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, classname, "$$_provider", Type.getDescriptor(ComponentProvider.class));
            mv.visitLdcInsn(clazzConst);
            // load component instance
            mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(ComponentProvider.class), "get",
                    Type.getMethodDescriptor(Type.getType(Component.class), Type.getType(Class.class)), false);

            // add parameters
            Class<?>[] parameters = m.getParameterTypes();
            for (int i = 0; i < m.getParameterCount(); i++) {
                mv.visitVarInsn(Type.getType(parameters[i]).getOpcode(ILOAD), i + 1);
            }

            // invoke
            mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(intf), m.getName(), descr, true);
            mv.visitInsn(isVoid ? RETURN : Type.getType(m.getReturnType()).getOpcode(IRETURN));
            mv.visitMaxs(0, 0);
            mv.visitEnd();
        }
    }

    clazzNode.visitEnd();

    return ASMHelper.defineClass(clazzNode, ClassWriter.COMPUTE_MAXS, baseClazz.getProtectionDomain());
}