package com.powernode.javassist;

import com.powernode.bank.dao.AccountDao;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;

public class JavassistTest
{
    @Test
    public void TestGenerateAccountDaoImpl() throws Exception
    {
        //获取类池
        ClassPool pool = ClassPool.getDefault();
        //制造类
        CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
        //制造接口
        CtClass Interface = pool.makeInterface("com.powernode.bank.dao.AccountDao");
        //实现接口
        ctClass.addInterface(Interface);
        //获取所有的方法,获取接口中所有的方法
        Method[] methods = AccountDao.class.getDeclaredMethods();
        Arrays.stream(methods).forEach(method ->
        {
            //method是接口的抽象方法,我们现在需要实现这些方法
            try
            {
                //"public void insert(){System.out.println(123);}"我们要拼接出来的结果
                StringBuilder methodCode = new StringBuilder();
                methodCode.append("public ");//追加修饰符列表
                methodCode.append(method.getReturnType().getName());//最佳返回值类型
                methodCode.append(" ");
                methodCode.append(method.getName());//追加方法名字
                methodCode.append("(");
                //拼接参数,并用逗号隔开
                Class<?>[] parameterTypes = method.getParameterTypes();
                for (int i = 0; i < parameterTypes.length; i++)
                {
                    Class<?> parameterType = parameterTypes[i];
                    methodCode.append(parameterType.getName());
                    methodCode.append(" ");
//                    methodCode.append(parameterType.getName().toLowerCase().charAt(0) + parameterType.getName().substring(1));
                    methodCode.append("arg" + i);
                    if(i != parameterTypes.length - 1)
                    {
                        methodCode.append(",");
                    }
                }
                methodCode.append("){");
                methodCode.append("System.out.println(123);");
                //添加Return语句
                String simpleName = method.getReturnType().getSimpleName();
                if("void".equals(simpleName)) {}
                else if("int".equals(simpleName))
                {
                    methodCode.append("return 1;");
                }
                else if("String".equals(simpleName))
                {
                    methodCode.append("return \"hello\";");
                }
                else if("double".equals(simpleName))
                {
                    methodCode.append("return 1;");
                }
                methodCode.append("}");
                System.out.println(methodCode);
                CtMethod ctMethod = CtMethod.make(methodCode.toString(),ctClass);
                ctClass.addMethod(ctMethod);
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        });
        //实现接口中所有的方法
        //在内存中生成class,并加载到JVM中
        Class<?> aClass = ctClass.toClass();
//        //创建对象
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
        AccountDao accountDao = (AccountDao) declaredConstructor.newInstance();
        //调用方法
        accountDao.insert("aaaa");
        accountDao.update("aaaa",1000.0);
        accountDao.selectByActno("aaaa");
        accountDao.delete();
    }
    @Test
    public void TestGenerateFirstClass() throws Exception
    {
        //获取类池,用于生成Class
        ClassPool pool = ClassPool.getDefault();
        //需要完整全类名
        CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
        //制造方法
        String methodCode = "public void insert(){System.out.println(123);}";
        CtMethod ctMethod = CtMethod.make(methodCode,ctClass);
        //将方法添加到类中
        ctClass.addMethod(ctMethod);
        //生成类(在内存中生成class)
        ctClass.toClass();
        //类加载返回AccountDaoImpl的字节码
        //这里内存里就有这个类了,所以可以使用Class.forName创建class对象
        Class<?> aClass = Class.forName("com.powernode.bank.dao.impl.AccountDaoImpl");
        //创建对象
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
        Object o = declaredConstructor.newInstance();
        //获取AccountDaoImpl的Insert方法
        Method insert = aClass.getDeclaredMethod("insert");
        insert.invoke(o);
    }
    @Test
    public void TestGenerateImpl() throws Exception
    {
        //获取类池
        ClassPool pool = ClassPool.getDefault();
        //制造类
        CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
        //制造接口
        CtClass ctInterface = pool.makeInterface("com.powernode.bank.dao.AccountDao");
        //添加接口到类中
        ctClass.addInterface(ctInterface);//相当于AccountDaoImpl去implements接口AccountDao
        //实现接口的方法(制造方法先)
        //制造方法
        CtMethod ctMethod = CtMethod.make("public void delete(){System.out.println(\"hello delete!\");}", ctClass);
        ctClass.addMethod(ctMethod);
        //在内存中生成类(同时将生成的类加载到JVM中)
        Class<?> aClass = ctClass.toClass();
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
        AccountDao accountDao = (AccountDao)declaredConstructor.newInstance();
        accountDao.delete();
    }
} 
 
package com.powernode.javassist;

import com.powernode.bank.dao.AccountDao;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;

public class JavassistTest
{
    @Test
    public void TestGenerateAccountDaoImpl() throws Exception
    {
        //获取类池
        ClassPool pool = ClassPool.getDefault();
        //制造类
        CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
        //制造接口
        CtClass Interface = pool.makeInterface("com.powernode.bank.dao.AccountDao");
        //实现接口
        ctClass.addInterface(Interface);
        //获取所有的方法,获取接口中所有的方法
        Method[] methods = AccountDao.class.getDeclaredMethods();
        Arrays.stream(methods).forEach(method ->
        {
            //method是接口的抽象方法,我们现在需要实现这些方法
            try
            {
                //"public void insert(){System.out.println(123);}"我们要拼接出来的结果
                StringBuilder methodCode = new StringBuilder();
                methodCode.append("public ");//追加修饰符列表
                methodCode.append(method.getReturnType().getName());//最佳返回值类型
                methodCode.append(" ");
                methodCode.append(method.getName());//追加方法名字
                methodCode.append("(");
                //拼接参数,并用逗号隔开
                Class<?>[] parameterTypes = method.getParameterTypes();
                for (int i = 0; i < parameterTypes.length; i++)
                {
                    Class<?> parameterType = parameterTypes[i];
                    methodCode.append(parameterType.getName());
                    methodCode.append(" ");
//                    methodCode.append(parameterType.getName().toLowerCase().charAt(0) + parameterType.getName().substring(1));
                    methodCode.append("arg" + i);
                    if(i != parameterTypes.length - 1)
                    {
                        methodCode.append(",");
                    }
                }
                methodCode.append("){");
                methodCode.append("System.out.println(123);");
                //添加Return语句
                String simpleName = method.getReturnType().getSimpleName();
                if("void".equals(simpleName)) {}
                else if("int".equals(simpleName))
                {
                    methodCode.append("return 1;");
                }
                else if("String".equals(simpleName))
                {
                    methodCode.append("return \"hello\";");
                }
                else if("double".equals(simpleName))
                {
                    methodCode.append("return 1;");
                }
                methodCode.append("}");
                System.out.println(methodCode);
                CtMethod ctMethod = CtMethod.make(methodCode.toString(),ctClass);
                ctClass.addMethod(ctMethod);
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        });
        //实现接口中所有的方法
        //在内存中生成class,并加载到JVM中
        Class<?> aClass = ctClass.toClass();
//        //创建对象
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
        AccountDao accountDao = (AccountDao) declaredConstructor.newInstance();
        //调用方法
        accountDao.insert("aaaa");
        accountDao.update("aaaa",1000.0);
        accountDao.selectByActno("aaaa");
        accountDao.delete();
    }
    @Test
    public void TestGenerateFirstClass() throws Exception
    {
        //获取类池,用于生成Class
        ClassPool pool = ClassPool.getDefault();
        //需要完整全类名
        CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
        //制造方法
        String methodCode = "public void insert(){System.out.println(123);}";
        CtMethod ctMethod = CtMethod.make(methodCode,ctClass);
        //将方法添加到类中
        ctClass.addMethod(ctMethod);
        //生成类(在内存中生成class)
        ctClass.toClass();
        //类加载返回AccountDaoImpl的字节码
        //这里内存里就有这个类了,所以可以使用Class.forName创建class对象
        Class<?> aClass = Class.forName("com.powernode.bank.dao.impl.AccountDaoImpl");
        //创建对象
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
        Object o = declaredConstructor.newInstance();
        //获取AccountDaoImpl的Insert方法
        Method insert = aClass.getDeclaredMethod("insert");
        insert.invoke(o);
    }
    @Test
    public void TestGenerateImpl() throws Exception
    {
        //获取类池
        ClassPool pool = ClassPool.getDefault();
        //制造类
        CtClass ctClass = pool.makeClass("com.powernode.bank.dao.impl.AccountDaoImpl");
        //制造接口
        CtClass ctInterface = pool.makeInterface("com.powernode.bank.dao.AccountDao");
        //添加接口到类中
        ctClass.addInterface(ctInterface);//相当于AccountDaoImpl去implements接口AccountDao
        //实现接口的方法(制造方法先)
        //制造方法
        CtMethod ctMethod = CtMethod.make("public void delete(){System.out.println(\"hello delete!\");}", ctClass);
        ctClass.addMethod(ctMethod);
        //在内存中生成类(同时将生成的类加载到JVM中)
        Class<?> aClass = ctClass.toClass();
        Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
        AccountDao accountDao = (AccountDao)declaredConstructor.newInstance();
        accountDao.delete();
    }
}
package com.powernode.bank.dao;

public interface AccountDao
{
    void delete();
    int insert(String actno);
    int update(String actno,Double balance);
    String selectByActno(String actno);
} 
 
package com.powernode.bank.dao;

public interface AccountDao
{
    void delete();
    int insert(String actno);
    int update(String actno,Double balance);
    String selectByActno(String actno);
}
<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.powernode</groupId>
    <artifactId>javassist-Test</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.29.1-GA</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project> 
 
<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.powernode</groupId>
    <artifactId>javassist-Test</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.29.1-GA</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>