Deprecated:这种方式在SpringBoot项目中不太好用,打成jar包后会有很多问题
请参考:https://blog.csdn.net/zhaohongfei_358/article/details/121383997
案例说明
我们有一个Person类:
package test;
import lombok.Data;
@Data
public abstract class Person {
private String name;
public abstract void sayHello();
}
Person类有一个抽象方法 sayHello
,但是具体有哪些Person并不知道,需要配置在数据库中,然后动态进行生成Person的子类。
动态生成类工具类
<dependency>
<groupId>com.itranswarp</groupId>
<artifactId>compiler</artifactId>
<version>1.0</version>
</dependency>
如果是SpringBoot项目,最好加上
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.8</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
工具类代码如下:
package test;
import com.itranswarp.compiler.JavaStringCompiler;
import java.util.Map;
public class CompilerUtil {
public static Class generateClass(String javaFilename, String packageName, String javaCode) throws Exception {
JavaStringCompiler compiler = new JavaStringCompiler();
String prefix = String.format("package %s;", packageName);
Map<String, byte[]> map = compiler.compile(javaFilename + ".java", prefix + "\n" + javaCode);
return compiler.loadClass(packageName + "." + javaFilename, map);
}
}
动态生成类
package test;
import com.itranswarp.compiler.JavaStringCompiler;
import java.util.Map;
public class CompilerUtil {
public static Class generateClass(String javaFilename, String packageName, String javaCode) throws Exception {
JavaStringCompiler compiler = new JavaStringCompiler();
String prefix = String.format("package %s;", packageName);
Map<String, byte[]> map = compiler.compile(javaFilename + ".java", prefix + "\n" + javaCode);
return compiler.loadClass(packageName + "." + javaFilename, map);
}
public static void main(String[] args) throws Exception {
String teacherCode = "public class Teacher extends Person {\n" +
"\n" +
" @Override\n" +
" public void sayHello() {\n" +
" System.out.println(\"My name is \" + getName() + \", I am a teacher\");\n" +
" }\n" +
"}\n";
Class teacherClass = generateClass("Teacher", "test", teacherCode);
Person person = (Person) teacherClass.newInstance();
person.setName("Tom");
person.sayHello();
}
}
My name is Tom, I am a teacher
生产环境报错
打Jar包后(生产环境)报错:错误: 找不到符号
本地运行很好,到生产上,就报:cannot find symbol
java.lang.RuntimeException: Compilation failed.
at com.itranswarp.compiler.JavaStringCompiler.compile(JavaStringCompiler.java:46)
at com.fsk.ehr.utils.SalaryUtil.getOrGenerateSalaryComputerClass(SalaryUtil.java:51)
解决方案:
参考文档:https://github.com/michaelliao/compiler/issues/5
25行报空指针
public JavaStringCompiler() {
this.compiler = ToolProvider.getSystemJavaCompiler();
this.stdManager = compiler.getStandardFileManager(null, null, null); // 报空指针
}
解决方案:
查看生产环境是否装了jre,没有装jdk,如果不装jdk,是没法使用动态编译功能的。