如何使用 javassist 实例化在运行时创建的 class?
How to instantiate a class created at runtime with javassist?
我刚开始使用 javassist,我似乎不知道如何实例化在运行时创建的 class。
makeNewClass()
方法使 NewClass
class 变成这样:
public bin.objects.base.NewClass {
public int quantity = 5;
private float weight = 30.25f;
public float getWeight() { return weight; }
public void setWeight(float weight) { this.weight = weight; }
public float totalWeight() { return quantity * getWeight(); }
}
这个方法很好用:
public void makeNewClass() throws NotFoundException, IOException, CannotCompileException {
// ClassMaker maker holds the CtClass object and handles all the "making"
ClassMaker maker = new ClassMaker("bin.objects.base.NewClass");
maker.addField(CtClass.intType, "quantity", "5", Modifier.PUBLIC);
maker.addField(CtClass.floatType, "weight", "30.25f", Modifier.PRIVATE);
maker.addMethod(Modifier.PUBLIC, CtClass.floatType, "totalWeight", null, null,
"{ return quantity * getWeight(); }", null, MethodType.standard);
maker.getCtClass().writeFile();
}
现在开始做题。此方法应该实例化 NewClass
,访问它的字段并调用它的方法。
public void testNewClass()
throws Throwable {
CtClass ctclass = ClassPool.getDefault().get("bin.objects.base.NovaClasse");
Object testClass = ctclass.toClass(new Loader(), null);
// Throws NoSuchFieldException
Field q = testClass.getClass().getDeclaredField("quantity");
int quantity = (int) q.get(testClass);
Class[] cArg = new Class[1];
cArg[0] = Float.class;
// Throws NoSuchMethodException
Method m = testClass.getClass().getDeclaredMethod("getWeight", cArg);
float weight = (float) m.invoke(testClass, null);
// Throws NoSuchMethodException
m = testClass.getClass().getDeclaredMethod("totalWeight", cArg);
float totalWeight = (float) m.invoke(testClass, null);
System.out.println("quantity = " + quantity +
"weight = " + weight +
"totalWeight = " + totalWeight);
}
现在,我已经弄清楚 testClass 实际上是作为 java.lang.Class
的实例初始化的,而不是 bin.objects.base.NewClass
。所以,很明显,它不会找到NewClass的字段和方法。
问题是我该如何解决?我尝试使用 java.lang.Class.cast()
方法,但没有成功。
尝试使用反射将您的 class 对象作为 :
Field q = Class.forName("bin.objetos.base.NovaClasse").getDeclaredField("quantity");
您也可以对其他字段执行相同的操作。
我终于找到问题所在了。
看来是ClassLoader的问题。我找到了答案 in this post。为了解决它,我只包含了这一行:
Class newClasse = ctclass.toClass(this.getClass().getClassLoader(),
this.getClass().getProtectionDomain());
@nullpointer 的回答也有帮助。
因此,经过更多更改后,testNewClass()
方法最终变成了这样:
public void testNewClass()
throws Throwable {
CtClass ctclass = ClassPool.getDefault().get("bin.objects.base.NewClass");
Class newClass = ctclass.toClass(this.getClass().getClassLoader(),
this.getClass().getProtectionDomain());
Object objNewClass = newClass.newInstance();
System.out.println("Accessing the field 'public int quantity'...");
Field q = newClass.getDeclaredField("quantity");
int quantity = (int) q.get(objNewClass);
System.out.println("quantity = " + quantity);
System.out.println("\nAccessing the field 'private float weight' " +
"through the method 'public float getWeight()'...");
Method m = newClass.getDeclaredMethod("getWeight", null);
float weight = (float) m.invoke(objNewClass, null);
System.out.println("weight = " + weight);
System.out.println("\nAccessing the method 'public float totalWeight()'...");
m = newClass.getDeclaredMethod("totalWeight", null);
float totalWeight = (float) m.invoke(objNewClass, null);
System.out.println("totalWeight = " + totalWeight);
}
我刚开始使用 javassist,我似乎不知道如何实例化在运行时创建的 class。
makeNewClass()
方法使 NewClass
class 变成这样:
public bin.objects.base.NewClass {
public int quantity = 5;
private float weight = 30.25f;
public float getWeight() { return weight; }
public void setWeight(float weight) { this.weight = weight; }
public float totalWeight() { return quantity * getWeight(); }
}
这个方法很好用:
public void makeNewClass() throws NotFoundException, IOException, CannotCompileException {
// ClassMaker maker holds the CtClass object and handles all the "making"
ClassMaker maker = new ClassMaker("bin.objects.base.NewClass");
maker.addField(CtClass.intType, "quantity", "5", Modifier.PUBLIC);
maker.addField(CtClass.floatType, "weight", "30.25f", Modifier.PRIVATE);
maker.addMethod(Modifier.PUBLIC, CtClass.floatType, "totalWeight", null, null,
"{ return quantity * getWeight(); }", null, MethodType.standard);
maker.getCtClass().writeFile();
}
现在开始做题。此方法应该实例化 NewClass
,访问它的字段并调用它的方法。
public void testNewClass()
throws Throwable {
CtClass ctclass = ClassPool.getDefault().get("bin.objects.base.NovaClasse");
Object testClass = ctclass.toClass(new Loader(), null);
// Throws NoSuchFieldException
Field q = testClass.getClass().getDeclaredField("quantity");
int quantity = (int) q.get(testClass);
Class[] cArg = new Class[1];
cArg[0] = Float.class;
// Throws NoSuchMethodException
Method m = testClass.getClass().getDeclaredMethod("getWeight", cArg);
float weight = (float) m.invoke(testClass, null);
// Throws NoSuchMethodException
m = testClass.getClass().getDeclaredMethod("totalWeight", cArg);
float totalWeight = (float) m.invoke(testClass, null);
System.out.println("quantity = " + quantity +
"weight = " + weight +
"totalWeight = " + totalWeight);
}
现在,我已经弄清楚 testClass 实际上是作为 java.lang.Class
的实例初始化的,而不是 bin.objects.base.NewClass
。所以,很明显,它不会找到NewClass的字段和方法。
问题是我该如何解决?我尝试使用 java.lang.Class.cast()
方法,但没有成功。
尝试使用反射将您的 class 对象作为 :
Field q = Class.forName("bin.objetos.base.NovaClasse").getDeclaredField("quantity");
您也可以对其他字段执行相同的操作。
我终于找到问题所在了。
看来是ClassLoader的问题。我找到了答案 in this post。为了解决它,我只包含了这一行:
Class newClasse = ctclass.toClass(this.getClass().getClassLoader(),
this.getClass().getProtectionDomain());
@nullpointer 的回答也有帮助。
因此,经过更多更改后,testNewClass()
方法最终变成了这样:
public void testNewClass()
throws Throwable {
CtClass ctclass = ClassPool.getDefault().get("bin.objects.base.NewClass");
Class newClass = ctclass.toClass(this.getClass().getClassLoader(),
this.getClass().getProtectionDomain());
Object objNewClass = newClass.newInstance();
System.out.println("Accessing the field 'public int quantity'...");
Field q = newClass.getDeclaredField("quantity");
int quantity = (int) q.get(objNewClass);
System.out.println("quantity = " + quantity);
System.out.println("\nAccessing the field 'private float weight' " +
"through the method 'public float getWeight()'...");
Method m = newClass.getDeclaredMethod("getWeight", null);
float weight = (float) m.invoke(objNewClass, null);
System.out.println("weight = " + weight);
System.out.println("\nAccessing the method 'public float totalWeight()'...");
m = newClass.getDeclaredMethod("totalWeight", null);
float totalWeight = (float) m.invoke(objNewClass, null);
System.out.println("totalWeight = " + totalWeight);
}