欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java编程奇淫技巧之让java帮我们生成java代码后不停服,直接编译为class并且反射为对象直接使用

程序员文章站 2022-05-25 23:46:39
...

项目中总不乏简单的CURD,深圳稍微复杂点的CURD,是不需要写后端代码的,只要抽象的好,完全可以一个base类全部搞定,前端代码也可以使用 js来做简单的配置 直接生成  见 : https://blog.csdn.net/shuaizai88/article/details/84670602

我们可以让java去解析js的列配置来拼接sql,注册到mybatis中,然后执行,返回map,但是遇到一个问题,我项目中有一个服务是必须传对象才能处理,因此我需要类对象,而不是map或者json,但是我是通过JS来配置CRUD的并么有写一行代码怎么办呢????

   于是找动态生成java的解决方案。

     首先看到了此篇文章:https://my.oschina.net/u/3049601/blog/1862308  介绍了由复杂到简单的各种方案,最终决定用最简单的方案来冬天根据配置生成java代码 - > 编译javaclass->使用自定义类加载器加载class -> 遍历数据库读取的内容->反射通过class得到对象->调用系统服务把这堆对象传进去做数据处理->把对象转换为json。

     上干货,我已经写好了,直接运行main方法即可,你需要自己写一个java 文件然后读取他放到我提供的方法中然后就可以得到class对象了。

    

package com.ylm.core.clazz;

import com.ylm.common.utils.FileUtils;
import com.ylm.common.utils.ReflectUtils;
import com.ylm.core.base.bean.SuperBean;

import javax.tools.*;
import java.io.*;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.CharBuffer;
import java.util.*;
import javax.tools.JavaFileObject.Kind;
/**
 *  把一段Java字符串变成类
 * @ProjectName: framework_v2_idea2
 * @Package: com.ylm.core.clazz
 * @ClassName: MemoryClassLoader
 * @Author: JackWang
 * @CreateDate: 2018/12/5 0005 20:26
 * @UpdateUser: JackWang
 * @UpdateDate: 2018/12/5 0005 20:26
 * @Version: 1.0
 */
public class MemoryClassLoader extends URLClassLoader {



    private Map<String, byte[]> classBytes = new HashMap<String, byte[]>();

    /**
     * 单利默认的
     */
    private static final MemoryClassLoader defaultLoader = new MemoryClassLoader();

    private MemoryClassLoader(){ super(new URL[0], MemoryClassLoader.class.getClassLoader());}

    /**
     * 获取默认的类加载器
     * @return 类加载器对象
     */
    public static  MemoryClassLoader getInstrance(){
        return defaultLoader;
    }

    /**
     * 注册Java 字符串到内存类加载器中
     * @param className 类名字
     * @param javaStr Java字符串
     */
    public void registerJava(String className,String javaStr)
    {
        this.classBytes.putAll(compile( className,  javaStr) );
    }

    private static Map<String, byte[]> compile(String className, String javaStr) {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager stdManager = compiler.getStandardFileManager(null, null, null);
        try (MemoryJavaFileManager manager = new MemoryJavaFileManager(stdManager)) {
            JavaFileObject javaFileObject = manager.makeStringSource(className, javaStr);
            JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, Arrays.asList(javaFileObject));
            if (task.call())
                return manager.getClassBytes();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


  /*  public static void main(String[] args) throws FileNotFoundException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        *//*JavacProcessingEnvironment n = null;*//*
        MemoryClassLoader loader = MemoryClassLoader.getInstrance();
        loader.registerJava("Test", FileUtils.readTxtFile(new FileInputStream(new File("d:/Test.java"))));
        Class testClass = loader.findClass("Test");
        Object obj = testClass.newInstance();
        SuperBean<?> superb = (SuperBean)obj;
        superb.getTransMap().put("hello","world");
        System.out.println(superb.getTransMap());

    }*/

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] buf = classBytes.get(name);
        if (buf == null) {
            return super.findClass(name);
        }
        classBytes.remove(name);
        return defineClass(name, buf, 0, buf.length);
    }
}


/**
 *  内存Java文件管理器
 */
class MemoryJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {

