Javassist.java 4.1 KB
package com.skua.tool.javassist;

import javassist.*;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author sonin
 * @date 2021/12/5 18:44
 */
public class Javassist {

    private static final Map<String, Class> cache = new HashMap<>();

    private String className;

    private String similarClassName;

    private Map<String, Class> fieldMap;

    Javassist() {
        fieldMap = new LinkedHashMap<>();
    }

    /**
     * 待创建的类
     *
     * @param className
     * @return
     */
    public Javassist className(String className) {
        this.className = className;
        return this;
    }

    /**
     * 新创建的类class属性继承自similarClass
     *
     * @param similarClassName
     * @return
     */
    public Javassist similarClassName(String similarClassName) {
        this.similarClassName = similarClassName;
        return this;
    }

    /**
     * 添加字段(会生成get/set方法)
     *
     * @param fieldName
     * @param fieldType
     * @return
     */
    public Javassist field(String fieldName, Class fieldType) {
        fieldMap.put(fieldName, fieldType);
        return this;
    }

    public Class buildClass() throws Exception {
        if (similarClassName == null) {
            initClass(1);
        } else {
            if (!cache.containsKey(similarClassName)) {
                initClass(1);
            } else {
                initClass(2);
            }
        }
        return cache.get(className);
    }

    public Class getClass(String className) {
        return cache.getOrDefault(className, Object.class);
    }

    /**
     * type: 1 => 根据field生成类; 2 => 根据similarClass生成相似类
     *
     * @param type
     * @throws Exception
     */
    private void initClass(int type) throws Exception {
        if (!cache.containsKey(className)) {
            synchronized (cache) {
                if (!cache.containsKey(className)) {
                    // 创建ClassPool
                    ClassPool classPool = ClassPool.getDefault();
                    // 生成类的名称
                    CtClass ctClass = classPool.makeClass(className);
                    if (type == 1) {
                        for (Map.Entry<String, Class> item : fieldMap.entrySet()) {
                            initField(classPool, ctClass, item.getValue().getName(), item.getKey());
                        }
                    } else if (type == 2) {
                        Class similarClass = cache.get(similarClassName);
                        for (Field field : similarClass.getDeclaredFields()) {
                            initField(classPool, ctClass, field.getType().getName(), field.getName());
                        }
                    }
                    // 创建构造方法,指定了构造方法的参数类型和构造方法所属的类
                    CtConstructor ctConstructor = new CtConstructor(new CtClass[]{}, ctClass);
                    // 设置方法体
                    ctConstructor.setBody("{\n}");
                    ctClass.addConstructor(ctConstructor);
                    // 缓存生成的类
                    cache.put(className, ctClass.toClass());
                }
            }
        }
    }

    private void initField(ClassPool classPool, CtClass ctClass, String fieldType, String fieldName) throws Exception {
        // 创建字段,指定了字段类型、字段名称、字段所属的类
        CtField ctField = new CtField(classPool.get(fieldType), fieldName, ctClass);
        // 指定该字段使用private修饰
        ctField.setModifiers(Modifier.PRIVATE);
        // 将字段添加到ctClass中
        ctClass.addField(ctField);
        // 设置ctClass字段的getter/setter方法
        String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        String setMethodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        ctClass.addMethod(CtNewMethod.getter(getMethodName, ctField));
        ctClass.addMethod(CtNewMethod.setter(setMethodName, ctField));
    }

}