GroovyCastException while 运行 java code containing new line "\n" with groovy script engine(GroovyClassLoader)

GroovyCastException while running java code containing new line "\n" with groovy script engine(GroovyClassLoader)

目前我正在研究以字符串形式 运行 java 代码的方法。这就是我的做法。

import java.util.HashMap;
import java.util.Map;

import groovy.lang.GroovyClassLoader;

public class GroovyWhosebug {

    public static void main(String[] args) {
        GroovyClassLoader gcl = new GroovyClassLoader();
        String codeSnippet = "double calculatedAnswer = (Double)"
                + "contextMap.get(\"doubleValue\") * (Double)contextMap.get(\"doubleValue\");"
                + " calculatedAnswer = Math.sqrt(calculatedAnswer); "
                + "calculatedAnswer = calculatedAnswer * calculatedAnswer;"
                + "System.out.println(calculatedAnswer);"
                + " return calculatedAnswer;";
        StringBuilder sb = new StringBuilder();
        sb.append("public class ScriptImplementor implements ScriptEvaluator { public Object evaluate(Map contextMap) {");
        sb.append(codeSnippet);
        sb.append("} }");
        Class<?> clazz = gcl.parseClass(sb.toString());
        ScriptEvaluator scriptEvaluator = null;     
        double calculatedAnswer = 100.0;        
        try {
            Map contextMap = new HashMap();
            contextMap.put("doubleValue", (double)100.0);
            contextMap.put("threadId", "thread"+100);
            contextMap.put("hashCode", 100);
            scriptEvaluator = (ScriptEvaluator) clazz.newInstance();
            scriptEvaluator.evaluate(contextMap);;
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

public interface ScriptEvaluator {
    public Object evaluate(Map contextMap);
}

问题是在以下情况下它失败了。

import java.util.HashMap;
import java.util.Map;

import groovy.lang.GroovyClassLoader;

public class GroovyWhosebug {

    public static void main(String[] args) {
        GroovyClassLoader gcl = new GroovyClassLoader();
        String codeSnippet = "double calculatedAnswer = (Double)"
                + "\n "
                + "contextMap.get(\"doubleValue\") * (Double)contextMap.get(\"doubleValue\");"
                + " calculatedAnswer = Math.sqrt(calculatedAnswer); "
                + "calculatedAnswer = calculatedAnswer * calculatedAnswer;"
                + "System.out.println(calculatedAnswer);"
                + " return calculatedAnswer;";
        StringBuilder sb = new StringBuilder();
        sb.append("public class ScriptImplementor implements ScriptEvaluator { public Object evaluate(Map contextMap) {");
        //sb.append(codeSnippet.replaceAll("\n", " "));
        sb.append(codeSnippet);
        sb.append("} }");
        Class<?> clazz = gcl.parseClass(sb.toString());
        ScriptEvaluator scriptEvaluator = null;     
        double calculatedAnswer = 100.0;
        try {
            Map contextMap = new HashMap();
            contextMap.put("doubleValue", (double)100.0);
            contextMap.put("threadId", "thread"+100);
            contextMap.put("hashCode", 100);
            scriptEvaluator = (ScriptEvaluator) clazz.newInstance();
            scriptEvaluator.evaluate(contextMap);;
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
public interface ScriptEvaluator {
    public Object evaluate(Map contextMap);
}

我不明白它为什么会失败以及此错误消息的含义 -

Exception in thread "main" org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'class java.lang.Double' with class 'java.lang.Class' to class 'double'
    at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.castToNumber(DefaultTypeTransformation.java:163)
    at org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.doubleUnbox(DefaultTypeTransformation.java:88)
    at ScriptImplementor.evaluate(script15126616543572010791987.groovy:1)
    at GroovyWhosebug.main(GroovyWhosebug.java:33)

取消注释此代码后 //sb.append(codeSnippet.replaceAll("\n", " ")); 它起作用了。但请提出一个更好的方法来处理它。还有为什么它在解析 class 时不报错? 像这样我还能期待什么惊喜?

你找到了 Java 和 Groovy 之间的差异。

在 Java 中,语句以分号结束。

在 Groovy 中,一个语句以分号结束, 如果该语句已经是一个完整的语句,则以换行符结束。

在您的情况下,这意味着代码

double calculatedAnswer = (Double)
contextMap.get("doubleValue") * (Double)contextMap.get("doubleValue")

是两个语句。

这些语句中的第一个是 double calculatedAnswer = (Double)

在Groovy中你也可以省略.class来引用一个class,所以Double.class可以写成Double.

所以您在该语句中所做的是,将 Double class 对象分配给 double 变量。括号在这里只是空操作。

这当然会像消息所说的那样失败,因为 Double class 对象不能自动大小写为 double.

您可以显式转义换行符,使其不会像

中那样结束语句
double calculatedAnswer = (Double)\
contextMap.get("doubleValue") * (Double)contextMap.get("doubleValue")

这会像您预期的那样工作。

当然也有其他情况 Groovy 和 Java 不同。

永远记住,Groovy 语法接近 Java 语法,但 完全相同。

每个有效的 Java 代码也是有效的 Groovy 代码,但不一定与您在此示例中看到的含义完全相同。