com.github.jonathanxd.codeapi.test.asm.Transformer.java Source code

Java tutorial

Introduction

Here is the source code for com.github.jonathanxd.codeapi.test.asm.Transformer.java

Source

/*
 *      CodeAPI-BytecodeWriter - Framework to generate Java code and Bytecode code. <https://github.com/JonathanxD/CodeAPI-BytecodeWriter>
 *
 *         The MIT License (MIT)
 *
 *      Copyright (c) 2017 TheRealBuggy/JonathanxD (https://github.com/JonathanxD/ & https://github.com/TheRealBuggy/) <jonathan.scripter@programmer.net>
 *      Copyright (c) contributors
 *
 *
 *      Permission is hereby granted, free of charge, to any person obtaining a copy
 *      of this software and associated documentation files (the "Software"), to deal
 *      in the Software without restriction, including without limitation the rights
 *      to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *      copies of the Software, and to permit persons to whom the Software is
 *      furnished to do so, subject to the following conditions:
 *
 *      The above copyright notice and this permission notice shall be included in
 *      all copies or substantial portions of the Software.
 *
 *      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *      IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *      FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *      AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *      LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *      OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *      THE SOFTWARE.
 */
package com.github.jonathanxd.codeapi.test.asm;

import com.github.jonathanxd.codeapi.CodeAPI;
import com.github.jonathanxd.codeapi.bytecode.BytecodeClass;
import com.github.jonathanxd.codeapi.bytecode.BytecodeOptions;
import com.github.jonathanxd.codeapi.bytecode.VisitLineType;
import com.github.jonathanxd.codeapi.bytecode.common.MVData;
import com.github.jonathanxd.codeapi.bytecode.gen.BytecodeGenerator;
import com.github.jonathanxd.codeapi.common.Data;
import com.github.jonathanxd.codeapi.helper.Predefined;
import com.github.jonathanxd.codeapi.literal.Literals;
import com.github.jonathanxd.codeapi.test.InvocationsTest_;

import org.junit.Assert;
import org.junit.Test;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.List;

public class Transformer {

    public static byte[] toByteArray(InputStream input) throws IOException {
        byte[] buffer = new byte[8192];
        int bytesRead;
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        while ((bytesRead = input.read(buffer)) != -1) {
            output.write(buffer, 0, bytesRead);
        }
        return output.toByteArray();
    }

    @Test
    public void transform() throws Throwable {

        WrappedPrintStream wrappedPrintStream = new WrappedPrintStream(System.out);
        System.setOut(wrappedPrintStream);

        BytecodeGenerator bytecodeGenerator = new BytecodeGenerator();

        bytecodeGenerator.getOptions().set(BytecodeOptions.VISIT_LINES, VisitLineType.FOLLOW_CODE_SOURCE);

        BytecodeClass[] bytecodeClasses = bytecodeGenerator.gen(InvocationsTest_.$()._2());

        byte[] bytes = bytecodeClasses[0].getBytecode();

        ClassReader cr = new ClassReader(bytes);
        ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);

        cr.accept(new MyClassVisitor(Opcodes.ASM5, cw), 0);

        byte[] bytes1 = cw.toByteArray();

        ResultSaver.save(this.getClass(), bytes1);

        BCLoader bcLoader = new BCLoader();

        Class<?> define = bcLoader.define("fullName.InvocationsTest__Generated", bytes1);

        Object o = define.newInstance();

        MethodHandle check = MethodHandles.lookup().findVirtual(define, "check",
                MethodType.methodType(Boolean.TYPE, Integer.TYPE));

        try {
            boolean b = (boolean) check.bindTo(o).invoke(9);
        } catch (Exception e) {
            e.printStackTrace();
        }

        Assert.assertTrue(wrappedPrintStream.printed.contains("Inicializado!"));
        Assert.assertTrue(wrappedPrintStream.printed.contains("XSD"));
    }

    static class MyClassVisitor extends ClassVisitor {
        public MyClassVisitor(int api) {
            super(api);
        }

        public MyClassVisitor(int api, ClassVisitor cv) {
            super(api, cv);
        }

        @Override
        public void visit(int version, int access, String name, String signature, String superName,
                String[] interfaces) {
            super.visit(52, access, name, signature, superName, interfaces);
        }

        @Override
        public MethodVisitor visitMethod(int access, String name, String desc, String signature,
                String[] exceptions) {
            if (name.equals("<init>")) {
                return new MyVisitor(Opcodes.ASM5, super.visitMethod(access, name, desc, signature, exceptions));
            }

            if (name.contains("fragment$")) {
                if (desc.endsWith("Ljava/lang/String;")) {
                    return new FragmentTransformer(Opcodes.ASM5,
                            super.visitMethod(access, name, desc, signature, exceptions));
                }
            }

            return super.visitMethod(access, name, desc, signature, exceptions);
        }
    }

    private static class FragmentTransformer extends MethodVisitor {

        private final BytecodeGenerator bytecodeGenerator = new BytecodeGenerator();

        public FragmentTransformer(int api, MethodVisitor mv) {
            super(api, mv);
        }

        @Override
        public void visitInsn(int opcode) {

            if (opcode == Opcodes.ARETURN) {
                MVData mvData = new MVData(super.mv, new ArrayList<>());
                Data mapData = new Data();

                super.visitInsn(Opcodes.POP);

                bytecodeGenerator.gen(
                        CodeAPI.sourceOfParts(CodeAPI.returnValue(String.class, Literals.STRING("XSD"))), mapData,
                        mvData);

                //bytecodeGenerator.gen
            }

            super.visitInsn(opcode);
        }
    }

    private static class MyVisitor extends MethodVisitor {

        private final BytecodeGenerator bytecodeGenerator = new BytecodeGenerator();

        public MyVisitor(int api, MethodVisitor mv) {
            super(api, mv);
        }

        public MyVisitor(int api) {
            super(api);
        }

        @Override
        public void visitInsn(int opcode) {

            if (opcode == Opcodes.RETURN) {
                MVData mvData = new MVData(super.mv, new ArrayList<>());

                bytecodeGenerator.gen(
                        CodeAPI.sourceOfParts(Predefined.invokePrintln(Literals.STRING("Inicializado!"))),
                        new Data(), mvData);

                //bytecodeGenerator.gen
            }

            super.visitInsn(opcode);
        }
    }

    static class WrappedPrintStream extends PrintStream {

        public List<String> printed = new ArrayList<>();

        public WrappedPrintStream(PrintStream toWrap) {
            super(toWrap);
        }

        @Override
        public void println(String str) {
            super.println(str);
            printed.add(str);
        }

        @Override
        public void println(Object obj) {
            super.println(obj);
            printed.add(String.valueOf(obj));
        }
    }
}