Package one.nio.serial.gen

Source Code of one.nio.serial.gen.StubGenerator

package one.nio.serial.gen;

import one.nio.gen.BytecodeGenerator;
import one.nio.mgt.Management;
import one.nio.serial.FieldDescriptor;
import one.nio.serial.Repository;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;

public class StubGenerator extends BytecodeGenerator {
    public static final StubGenerator INSTANCE = new StubGenerator();
    private static final String PACKAGE_PREFIX = "sun/reflect/";

    StubGenerator() {
        Management.registerMXBean(this, "one.nio.serial:type=BytecodeGenerator");
    }

    private synchronized Class<?> defineClassIfNotExists(String internalClassName, byte[] classData) {
        String className = internalClassName.replace('/', '.');
        Class<?> result = findLoadedClass(className);
        if (result == null) {
            Repository.log.warn("Generating stub for class " + className);
            result = defineClass(classData);
        }
        return result;
    }

    public static Class generateRegular(String className, String superName, FieldDescriptor[] fds) {
        String internalClassName = PACKAGE_PREFIX + className;

        ClassWriter cv = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        cv.visit(V1_5, ACC_PUBLIC | ACC_FINAL, internalClassName, null, superName,
                new String[] { "java/io/Serializable" });

        MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, superName, "<init>", "()V");
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();

        if (fds != null) {
            for (FieldDescriptor fd : fds) {
                String name = fd.name();
                String oldName = null;

                int p = name.indexOf('|');
                if (p >= 0) {
                    oldName = name.substring(p + 1);
                    name = name.substring(0, p);
                }

                FieldVisitor fv = cv.visitField(ACC_PRIVATE, name, Type.getDescriptor(fd.type().resolve()), null, null);
                if (oldName != null) {
                    AnnotationVisitor av = fv.visitAnnotation("Lone/nio/serial/Renamed;", true);
                    av.visit("from", oldName);
                    av.visitEnd();
                }
                fv.visitEnd();
            }
        }

        cv.visitEnd();
        return INSTANCE.defineClassIfNotExists(internalClassName, cv.toByteArray());
    }

    public static Class generateEnum(String className, String[] constants) {
        String internalClassName = PACKAGE_PREFIX + className;

        ClassWriter cv = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        cv.visit(V1_5, ACC_PUBLIC | ACC_FINAL | ACC_ENUM, internalClassName, null, "java/lang/Enum", null);

        String classDesc = 'L' + internalClassName + ';';
        for (String c : constants) {
            cv.visitField(ACC_PUBLIC | ACC_STATIC | ACC_FINAL, c, classDesc, null, null).visitEnd();
        }

        String arrayDesc = '[' + classDesc;
        cv.visitField(ACC_PRIVATE | ACC_STATIC | ACC_FINAL, "$VALUES", arrayDesc, null, null).visitEnd();

        MethodVisitor mv = cv.visitMethod(ACC_PRIVATE, "<init>", "(Ljava/lang/String;I)V", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitVarInsn(ILOAD, 2);
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Enum", "<init>", "(Ljava/lang/String;I)V");
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();

        mv = cv.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
        mv.visitCode();
        emitInt(mv, constants.length);
        mv.visitTypeInsn(ANEWARRAY, internalClassName);

        for (int i = 0; i < constants.length; i++) {
            mv.visitInsn(DUP);
            emitInt(mv, i);
            mv.visitTypeInsn(NEW, internalClassName);
            mv.visitInsn(DUP);
            mv.visitLdcInsn(constants[i]);
            emitInt(mv, i);
            mv.visitMethodInsn(INVOKESPECIAL, internalClassName, "<init>", "(Ljava/lang/String;I)V");
            mv.visitInsn(DUP);
            mv.visitFieldInsn(PUTSTATIC, internalClassName, constants[i], classDesc);
            mv.visitInsn(AASTORE);
        }

        mv.visitFieldInsn(PUTSTATIC, internalClassName, "$VALUES", arrayDesc);
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();

        mv = cv.visitMethod(ACC_PUBLIC | ACC_STATIC, "values", "()" + arrayDesc, null, null);
        mv.visitCode();
        mv.visitFieldInsn(GETSTATIC, internalClassName, "$VALUES", arrayDesc);
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();

        mv = cv.visitMethod(ACC_PUBLIC | ACC_STATIC, "valueOf", "(Ljava/lang/String;)" + classDesc, null, null);
        mv.visitCode();
        mv.visitLdcInsn(Type.getObjectType(internalClassName));
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESTATIC, "java/lang/Enum", "valueOf", "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;");
        mv.visitTypeInsn(CHECKCAST, internalClassName);
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();

        cv.visitEnd();
        return INSTANCE.defineClassIfNotExists(internalClassName, cv.toByteArray());
    }
}
TOP

Related Classes of one.nio.serial.gen.StubGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.