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?
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.
This was a classic issue with JPype. If the jar can't be loaded then JPackage will return another JPackage which is not callable. Common causes of a failure to load include
The JVM loaded does not support the version of the jar (Check that getDefaultJVMPath() is not some old version)
A jar dependency is missing.
The JVM could not find the Jar as the specified path.
The previous solution was to use java.lang.Class.forName which would print the diagnostics on the jar loading. Version 0.7.0 which is currently in available as a release candidate has addressed this.
Also it is recommended that you use jpype.imports or JClass rather than JPackage when importing a class. It is much safer as it will report a more meaningful error. For example:
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
You can mark a package as being conforming (Classes start upper, packages are lower) to force an error.
Related
I can't run methods of a library.
My library is in my PATH and also getting loaded without errors by following code:
System.loadLibrary("FTDIInterface");
But the functions are not working.
I get the following exception:
Caused by: java.lang.UnsatisfiedLinkError: Messgeraet.src.net.sf.yad2xx.FTDIInterface.getDevices()[LMessgeraet/src/net/sf/yad2xx/Device;
at Messgeraet.src.net.sf.yad2xx.FTDIInterface.getDevices(Native Method)
at Messgeraet.src.Emu.EmuConnection.<init>(EmuConnection.java:22)
at Messgeraet.src.Emu.EmuModel.connect(EmuModel.java:27)
at Messgeraet.src.JavaFX.FXController.connect(FXController.java:112)
... 62 more
I am using eclipse. In IntelliJ it is working fine and I also got another eclipse project that includes the library without any problems.
Why it can't run my method FTDIInterface.getDevices?
Your package seems off; Messgereat.src sounds like you have a project dir named Messgereat, within you have a folder named 'src' with your java sources, and you've misconfigured your build tooling; the right package name sounds like it should be: package net.sf.yad2xx;, but due to a misconfigured build it wasn't working and you decided to fix the problem by updating your package statements, but that broke your JNI bindings.
The solution would then be to undo all the changes you've made to your package statements, and fix your build script instead.
Alternatively, if you really do intend to use that bizarre package, then make sure you have executed javah with the exact same build setup and use that as a basis for your JNI code. If you've done that, include the exported symbols in the library as the comment by #user2543253 suggested.
NB: It's a bit odd that your loadLibrary call works at all; PATH has nothing to do with it, but presuambly then your library so happens to be located in a place that is listed on your librarypath, which is the system property (of the VM, not of your OS) named 'java.library.path'; you set it with e.g.:
java -Djava.library.path=/path1:/path2 -cp /path/to/dep1.jar:/path/to/dep2.jar com.foo.Main
because of this confusion it is also possible that some different native lib file also named FTDIInterface is being loaded instead of the one you think is being loaded. If you want to be certain of what is being loaded, run System.load("/absolute/path/to/the/dll-jnilib-or-so-libraryfile.so"); - then you know for sure.
I am unable to compile tests with JUnit. When I attempt to do so, I get this error:
package org.junit.jupiter.api does not exist
I get this error compiling the tests even if I put the .jar in the same directory and compile as follows:
javac -cp junit4-4.12.jar Tests.java
The contents of Test.java are:
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
public class Tests {
... several tests ...
It's not clear to me what the issue is, and as far as I can tell, it should work with the .jar -- it's the one from /usr/share/java, where it was installed when I installed junit.
As #DwB has already mentioned you have wrong junit version.
Here is what is jupiter in JUnit: http://junit.org/junit5/docs/current/user-guide/#overview-what-is-junit-5
In simple words JUnit Jupiter API is a set of new classes which were written and introduced in junit 5 version only. And ur trying to use 4 version.
And also i want to clarify some points.
even if I put the .jar in the same directory and compile as follows
It does not matter actually is your file in the same directory or not. Its all about it's path. If you are setting jar only by name of jar file (as you did) then your path becomes relative to your current directory from where u execute javac command. You can just use absolute path and run this command from every directory you want.
https://docs.oracle.com/javase/8/docs/technotes/tools/windows/classpath.html (this one is for windows but for other os there are only minor changes in path writing)
If you get errors like package does not exist, classnotfound or anything similar then such kinds of errors almost always mean you have something wrong with your classpath or dependencies. In your case you simply had wrong version.
Now about finding necessary deps. In java world one of the main places for dependencies is maven central. Almost every opensource library can be found there and maven by default uses this repository to find and load dependencies (in your case these are jars) from there. Also you can use it to get necessary jars manually by simply using it's UI (https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api/5.0.0). There is download jar button.
Now if you know package or class but do not know in what dependency (jar for simplicity) it is located. In this case you can use http://grepcode.com or other resources which allow to search within available source code withit different repositories. In most cases this work. With juniper i did not manage to find smth there but in other cases this may help) Or the most simple case is just google package and in most cases it also will help to define entry point.
Now about solving ur issue. It seems that you will need as api as implentation. You will definitely need this one https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api/5.0.0 but it seems that you will need juniper-engine too. First try adding only API and then just go on adding necessary libraries according to errors. You can add multiple jars to cp (read provided class path guide from oracle).
I am working on application that has components written in several languages. I am trying to get functionality that works fine in Java working in Jython. There is some native/C++ functionality that Java access via the JNI and is wrapped by SWIG.
Whenever I try to import all of the classes in the project I get errors that PROJECTJNI cannot be linked. Here is my minimum case to produce:
import sys
sys.path.append('PROJECT.jar')
from com.whatever.project import *
Here is the error message when this is executed:
$ jython Bootstrap.py
"my" variable $jythonHome masks earlier declaration in same scope at /usr/bin/jython line 15.
Traceback (most recent call last):
File "Bootstrap.py", line 9, in <module>
from com.whatever.project import *
java.lang.UnsatisfiedLinkError: com.whatever.project.PROJECTJNI.swig_module_init()V
at com.whatever.project.PROJECTJNI.swig_module_init(Native Method)
at com.whatever.project.PROJECTJNI.<clinit>(PROJECTJNI.java:974)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:278)
at org.python.core.Py.loadAndInitClass(Py.java:909)
at org.python.core.Py.findClassInternal(Py.java:844)
at org.python.core.Py.findClass(Py.java:869)
at org.python.core.packagecache.PackageManager.basicDoDir(PackageManager.java:107)
at org.python.core.packagecache.SysPackageManager.doDir(SysPackageManager.java:138)
at org.python.core.PyJavaPackage.fillDir(PyJavaPackage.java:123)
at org.python.core.imp.importAll(imp.java:1051)
at org.python.core.imp.importAll(imp.java:1039)
at org.python.pycode._pyx0.f$0(Bootstrap.py:9)
at org.python.pycode._pyx0.call_function(Bootstrap.py)
at org.python.core.PyTableCode.call(PyTableCode.java:165)
at org.python.core.PyCode.call(PyCode.java:18)
at org.python.core.Py.runCode(Py.java:1275)
at org.python.util.PythonInterpreter.execfile(PythonInterpreter.java:235)
at org.python.util.jython.run(jython.java:247)
at org.python.util.jython.main(jython.java:129)
java.lang.UnsatisfiedLinkError: java.lang.UnsatisfiedLinkError: com.whatever.project.PROJECTJNI.swig_module_init()V
The line 15 thing shows up on any time we invoke jython, we had been ignoring it.
We can get the classes from the Java Project to work by simply loading them one at a time:
com.whatever.project import Class1
com.whatever.project import Class2
...
com.whatever.project import Class50
This is highly impractical because even for short python script we might need a dozen classes. Many of them are exceptions that we are catching which have unique types. So anything that robustly handles errors might need a huge number of classes.
As per the jython documentation I should be able to hide PROJECTJNI so it is not loaded by doing something like this, but I found the docs less than perfectly clear. Here is what I attempted:
import com.whatever.project
__all__ = dir(com.whatever.project)
__all__.remove('PROJECTJNI')
from com.whatever.project import *
But this fails with errors and still clearly trying to load PROJECTJNI.
I also tried to fix the native executable so it could be linked against correctl. I learned another group using JRuby had no issue including everything, so I decided to check the source and the binary. I found void swig_module_init() in the file Project_wrap.cpp that Swig created. It was hidden behind a macro, but it was there, and objdump confirms:
$objdump libPROJECT.so -t |grep PROJECTJNI |grep init
000000000051a900 l O .data 00000000000009d0 _ZZ59Java_com_whatever_project_PROJECTJNI_swig_1module_1initE7methods
0000000000263f66 g F .text 00000000000000d1 Java_com_whatever_project_PROJECTJNI_swig_1module_1init
Am I doing something wrong with any of my troubleshooting steps? Is the a bug in Jython? Is there a simple Python workaround to make it skip loading PROJECTJNI?
Anything that lets me skip linking this or makes this link correctly will be accepted.
On one of the Java classes, the BinaryLoader, there was a method called void load_binary() that is called in a static section of that class:
public class BinaryLoader
{
static
{ load_binaries(); }
public static void load_binaries()
{
// Deep inside here is a call to actually load the shared library. Using
load_shared_library_from_jar("PROJECT");
}
... // more details here
}
Our Java code using the native API called this method as the class was loaded. Our JRuby code called this when the class was 'touched', just using the Constant's name, the name of the class, invoked the static section. To clarify here is a sample from our docs and live Ruby scripts that does this:
# Tells Jruby to load the Java Interopability layer.
require 'java'
# Loads the PROJECT Java tools.
require 'PROJECT.jar'
# Shorten the PROJECT tool names from their obnoxiously long Java name.
module PROJECT
include_package "com.whatever.project"
end
# Let Ruby know the BinaryLoader exists and it will have PROJECT load all the system binaries.
PROJECT::BinaryLoader
Apparently requiring the JarFile is enough to make all the Native symbols and Java classes available in Ruby and the binary isn't loaded until the last line which is just an expressions that resolves to the name of the class and force the static section to run. The actual method call would have looked like: PROJECT::BinaryLoader.load_binaries
In Jython the static section was never invoked even when calling other static methods on the BinaryLoader class. I forced it to call the method manually by importing the minimum of Java and Native symbols to call the method:
# Tells Jython to load the python system Interopability tools.
import sys
# When searching for python symbols, this Java jar should be search also.
sys.path.append('PROJECT.jar')
# Load just enough the have the JVM Know how to load the native PROJECT libraries
from com.whatever.project import PROJECT
from com.whatever.project import BinaryLoader
# Load any native binaries that are required
BinaryLoader.load_binaries()
# After this line is run in any given script then PROJECT can be used.
from com.whatever.project import *
Clearly the native binaries were simply not loaded as had been thought. Anything that loaded these would have been an acceptable solution.
This works around Jython not invoking the static section, by doing the work it should have as early as possible. This seems like a bug in Jython, but it might be that guarantees on static load order are not strongly enforced in Java. Either way because this incompatibility we will likely be removing the static section to prevent future Java ad Ruby Devs from adding something that could fail to load in Python.
When I attempt to run scons (2.3.0) to build a class from a SWIG interface file, scons fails to pick up all the generated files, either as being in the sourcepath, or to be included in the build (even with classpath set). Instead only two java files are attempted to be compiled, both of which fail because they are derived from other classes.
loc_env = env.Clone()
loc_env['JAVACLASSPATH']= ['build/$TARGET_ARCH/$TARGET_OS/.../java']
swig_j = loc_env.Java(target='.', source=['source_java.i']) #1
#swig_j = loc_env.Jar(target='.', source=['source_java.i']) #2
Both #1, and #2 fail to produce a result. #2 shows an error message that the source has not been accepted, and is a blank string, which I can accept, even with example code suggesting it should work.
For #1 The root cause seems to be in Scons/Tool/swig.py def _find_modules(src):, which has a regex to match all modules generated, but fails to account for any raw enums or other artefacts from wrapping up C code. When I had a hand-rolled makefile the classpath
For reference, The javac build instruction for #1 is:
javac -classpath build/x86_64/linux/.../java -d build/x86_64/linux/.../java/ -sourcepath build/x86_64/linux/.../java build/x86_64/linux/release/.../source.java build/x86_64/linux/release/.../sourceJNI.java
Is this a known bug (As part of SCONS' handling of 1->N mappings)? Is it a flaw in the Scons Parsing of .i files? or is it a more fundamental issue?
This is a bug in SCons. The changes slated for 2.5.0 fix the issue, by improving cross-language scanning. I look forwards to ripping out my hack sometime next year!
I am using the code from Rome's tutorials page http://wiki.java.net/twiki/bin/view/Javawsxml/Rome05TutorialFeedReader . Also trying this one: http://wiki.java.net/twiki/bin/view/Javawsxml/Rome05TutorialFeedReader
Compiling works, but I'm not sure how to run these examples. Why I just type java FeedReader or java FeedAggregator into the command line, I get the error:
C:\projects\freshmeat\src>java FeedAggregator http://freecode.com/?format=atom
Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/syndication/f
eed/synd/SyndFeed
plus the large block that follows this error
Why is this happening, how do I fix it and try these things out? How do I get something to work with Rome!?
You need to include rome in the runtime classpath (in addition to the compile-time classpath)
java -classpath lib/rome.jar FeedAggregator ...
The samples you are trying to run are in the package com.sun.syndication.samples. You say you are a complete beginner, so, to make things simpler, I would recommend that you remove the line beginning with package in each of FeedReader.java and FeedAggregator.java. Recompile the classes after removing their package directives.
Then, to run these classes, make sure you're in the same directory as the class files FeedReader.class and FeedAggregator.class that javac created. Then, try running:
java -cp c:\projects\freshmeat\libs\rome-1.0.jar;c:\projects\freshmeat\libs\jdom-1.0.jar;. FeedReader
(and similarly for FeedAggregator.)
Note also that I've added the current directory, ., to the -cp attribute. Without this, the Java virtual machine won't know that it has to look in the current directory to find your FeedReader and FeedAggregator classes.
If you were to reinstate the package directives, you'd find the class files FeedReader.class and FeedAggregator.class would be created inside a directory com\sun\syndication\samples when you compile their sources. To run the class files from this location, you'd use a command line such as
java -cp c:\projects\freshmeat\libs\rome-1.0.jar;c:\projects\freshmeat\libs\jdom-1.0.jar;. com.sun.syndication.samples.FeedReader
and you'd run this from the directory containing the com subdirectory, not the directory that contains the class files.
More information on packages in Java can be found here.