    // compiled classes in bytes:
    final Map<String, byte[]> classBytes = new HashMap<String, byte[]>();

    final Map<String, List<JavaFileObject>> classObjectPackageMap = new HashMap<>();

    MemoryJavaFileManager(JavaFileManager fileManager) {
        super(fileManager);
    }

    public Map<String, byte[]> getClassBytes() {
        return new HashMap<String, byte[]>(this.classBytes);
    }

    @Override
    public void flush() throws IOException {
    }

    @Override
    public void close() throws IOException {
        classBytes.clear();
    }

    @Override
    public Iterable<JavaFileObject> list(Location location,
                                         String packageName,
                                         Set<Kind> kinds,
                                         boolean recurse)
            throws IOException
    {
        Iterable<JavaFileObject> it = super.list(location, packageName, kinds, recurse);

        if (kinds.contains(Kind.CLASS)) {
            final List<JavaFileObject> javaFileObjectList = classObjectPackageMap.get(packageName);
            if (javaFileObjectList != null) {
                if (it != null) {
                    for (JavaFileObject javaFileObject : it) {
                        javaFileObjectList.add(javaFileObject);
                    }
                }
                return javaFileObjectList;
            } else {
                return it;
            }
        } else {
            return it;
        }
    }

    @Override
    public String inferBinaryName(Location location, JavaFileObject file) {
        if (file instanceof MemoryInputJavaClassObject) {
            return ((MemoryInputJavaClassObject)file).inferBinaryName();
        }
        return super.inferBinaryName(location, file);
    }

    @Override
    public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, Kind kind,
                                               FileObject sibling) throws IOException {
        if (kind == Kind.CLASS) {
            return new MemoryOutputJavaClassObject(className);
        } else {
            return super.getJavaFileForOutput(location, className, kind, sibling);
        }
    }

    JavaFileObject makeStringSource(String className, final String code) {
        String classPath = className.replace('.', '/') + Kind.SOURCE.extension;

        return new SimpleJavaFileObject(URI.create("string:///" + classPath), Kind.SOURCE) {
            @Override
            public CharBuffer getCharContent(boolean ignoreEncodingErrors) {
                return CharBuffer.wrap(code);
            }
        };
    }

    void makeBinaryClass(String className, final byte[] bs) {
        JavaFileObject javaFileObject = new MemoryInputJavaClassObject(className, bs);

        String packageName = "";
        int pos = className.lastIndexOf('.');
        if (pos > 0) {
            packageName = className.substring(0, pos);
        }
        List<JavaFileObject> javaFileObjectList = classObjectPackageMap.get(packageName);
        if (javaFileObjectList == null) {
            javaFileObjectList = new LinkedList<>();
            javaFileObjectList.add(javaFileObject);

            classObjectPackageMap.put(packageName, javaFileObjectList);
        } else {
            javaFileObjectList.add(javaFileObject);
        }
    }

    class MemoryInputJavaClassObject extends SimpleJavaFileObject {
        final String className;
        final byte[] bs;

        MemoryInputJavaClassObject(String className, byte[] bs) {
            super(URI.create("string:///" + className.replace('.', '/') + Kind.CLASS.extension), Kind.CLASS);
            this.className = className;
            this.bs = bs;
        }

        @Override
        public InputStream openInputStream() {
            return new ByteArrayInputStream(bs);
        }

        public String inferBinaryName() {
            return className;
        }
    }

    class MemoryOutputJavaClassObject extends SimpleJavaFileObject {
        final String className;

        MemoryOutputJavaClassObject(String className) {
            super(URI.create("string:///" + className.replace('.', '/') + Kind.CLASS.extension), Kind.CLASS);
            this.className = className;
        }

        @Override
        public OutputStream openOutputStream() {
            return new FilterOutputStream(new ByteArrayOutputStream()) {
                @Override
                public void close() throws IOException {
                    out.close();
                    ByteArrayOutputStream bos = (ByteArrayOutputStream) out;
                    byte[] bs = bos.toByteArray();
                    classBytes.put(className, bs);
                    makeBinaryClass(className, bs);
                }
            };
        }
    }
}