<!-- https://mvnrepository.com/artifact/javassist/javassist --> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> </dependency>
package com.noob; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.MethodDescriptor; import java.beans.PropertyDescriptor; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import javassist.CannotCompileException; import javassist.ClassPool; import javassist.CtClass; import javassist.CtField; import javassist.CtMethod; import javassist.NotFoundException; import lombok.Data; import com.alibaba.fastjson.JSON; public class TestJavassist { public static void main(String[] args) { try { ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream readIn = new ObjectOutputStream(bo); readIn.writeObject(modifyClass()); ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream writeOut = new ObjectInputStream(bi); A a = A.class.cast(writeOut.readObject()); // 反序列化對象類型是序列化對象的父類或自己 System.out.println("序列化對象:---" + JSON.toJSONString(a)); System.out.println(a.getA_a()); } catch (Exception e) { e.printStackTrace(); } } private static Object modifyClass() throws NotFoundException, CannotCompileException, IntrospectionException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { /* System.out.println("-----------修改前的A.class信息--------------------"); for (Method method : A.class.getDeclaredMethods()) { System.out.println("method:----" + method.getName()); } for (Field field : A.class.getDeclaredFields()) { System.out.println("field:----" + field.getName()); }*/ ClassPool pool = ClassPool.getDefault(); // 獲取一個A類的CtClass對象 CtClass ctClass = pool.get("com.noob.A"); // 爲ctClass設置一個父類 ctClass.setSuperclass(pool.get("com.noob.B")); // 爲cTclass對象添加一個屬性name ctClass.addField(CtField.make("private String addField;", ctClass)); ctClass.addMethod(CtMethod.make("public void setAddField(String addField){this.addField = addField;}", ctClass)); ctClass.addMethod(CtMethod.make("public String getAddField(){return this.addField;}", ctClass)); ctClass.removeField(ctClass.getDeclaredField("A_a")); ctClass.removeMethod(ctClass.getDeclaredMethod("getA_a")); ctClass.removeMethod(ctClass.getDeclaredMethod("setA_a")); // 把 A.class 中的A_a 相關信息刪掉. // 獲取ctClass對象對應的Class對象cls Class cls = ctClass.toClass(); // 對cls類進行內省,獲得對象BeanInfo BeanInfo beanInfo = Introspector.getBeanInfo(cls, Object.class); System.out.println("-----------Javassist 修改操做對象信息--------------------"); MethodDescriptor[] methodDescriptors = beanInfo.getMethodDescriptors(); // 獲取beanInfo的方法描述對象 for (int i = 0; i < methodDescriptors.length; i++) { System.out.println("method:----" + methodDescriptors[i].getName()); } PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();// 獲取beanInfo的屬性描述對象 for (int i = 0; i < propertyDescriptors.length; i++) { System.out.println("field:----" + propertyDescriptors[i].getDisplayName()); } System.out.println("-----------修改後直接經過A.class獲取信息--------------------"); for (Method method : A.class.getDeclaredMethods()) { System.out.println("method:----" + method.getName()); } for (Field field : A.class.getDeclaredFields()) { System.out.println("field:----" + field.getName()); } Object obj = cls.newInstance(); for (Method method : cls.getDeclaredMethods()) { if (method.getName().startsWith("set")) { method.invoke(obj, "test" + method.getName()); } } return obj; } } @Data class A implements Serializable { private static final long serialVersionUID = 1L; private String A_a, A_b, A_c; } @Data class B implements Serializable { private static final long serialVersionUID = 1L; private String B_d, B_e, B_f; }
-----------Javassist 修改操做對象信息-------------------- method:----setB_e method:----getAddField method:----setB_f method:----setB_d method:----getB_d method:----getB_e method:----getB_f method:----setA_b method:----setA_c method:----canEqual method:----getA_b method:----getA_c method:----setAddField field:----a_b field:----a_c field:----addField field:----b_d field:----b_e field:----b_f -----------修改後直接經過A.class獲取信息-------------------- method:----equals method:----toString method:----hashCode method:----getA_b method:----getA_c method:----setA_b method:----setA_c method:----canEqual method:----setAddField method:----getAddField field:----serialVersionUID field:----A_b field:----A_c field:----addField 序列化對象:---{"a_b":"testsetA_b","a_c":"testsetA_c","addField":"testsetAddField"} Exception in thread "main" java.lang.NoSuchMethodError: com.noob.A.getA_a()Ljava/lang/String; at com.noob.TestJavassist.main(TestJavassist.java:39)
【新增 字段、方法】java
【刪除 字段、方法】json
測試結論:
經過javassist修改A.class以後:測試
-----------修改前的A.class信息-------------------- method:----equals method:----toString method:----hashCode method:----getA_a method:----setA_a method:----getA_b method:----getA_c method:----setA_b method:----setA_c method:----canEqual field:----serialVersionUID field:----A_a field:----A_b field:----A_c javassist.CannotCompileException: by java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "com/noob/A" at javassist.ClassPool.toClass(ClassPool.java:1085) at javassist.ClassPool.toClass(ClassPool.java:1028) at javassist.ClassPool.toClass(ClassPool.java:986) at javassist.CtClass.toClass(CtClass.java:1079) at com.noob.TestJavassist.modifyClass(TestJavassist.java:71) at com.noob.TestJavassist.main(TestJavassist.java:34) Caused by: java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "com/noob/A" at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:763) at java.lang.ClassLoader.defineClass(ClassLoader.java:642) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at javassist.ClassPool.toClass2(ClassPool.java:1098) at javassist.ClassPool.toClass(ClassPool.java:1079) ... 5 more javassist.CannotCompileException: by java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "com/noob/A" at javassist.ClassPool.toClass(ClassPool.java:1085) at javassist.ClassPool.toClass(ClassPool.java:1028) at javassist.ClassPool.toClass(ClassPool.java:986) at javassist.CtClass.toClass(CtClass.java:1079) at com.noob.TestJavassist.modifyClass(TestJavassist.java:71) at com.noob.TestJavassist.main(TestJavassist.java:34) Caused by: java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "com/noob/A" at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:763) at java.lang.ClassLoader.defineClass(ClassLoader.java:642) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at javassist.ClassPool.toClass2(ClassPool.java:1098) at javassist.ClassPool.toClass(ClassPool.java:1079) ... 5 more javassist.CannotCompileException: by java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "com/noob/A" at javassist.ClassPool.toClass(ClassPool.java:1085) at javassist.ClassPool.toClass(ClassPool.java:1028) at javassist.ClassPool.toClass(ClassPool.java:986) at javassist.CtClass.toClass(CtClass.java:1079) at com.noob.TestJavassist.modifyClass(TestJavassist.java:71) at com.noob.TestJavassist.main(TestJavassist.java:34) Caused by: java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "com/noob/A" at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:763) at java.lang.ClassLoader.defineClass(ClassLoader.java:642) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at javassist.ClassPool.toClass2(ClassPool.java:1098) at javassist.ClassPool.toClass(ClassPool.java:1079) ... 5 more