【问题标题】:Run javac compiled groovy code using java?使用java运行javac编译的groovy代码?
【发布时间】:2014-10-02 18:00:38
【问题描述】:

我有一个简单的 groovy 文件如下:

class test2 {
    public static void main(String[] args) {
        println("In groovy!!");
    }
}

我的 gradle 任务是把它编译成一个 test2 类文件

如何从提示符运行此文件?

java test2(来自 test2.class 文件的位置) 导致:错误:无法找到或加载主类 test2.class

我假设我需要将 asm 和 groovy 添加到类路径中。然而: java -cp "groovy-all-2.3.6.jar;asm-all-3.3.1.jar" test2 也不起作用(文件位于正确的位置)。

【问题讨论】:

    标签: java groovy


    【解决方案1】:

    我知道这对于 OP 来说可能有点晚了,但是:

    鉴于您的 groovy main 存在,错误消息:

    错误:无法找到或加载主类 YOUR_MAINCLASS_HERE

    java 命令在执行 groovy main(生成类的已编译 groovy 文件)基本上意味着您的 groovy jar不在 类路径中。

    更长的答案:

    让我们看看为什么这是一个简单的 hello world 示例。我有一个名为 main.groovy 的文件,其内容如下:

    class Main {
        static void main(String[] args){
                println('hello world')
        }
    

    }

    把它放在你的文件系统中的某个地方。在同一目录中打开命令提示符并确保可以通过 PATH 访问 groovy 和 java。

    在命令提示符下,用groovyc编译文件,所以只需输入:

    groovyc main.groovy
    

    这将生成一个名为 Main.class 的文件(由于类名,M 大写)。

    好的,现在我们有了适当的测试设置。如果您现在尝试仅使用 java 命令运行该文件:

    java Main 
    

    您将收到错误消息:

    错误:无法找到或加载主类 Main

    这有点出乎意料,因为我们可以认为我们可以在 Main.class 中调用 main 而无需链接 groovy 库,所以我们会期待 ClassNotFoundException 这样的异常。

    相反,在你的类路径中使用 groovy 再试一次。我将您的 groovy 安装目录称为 GROOVY_HOME。最后运行 hello world Main 类,我们可以输入:

    java -cp ".:/$GROOVY_HOME/lib/*" 主要

    在类 unix 系统上产生预期的输出(在 Windows 上,您需要用分号替换冒号,变量访问类似于 %GROOVY_HOME%)。

    原因很简单:Groovy 为 groovy 主要方法生成的签名与 Java 规范所要求的签名不同。因此,您只能在 CLASSPATH 上使用 groovy 调用 groovy main - 这是完全有道理的!

    您可以自己检查一下。现在试试这个命令:

    javap Main.class
    

    这将使您快速分析“Main.class”类的字节码和当前接口。一直以来,您都会看到与此输出类似的内容:

    Compiled from "main.groovy"
    public class Main implements groovy.lang.GroovyObject {
      public static transient boolean __$stMC;
      public Main();
      public static void main(java.lang.String...);
      protected groovy.lang.MetaClass $getStaticMetaClass();
      public groovy.lang.MetaClass getMetaClass();
      public void setMetaClass(groovy.lang.MetaClass);
      public java.lang.Object invokeMethod(java.lang.String, java.lang.Object);
      public java.lang.Object getProperty(java.lang.String);
      public void setProperty(java.lang.String, java.lang.Object);
    }
    

    感兴趣的是第 5 行:

      public static void main(java.lang.String...);
    

    这似乎与普通的 java main 非常相似,但有一个区别:groovyc 使用了 java.lang.String 省略号(如三个点所示)而不是 java.lang.String[]。

    所以这可能是原因。我不太确定,因为通常如果 java 可以找到类而不是方法签名,它会给你一个适当的错误输出。例如,尝试:

    java java.lang.Integer
    

    这显然不是一个主要的方法。 Java 正确地看到了这一点:

    Error: Main method not found in class java.lang.Integer, please define the main method as:
    public static void main(String[] args)
    or a JavaFX application class must extend javafx.application.Application
    

    我也不确定,在类加载期间 groovy 做了什么来理解这种主要签名(或者说这种字节码),但是如果你将它与普通的 java hello world javap 输出进行比较,你会得到

    public class JMain { public JMain(); public static void main(java.lang.String[]); }

    它有一个不同的和正常的 java 主签名。

    也许关键的 groovy 团队中的某个人可以澄清一下。 我希望这会给你一个提示。

    【讨论】:

    • 很好的答案。谢谢。
    • 节省了我的一天,同时想知道为什么找不到该类,如果它在那里...
    【解决方案2】:

    test2.class 需要在您的 CLASSPATH 中。例如,如果它位于 /Users/you/classes/test2.class 则 /Users/you/classes/ 需要在您的 CLASSPATH 中。

    由于您是使用 Gradle 构建的,因此您也可以让 Gradle 使用 JavaExec 为您解决所有这些问题。请参阅http://www.gradle.org/docs/current/dsl/org.gradle.api.tasks.JavaExec.html 了解更多信息。 build.gradle 中的一个简单示例可能是这样的:

    task myTask(type: JavaExec, dependsOn: 'classes') {
        main = 'test2'
        classpath = sourceSets.main.runtimeClasspath
    }
    

    希望对你有帮助。

    【讨论】:

    • 我从包含 test2.class 的目录运行它,而 test2 没有包定义。
    • 然后把当前目录放到你的CLASSPATH中。
    • 使用“.”。 ` java -cp "groovy-all-2.3.6.jar;asm-all-3.3.1.jar;."测试2`
    • 如果 test2.class 在当前目录中,您发布的命令没有任何意义。 groovy-all-2.3.6.jar、asm-all-3.3.1.jar 和 test2.class 真的都在同一个目录下吗?
    • 是的,都在同一个目录中用于测试目的
    猜你喜欢
    • 2012-04-06
    • 2012-11-10
    • 1970-01-01
    • 1970-01-01
    • 2020-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多