【问题标题】:jpype simple jar import and run main()jpype 简单 jar 导入并运行 main()
【发布时间】:2019-09-07 02:32:46
【问题描述】:

我正在尝试打开一个 jar 文件并执行它的主要功能,但是 jpype 抛出了一个对我来说没有意义的错误。这是我的代码:

jpype.startJVM(jpype.getDefaultJVMPath(), '-Djava.class.path="%s"' % jar)
CommandLine = jpype.JPackage('phylonet').coalescent.CommandLine
CommandLine.main(['-i', input_file, '-o', output_file])
jpype.shutdownJVM()

我收到此错误: TypeError: Package phylonet.coalescent.CommandLine.main is not Callable

我已经提供了 jar 文件的绝对路径,并且我已经从 META-INF/MANIFEST.MF 中获取了 main 函数:

cat tmp/META-INF/MANIFEST.MF | grep Main-Class
Main-Class: phylonet.coalescent.CommandLine

我试图打开的 jar 文件称为 astral,来自这里:https://github.com/smirarab/ASTRAL

像这样调用它可以按预期工作:

java -Djava.class.path="./astral.jar"

那么当我用 jpype 调用它时为什么不呢?

【问题讨论】:

标签: java python jpype


【解决方案1】:

首先,我已经在我自己的 jarfile 上测试了您的代码。确实,我遇到了这样的错误:

TypeError: Package clip.frontend.Start.main is not Callable

然后,仔细阅读文档后,我使用了另一种方法。

import jpype

# I've used other set of parameters to JVM, and modified a bit your classpath setting.
jpype.startJVM(jpype.getDefaultJVMPath(), "-ea", "-Djava.class.path=clip.jar")

# Second difference, I decided to use JClass because it was more clear for me.
# Parameter array was kept empty.
jpype.JClass("clip.frontend.Start").main([])
jpype.shutdownJVM()

而且输出是正确的:

% python2 main.py
2 2
+>+[<[>>+>+<<<-]>>[<<+>>-]>[[-]>>>>>>+<<<<<<<<<[-]>[-]>>>>>>>>[<<<<<<<<+>+>>>>>>>-]
<<<<<<<[>>>>>>>+<<<<<<<-]>>>>>>>[-]<<<<<<]<<<[>>+>+<<<-]>>[<<+>>-]>[[-]>>>>>>++
[<<<<<+>>>>>>>>>>>>+<<<<<<<-]<<<<<[>>>>>+<<<<<-]>>>>>>>>>>>>>[>>]+<<[<<]>[>[>>]
<+<[<<]>-]<<<<<<<[-]++[<<<<<+>>>>>>>>>>>>+<<<<<<<-]<<<<<[>>>>>+<<<<<-]>>>>>>>>>>>>>
[>>]+<<[<<]>[>[>>]<+<[<<]>-]<<<<<<<[-]#JVM has been shutdown

现在,我决定根据您的问题翻译我的解决方案:

import jpype
jpype.startJVM(jpype.getDefaultJVMPath(), "-ea", "-Djava.class.path=astral.jar")
jpype.JClass("phylonet.coalescent.CommandLine").main([])
jpype.shutdownJVM()

并且代码可以正常工作。比实际解决方案更重要的是,为什么您的代码不起作用。您使用了错误的参数集并以 other 方式指定了类路径。

用JPackage替换JClass,代码依然有效。

import jpype
jpype.startJVM(jpype.getDefaultJVMPath(), "-ea", "-Djava.class.path=astral.jar")
jpype.JPackage('phylonet').coalescent.CommandLine.main([])
jpype.shutdownJVM()

由于您从类路径中提取类的方式是正确的,唯一可能的原因是指定了无效的参数集。删除-ea后代码仍然有效,所以你犯的错误在于这段代码。

'-Djava.class.path="%s"' % jar

事实上,我用这个来反对我的回答,然后,代码产生了这个:

TypeError: Package phylonet.coalescent.CommandLine.main is not Callable

这意味着,参数包含以下内容:

-Djava.class.path="astral.jar"

而不是跟随

-Djava.class.path=astral.jar

引号放错了位置,导致结果错误。

【讨论】:

    【解决方案2】:

    这是 JPype 的经典问题。如果无法加载 jar,则 JPackage 将返回另一个不可调用的 JPackage。加载失败的常见原因包括

    • 加载的JVM不支持jar的版本(检查getDefaultJVMPath()是不是旧版本)
    • 缺少 jar 依赖项。
    • JVM 找不到 Jar 作为指定路径。

    之前的解决方案是使用java.lang.Class.forName,它会在 jar 加载时打印诊断信息。目前作为候选发布版本提供的 0.7.0 版已经解决了这个问题。

    另外建议您在导入类时使用jpype.importsJClass 而不是JPackage。它更安全,因为它会报告更有意义的错误。例如:

    import jpype
    import jpype.imports
    
    jpype.startJVM()
    jpype.imports.registerDomain('phylonet')  # This is required as phylonet is not a tld
    
    from phylonet.coalescent import CommandLine
    

    您可以将包标记为符合要求(类从上开始,包在下)以强制出错。

    【讨论】:

    • 这种方法更简洁,我注意到错误现在得到了更好的处理。
    猜你喜欢
    • 2017-10-17
    • 2020-11-07
    • 2021-11-13
    • 2018-06-24
    • 2015-05-25
    • 2013-04-04
    • 2018-12-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多