浏览代码

增加动态创建class

zhouhao 7 年之前
父节点
当前提交
5d16a77142

+ 22 - 0
hsweb-boost/hsweb-boost-compiler/pom.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>hsweb-boost</artifactId>
+        <groupId>org.hswebframework.web</groupId>
+        <version>3.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>hsweb-boost-compiler</artifactId>
+
+    <dependencies>
+        <!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
+        <dependency>
+            <groupId>org.javassist</groupId>
+            <artifactId>javassist</artifactId>
+            <version>3.22.0-GA</version>
+        </dependency>
+    </dependencies>
+</project>

+ 123 - 0
hsweb-boost/hsweb-boost-compiler/src/main/java/org/hswebframework/web/boost/Compiler.java

@@ -0,0 +1,123 @@
+package org.hswebframework.web.boost;
+
+import javassist.*;
+import javassist.bytecode.AnnotationsAttribute;
+import javassist.bytecode.ConstPool;
+import lombok.Getter;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * @author zhouhao
+ * @since 3.0
+ */
+public class Compiler<I> {
+    public ClassPool  classPool = new ClassPool(true);
+    public static final AtomicLong counter   = new AtomicLong(1);
+
+    private CtClass  ctClass;
+    private Class<I> superClass;
+    @Getter
+    private String   className;
+    @Getter
+    private String   classFullName;
+
+    private Class<I> targetClass;
+
+    public static <I> Compiler<I> create(Class<I> superClass, String... classPathString) {
+        try {
+            return new Compiler<>(superClass, classPathString);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public Compiler(Class<I> superClass, String... classPathString) throws Exception {
+        if (superClass == null) {
+            throw new NullPointerException("superClass can not be null");
+        }
+        this.superClass = superClass;
+        if (classPathString != null) {
+            for (String path : classPathString) {
+                classPool.insertClassPath(path);
+            }
+        } else {
+            ClassPath classPath = new ClassClassPath(this.getClass());
+            classPool.insertClassPath(classPath);
+        }
+        className = superClass.getSimpleName() + "HSwebBoostGen" + counter.getAndAdd(1);
+        classFullName = superClass.getPackage() + "." + className;
+
+        ctClass = classPool.makeClass(classFullName);
+        if (superClass != Object.class) {
+            if (superClass.isInterface()) {
+                ctClass.setInterfaces(new CtClass[]{classPool.get(superClass.getName())});
+            } else {
+                ctClass.setSuperclass(classPool.get(superClass.getName()));
+            }
+        }
+        addConstructor("public " + className + "(){}");
+    }
+
+    public Compiler<I> addMethod(String code) {
+        return handleException(() -> ctClass.addMethod(CtNewMethod.make(code, ctClass)));
+    }
+
+    public Compiler<I> addConstructor(String code) {
+        return handleException(() -> ctClass.addConstructor(CtNewConstructor.make(code, ctClass)));
+    }
+
+    public Compiler<I> addField(String code) {
+        return addField(code, null);
+    }
+
+    public Compiler<I> addField(String code, String annotation) {
+        return handleException(() -> {
+            CtField ctField = CtField.make(code, ctClass);
+            if (null != annotation) {
+                ConstPool constPool = ctClass.getClassFile().getConstPool();
+                AnnotationsAttribute attributeInfo =
+                        new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
+                attributeInfo.addAnnotation(
+                        new javassist.bytecode.annotation.Annotation(annotation, constPool));
+                ctField.getFieldInfo().addAttribute(attributeInfo);
+            }
+            ctClass.addField(ctField);
+        });
+    }
+
+    private Compiler<I> handleException(Task task) {
+        try {
+            task.run();
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new RuntimeException(e.getMessage(), e);
+        }
+        return this;
+    }
+
+
+    public I newInstance() {
+        try {
+            return getTargetClass().newInstance();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public Class<I> getTargetClass() {
+        if (targetClass == null) {
+            try {
+                targetClass = ctClass.toClass();
+            } catch (CannotCompileException e) {
+                throw new RuntimeException(e.getMessage(), e);
+            }
+        }
+        return targetClass;
+    }
+
+    interface Task {
+        void run() throws Exception;
+    }
+}

+ 33 - 0
hsweb-boost/hsweb-boost-compiler/src/test/java/JaninoTest.java

@@ -0,0 +1,33 @@
+import javassist.ClassClassPath;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtNewMethod;
+import org.junit.Test;
+
+
+/**
+ * TODO 完成注释
+ *
+ * @author zhouhao
+ * @since
+ */
+public class JaninoTest {
+
+    @Test
+    public void Test() throws Exception {
+        ClassPool classPool = new ClassPool(true);
+        classPool.insertClassPath(new ClassClassPath(this.getClass()));
+
+        CtClass ctClass = classPool.makeClass("Test1");
+        ctClass.setInterfaces(new CtClass[]{classPool.get(TestApi.class.getName())});
+
+        ctClass.addMethod(CtNewMethod.make("public void hello(int i){System.out.println(i);}", ctClass));
+
+        TestApi api = (TestApi) ctClass.toClass().newInstance();
+        api.hello(1);
+    }
+
+    interface TestApi {
+        void hello(int i);
+    }
+}

+ 28 - 0
hsweb-boost/hsweb-boost-compiler/src/test/java/org/hswebframework/web/boost/CompilerTest.java

@@ -0,0 +1,28 @@
+package org.hswebframework.web.boost;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * TODO 完成注释
+ *
+ * @author zhouhao
+ * @since
+ */
+public class CompilerTest {
+
+    @Test
+    public void Test() throws Exception {
+        Compiler<TestApi> compiler = Compiler.create(TestApi.class)
+                .addMethod("public void hello(int i){System.out.println(\"aa\"+i);}");
+        Class<TestApi> czz = compiler.getTargetClass();
+
+        System.out.println(czz.getConstructors().length);
+        compiler.newInstance().hello(11);
+    }
+
+    public interface TestApi {
+         void hello(int i);
+    }
+}