В Javassist, как установить тип возвращаемого значения метода java.lang.Double при создании динамического метода с использованием CtMethod
Мне нужно динамически создавать класс и метод во время выполнения. Для этого я использую Javassist:
Метод, который я хочу создать динамически:
public Double formula1(FormulaAPI api) {
return api.evaluate(\"L\");
}
Если я передам весь вышеуказанный метод как тело метода, используя CtMethod.make(..)
, он отлично работает.
Но я хочу сделать его более общим, т.е. я хочу, чтобы return api.evaluate(\"L\");
в качестве тела моего метода и хочу использовать методы API JavaAssist для установки имени, типа возвращаемого значения и т. д. При попытке сделать это я получаю сообщение об ошибке:
***Exception in thread "main" java.lang.VerifyError:
(class: Formulae, method: formula1 signature: (Lcom/formula/FormulaAPI;)D) Wrong return type in function***
У меня вопрос: при вызове: CtMethod m = new CtMethod(...); как установить тип возвращаемого значения CtMethod на java.lang.Double вместо CtPrimitiveType.doubleType?
Весь мой исходный код:
public class JavaAssistTest {
private static final String className = "Formulae";
private static final String methodName = "formula1";
public static void main(String[] args) throws Exception{
JavaAssistTest jj = new JavaAssistTest();
try {
Class clazz = jj.generateClass(className, methodName);
Object obj = clazz.newInstance();
Method method = clazz.getDeclaredMethod(methodName,FormulaAPI.class);
FormulaAPI api = new FormulaAPI();
method.invoke(obj,api);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
}
}
public Class generateClass(String className, String methodName)
throws CannotCompileException, NotFoundException{
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass(className);
ClassLoader classLoader = FormulaAPI.class.getClassLoader();
pool.appendClassPath(new LoaderClassPath(classLoader));
pool.importPackage("com.formula");
String methodBody = "return $1.evaluate(\"L\");";
CtClass apiClass = pool.get("com.formula.FormulaAPI");
CtMethod m = new CtMethod(CtPrimitiveType.doubleType,methodName,new CtClass[]{apiClass},cc);
m.setBody(methodBody);
cc.addMethod(m);
return cc.toClass();
}
}
Класс FormulaAPI выглядит следующим образом:
public class FormulaAPI {
public Double evaluate(String source){
System.out.println("printing in FormulaAPI ");
return 2.0;
}
}
1 ответ
Ясно CtPrimitiveType.doubleType
не является типом CtClass для использования, так как вместо этого вам нужен класс-оболочка, и именно поэтому вы получаете исключение.
Но решение очень простое: вам просто нужно получить тип Double как CtClass и использовать его вместо этого. Поэтому измените свой метод генерации, чтобы он выглядел так:
public Class generateClass(String className, String methodName)
throws CannotCompileException, NotFoundException {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass(className);
ClassLoader classLoader = FormulaAPI.class.getClassLoader();
pool.appendClassPath(new LoaderClassPath(classLoader));
pool.importPackage("com.formula");
String methodBody = "return $1.evaluate(\"L\");";
CtClass apiClass = pool.get("com.formula.FormulaAPI");
CtClass doubleWrapperClass = pool.get("java.lang.Double");
CtMethod m = new CtMethod(doubleWrapperClass,methodName,new CtClass[]{apiClass},cc);
m.setBody(methodBody);
cc.addMethod(m);
return cc.toClass();
}
При запуске вашего кода с этими модификациями исключений быть не должно.