В 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();
}

При запуске вашего кода с этими модификациями исключений быть не должно.

Другие вопросы по тегам