javapythonjpype

jpype simple jar import and run main()


I'm trying to open a jar file and execute it's main function, but jpype is throwing an error that doesn't make sense to me. Here is my code:

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

I get this error: TypeError: Package phylonet.coalescent.CommandLine.main is not Callable

I've provided the absolute path to the jar file, and I've gotten the main function from META-INF/MANIFEST.MF:

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

The jar file I'm trying to open is called astral, from here: https://github.com/smirarab/ASTRAL

Calling it like this works as expected:

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

So why not when I call it with jpype?


Solution

  • First of all, I have tested your code on my own jarfile. Indeed, I was presented with such error:

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

    Then, after reading the docs carefully, I've used another method.

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

    And the output was correct:

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

    Now, I decided to translate my solution to match your problem:

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

    And the code works correctly. More important than the actual solution is the fact, why doesn't your code work. You used wrong set of parameters and specified the classpath in the other way.

    Replacing JClass with JPackage, the code still works.

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

    As the way you extract classes from classpath is correct, the only possible cause is specifying invalid parameter set. After removing -ea the code still works, so mistake you made lies in this fragment of code.

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

    And in fact, I've used this in opposition to my answer, and bam, the code yields this:

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

    This means, the parameter contained following:

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

    instead of following

    -Djava.class.path=astral.jar
    

    The quotes were misplaced and raised the error in result.