package org.cikaros.mapping.core;
import lombok.Data;
import org.objectweb.asm.*;
import javax.annotation.Generated;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import static org.objectweb.asm.Opcodes.*;
public class ClassGenerator {
private static class Util {
/**
* 包路径转路径
*/
public static String packageToPath(String packageName) {
return packageName.replace('.', '/');
}
/**
* 首字母大写(进行字母的ascii编码前移,效率是最高的)
*/
public static String getMethodName(String fieldName) {
char[] chars = fieldName.toCharArray();
chars[0] = toUpperCase(chars[0]);
return String.valueOf(chars);
}
/**
* 字符转成大写
*/
public static char toUpperCase(char c) {
if (97 <= c && c <= 122) {
c ^= 32;
}
return c;
}
}
private final ClassWriter CW = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
public void clazz(String clazz, Class<?> supper, Class<?>[] interfaces) {
String superName = Util.packageToPath(supper.getTypeName());
CW.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, Util.packageToPath(clazz), null, superName, Arrays.stream(interfaces).map(Class::getTypeName).map(Util::packageToPath).toArray(String[]::new));
this.annotation(Generated.class,av->{
av.visit("comments", "Generated By org.cikaros.mapping.core.ClassGenerator");
av.visit("date", DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss:SSS").format(LocalDateTime.now()));
});
this.defaultConstructor();
}
private void defaultConstructor() {
this.defineMethod(Opcodes.ACC_PUBLIC, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE), mv -> {
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Util.packageToPath(Object.class.getTypeName()), "<init>", "()V", false);
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(1, 1);
});
}
public void argsConstructor(String clazz, Map<String, Class<?>> args) {
List<Map.Entry<String, Class<?>>> entries = args.entrySet().stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toList());
//生成私有属性
entries.forEach(arg -> this.field(Opcodes.ACC_PRIVATE, arg.getValue(), arg.getKey()));
this.defineMethod(Opcodes.ACC_PUBLIC, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, entries.stream().map(Map.Entry::getValue).map(Type::getType).toArray(Type[]::new)), mv -> {
// 调用父类构造函数
mv.visitVarInsn(Opcodes.ALOAD, 0); // 加载 this
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Util.packageToPath(Object.class.getTypeName()), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE), false);
// 假设参数按顺序传递,从第二个参数开始(索引1)
int index = 1; // this 的索引是0,参数从1开始
for (Map.Entry<String, Class<?>> arg : entries) {
mv.visitVarInsn(Opcodes.ALOAD, 0); // 加载 this
// 根据参数类型加载参数到栈上
Class<?> argType = arg.getValue();
if (argType == int.class) {
mv.visitVarInsn(Opcodes.ILOAD, index);
} else if (argType == float.class) {
mv.visitVarInsn(Opcodes.FLOAD, index);
} else if (argType == double.class) {
mv.visitVarInsn(Opcodes.DLOAD, index);
} else if (argType == long.class) {
mv.visitVarInsn(Opcodes.LLOAD, index);
} else if (argType == short.class) {
mv.visitVarInsn(Opcodes.ILOAD, index);
} // 这里可以继续添加其他基本类型的处理
else {
// 对于引用类型
mv.visitVarInsn(Opcodes.ALOAD, index);
}
// 这里可以添加对参数的处理代码,例如设置字段值等
mv.visitFieldInsn(Opcodes.PUTFIELD, Util.packageToPath(clazz), arg.getKey(), Type.getDescriptor(argType));
index++;
}
// 正常结束方法
mv.visitInsn(Opcodes.RETURN);
// 计算操作数栈和局部变量表的大小
mv.visitMaxs(1, 1); // 这里需要根据实际情况调整
});
}
private void field(int accessFlags, Class<?> type, String field) {
CW.visitField(accessFlags, field, Type.getDescriptor(type), null, null);
}
public void annotation(Class<?> type,Consumer<AnnotationVisitor> body){
AnnotationVisitor av = CW.visitAnnotation(Type.getDescriptor(Generated.class), true);
body.accept(av);
av.visitEnd();
}
public void defineMethod(int accessFlags, String method, String descriptor, Consumer<MethodVisitor> body) {
MethodVisitor getterMV = CW.visitMethod(accessFlags, method, descriptor, null, null);
getterMV.visitCode();
body.accept(getterMV);
getterMV.visitEnd();
}
public void setter(String clazz, Class<?> type, String field) {
String setterName = String.format("set%s", Util.getMethodName(field));
String setterDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(type));
this.defineMethod(Opcodes.ACC_PUBLIC, setterName, setterDescriptor, mv -> {
mv.visitVarInsn(Opcodes.ALOAD, 0); // 加载当前类的引用(对于静态方法,这里可以省略)
mv.visitVarInsn(Opcodes.ALOAD, 1); // 加载参数中的String引用
mv.visitFieldInsn(Opcodes.PUTFIELD, Util.packageToPath(clazz), field, Type.getDescriptor(type));
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(2, 2); // 设置操作数栈和局部变量表的最大大小
});
}
public void getter(String clazz, Class<?> type, String field) {
String getterName = String.format("get%s", Util.getMethodName(field));
String getterDescriptor = Type.getMethodDescriptor(Type.getType(type));
this.defineMethod(Opcodes.ACC_PUBLIC, getterName, getterDescriptor, mv -> {
mv.visitVarInsn(Opcodes.ALOAD, 0); // 加载当前类的引用(对于静态方法,这里可以省略)
mv.visitFieldInsn(Opcodes.GETFIELD, Util.packageToPath(clazz), field, Type.getDescriptor(type));
mv.visitInsn(Opcodes.ARETURN);
mv.visitMaxs(1, 1); // 设置操作数栈和局部变量表的最大大小
});
}
public <T, R> void apply(Class<T> in, Class<R> out) {
String setterDescriptor = Type.getMethodDescriptor(Type.getType(Object.class), Type.getType(Object.class));
Method[] gets = Arrays.stream(in.getMethods()).filter(mv -> mv.getName().startsWith("get")).toArray(Method[]::new);
Method[] sets = Arrays.stream(out.getMethods()).filter(mv -> mv.getName().startsWith("set")).toArray(Method[]::new);
this.defineMethod(Opcodes.ACC_PUBLIC, "apply", setterDescriptor, mv -> {
mv.visitTypeInsn(Opcodes.NEW, Util.packageToPath(out.getTypeName())); // 创建一个新的 B 对象
mv.visitInsn(DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Util.packageToPath(out.getTypeName()), "<init>", "()V", false); // 调用 B 对象的构造方法
mv.visitVarInsn(ASTORE, 2);
for (int i = 0; i < Math.min(gets.length, sets.length); i++) {
Method get = gets[i];
Method set = sets[i];
//仅当getter返回类型与setter参数类型相等时
if (get.getReturnType().equals(Arrays.stream(set.getParameterTypes()).findFirst().orElse(null))) {
mv.visitVarInsn(Opcodes.ALOAD, 2);
mv.visitVarInsn(Opcodes.ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, Util.packageToPath(in.getTypeName()));
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Util.packageToPath(in.getTypeName()), gets[0].getName(), Type.getMethodDescriptor(get), false); // 调用 A 对象的 getProperty 方法
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Util.packageToPath(out.getTypeName()), sets[0].getName(), Type.getMethodDescriptor(set), false); // 调用 B 对象的 setProperty 方法
}
}
mv.visitVarInsn(Opcodes.ALOAD, 2);
mv.visitInsn(ARETURN); // 返回B对象
mv.visitMaxs(-1, -1);
});
}
public byte[] getBytes() {
return CW.toByteArray();
}
public void toFile(String location, String clazz) {
Path path = Paths.get(location, String.format("%s.class", Util.packageToPath(clazz)));
File file = path.toFile();
if (file.exists()) {
boolean _ = file.delete();
}
try (OutputStream out = Files.newOutputStream(path, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) {
out.write(CW.toByteArray());
} catch (IOException e) {
Logger.getGlobal().info(e.getMessage());
}
}
}