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);
}
};
}
}
}