In Javassist, how to set return type of method to java.lang.Double when creating dynamic method using CtMethod

huangapple go评论75阅读模式
英文:

In Javassist, how to set return type of method to java.lang.Double when creating dynamic method using CtMethod

问题

我必须在运行时动态创建一个类和方法。我正在使用Javassist进行这个操作:

我想要动态创建的方法是:

public Double formula1(FormulaAPI api) {  
    return api.evaluate("L"); 
}

如果我将上述整个方法作为方法体传递使用CtMethod.make(..),它可以正常工作。

但我想要更加通用,也就是说,我只想要return api.evaluate("L");作为我的方法体,并且想要使用JavaAssist API的方法来设置名称、返回类型等。
在尝试这样做时,我遇到了错误:

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;
	}
}

注意:由于您要求只返回翻译好的部分,因此上述内容是您提供的代码的翻译版本。如有其他问题,请随时询问。

英文:

I have to dynamically create a class and method at run time. I am using Javassist for this:

The method that I want to dynamically create is:

public Double formula1(FormulaAPI api) {  
return api.evaluate(\"L\"); 
}

If I pass the entire above method as method body using CtMethod.make(..), it works fine.

But I want to make it more generic, i.e. i want to only have return api.evaluate(\"L\"); as my method body and want to use the JavaAssist API methods to set the name, return type etc.
When trying to do this, I am getting error :

 ***Exception in thread "main" java.lang.VerifyError: 
(class: Formulae, method: formula1 signature: (Lcom/formula/FormulaAPI;)D) Wrong return type in function***

My question is : when calling:
CtMethod m = new CtMethod(...);
how can I set the return type of CtMethod to java.lang.Double instead of CtPrimitiveType.doubleType ?

My entire source code is:

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

The FormulaAPI class is as below:

public class FormulaAPI {
public Double evaluate(String source){
System.out.println("printing in FormulaAPI ");
return 2.0;
}
}

答案1

得分: 1

清楚地看出,CtPrimitiveType.doubleType并不是应该使用的CtClass类型,因为您实际上需要使用包装类,这就是您出现异常的原因。

但解决方案非常简单,您只需获取Double类型的CtClass并将其用于替代。因此,请将您的generate方法修改如下:

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

使用这些修改运行您的代码,您应该不会再遇到异常。

英文:

Clearly the CtPrimitiveType.doubleType is not the CtClass type to use since you need the wrapper class instead and that is why your are getting the exception.

But the solution is very simple you simply need to get the Double type as a CtClass and use it instead. So modify your generate method to look like:

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

Running your code with these modifications, you should have no exceptions.

huangapple
  • 本文由 发表于 2020年3月15日 21:29:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/60693436.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定