I have received the task, at work, to find a way to use some methods from an existent jar file in a Python project. I have very limited experience in Python, but I have worked with that specific jar file before (it is part of a project we are working on). I am not allowed to modify much of both projects, and they are required to be as independent as possible.
I have researched multiple ways to include the jar methods in Python. So far, I have tried Jython (which I cannot use because the Python project uses PyQt among other libraries, which force the use of CPython, if my understanding is correct), Pyjnius and JPype. JPype seems the most promising, but I cannot get it working either. I have pasted the my code below, slightly censored because I don't know how much I am allowed to share.
from jpype import *
import jpype.imports
try:
jpype.addClassPath("jars/sdk.jar") #the relative path to the jar file
jpype.startJVM(convertStrings=False)
java.lang.System.out.println(jpype.getClassPath()) #printing the classpath to check, the path is correctly pointing to the sdk.jar file
java.lang.System.out.println("Hello world") #just to check if jpype is installed correctly, works
jpype.imports.registerDomain("a")
from a.b.c.d.e.f.g.h import SomeClass #fails here
except OSError as err:
print(err) # ToDo: Remove print when done
pass
The error I am getting is that the module a.b.c.d.e.f.g.h.SomeClass could not be found. I have tried different ways to give the path (absolute path, relative path, place the jar in different places in the project and outside of it), but that doesn't seem to be the problem, as the path printed is the correct absolute path to the jar file.
Also, the jar is used in other (Java) projects and it works. It is created using maven package (using IntelliJ, if it is relevant, and the same Java version as the one used by the JPype JVM). In the Java projects, the import would be:
import a.b.c.d.e.f.g.h.SomeClass;
I have copied this and just transformed the syntax into Python.
I have also tried to create the class with JObject (which I probably didn't do right anyway) and also tried the older syntax (to my understanding) with JPackage. For the JPackage way, I am getting the exception that the package a.b.c.d.e.f.g.h.SomeClass.someMethod is not Callable, which to my understanding is an equivalent exception to the one I'm getting using jpype imports. I have already gone through all the questions I could find here with similar problems, but none of those solutions have helped me.
Can anyone suggest some possible solution? Or can anyone see what I'm doing wrong? Suggestions of other possibilities to replace JPype are also welcomed. If there is any clarification needed, I will edit the question.
The only thing that seems likely if the jar is on the classpath and failed to import would be for there to be some missing dependency. You have two other ways to try loading the class which may provide additional diagnostics.
jpype.JClass("a.b.c.d.e.f.g.h.SomeClass")
and
jpype.JClass("java.lang.Class").forName("a.b.c.d.e.f.g.h.SomeClass")
The first is manually loading a class by full class specification. It is mechanically what is happening under the import. The second is calling for Java to load the class (bypassing all of JPype). It returns a java.lang.Class which can be passed to JClass to make a wrapper.
Common failures include missing a jar or native library, attempting to start JPype from within a module and having the wrong relative path, error in initialization of the class due to missing resource. JPype is just calling JNI calls, so if everything is fine on Java end it should work. Given that you checked the java.class.path System variable, it has to be something to do with class resources.
The JPype user manual has an alternatives section if you would like to try to find another package. Most of the alternatives with the exception of PyJnius appear to be unmaintained.
Related
I'm a n00b coder. I found an interesting library and trying to start toying with it. Which is not going great. This library is from 99' and uses JUnit (which I'm unfamiliar with) so there is a lot of confusing stuff. But it seems like the source of my failing even more elementary. Namely I have troubles importing packages.
This library has a test called StandardEvalTest.java. I moved to it to main Java directory and now I'm trying and failing to launch it using JUnit.
This package path org.pokersource.game.Deck goes directly from the directory where the test StandardEvalTest.java sits.
I also added the main java directory to the PATH environmental variable. Which as I assumed will allow import to locate the package.
None of those two things help. Also I was suspecting that maybe Deck.java and Deck.class are not enough and I have to do some work to create a package from it. But as far as I can say from Oracle doc the only thing needed is a package name in the header. Which seems to be present.
So I'm out of moves. Please help!
PS: Some additional info inspired by #Dhrubo 's answer:
The test I'm trying to run indeed sits in the main java folder of the library. (I moved it here hoping that when running from here it would be easier to find the package)
If I'm trying to compile the test instead of running it with JUnit he seem to fail to find JUnit classes and other JUnit related stuff.
[Oh OK I'm an idiot! Dont't mind me]
You should include the package while running StandardEvalTest.java as below
javac -cp [classpath] org.pokersource.game.StandardEvalTest.java
and run it from package root directory, I am assuming it is custom java file that you want to compile. You run directory should be parent of your package directory.
** I also see, you are trying to compile StandardEvalTest.java instead of Deck.java ... then check your StandardEvalTest.java file whether it exists in desired location.
I have a Netbeans project of some Java code I wrote many years ago. I am doing a new project in python now, but I have a Java class in my old project that has some handy MIDI code that I would like to use since I have so far been unable to easily translate to python.
I used pip to install JPype, used Netbeans to build the class I need, and moved the .class file into the same directory as my python file. Here is an abridged part of my python code to call the Java class, which is called "SoundTester" and was in a package called "soundsynthesis".
from jpype import startJVM, shutdownJVM, java, addClassPath, JClass, JInt
import jpype.imports
startJVM(convertStrings=False)
try:
pass # Not sure why we need a pass here
tester = JClass('soundsynthesis/SoundTester')
except Exception as e:
print(f"Exception: {e}")
shutdownJVM()
The result is
Exception: java.lang.NoClassDefFoundError: soundsynthesis/SoundTester
Note that if I change soundsynthesis/SoundTester to just SoundTester, I get this slightly different exception:
Exception: java.lang.NoClassDefFoundError: SoundTester (wrong name: soundsynthesis/SoundTester)
I'm thinking that the issue may be due to me moving the .class files out of the Netbeans project and into my working directory, but I don't know how to resolve that. I also tried moving the java files into my desired directory and just using javac to build them.
I have ensured that my version of python and the jdk are both 64-bit, as that was a similar question's issue.
This is an issue with the path specification. It is true that JNI usually refers to classes using the slash notation. However, in this case JClass calls the Java Class.forName() method which requires dot notation rather than JNI. Thus the solution to this issue is to use JClass('soundsynthesis.SoundTester').
Here is an example using the test harness in jpype.
import jpype
jpype.startJVM(classpath=['test/classes'], convertStrings=False)
j = jpype.JClass('jpype.common.Fixture') # success
j = jpype.JClass('jpype/common/Fixture') # fails
In general, JPype uses the notations that are found in Java itself rather than those imposed by JNI. For further examples, please see the section "Import a class without tld" in the quick guide.
I solved the issue. Perhaps not the most elegant solution, but I modified the Java classes so they instead were not in any package (or rather they were in the default package) and then moved them to my python working directory and built them with javac there.
Once I had .class files of my java classes, I could call
tester = JClass('SoundTester') with no problem whatsoever.
Hope this helps someone else.
I'm trying to develop an email parser - to take email that's in a file and be able to programmatically handle the various components - to know who the sender and recipient were, the subject line, main body, and any attachments. I intend to extract attachments as individual files, but I'm stumped right at the beginning.
I started with an already working java program in a fully-functional development environment and have begun adding to it. One of the first additions was this line (then later, set of lines):
import javax.mail.*;
import javax.mail.internet;
import javax.mail.internet.MimeUtility;
Later, in an appropriate place, we have this humble beginning:
MimeMessage m = null;
I was shocked to find that the compile failed with only these two changes, and I learned here (on another StackOverflow page) that the package javax.mail package isn't included in the standard JDK. Puzzled, I looked and found this:
# rpm -qa | grep -i java
android-json-org-java-4.3-0.2.r3.1.fc21.noarch
snappy-java-1.0.5-2.fc21.noarch
tzdata-java-2015b-1.fc21.noarch
python-javapackages-4.1.0-7.fc21.noarch
postgresql94-jdbc-javadoc-9.3.1101-1.f21.noarch
protobuf-java-2.5.0-11.fc21.x86_64
java-1.8.0-openjdk-1.8.0.40-25.b25.fc21.x86_64
java-1.8.0-openjdk-headless-1.8.0.40-25.b25.fc21.x86_64
javassist-3.18.1-2.fc21.noarch
apache-commons-javaflow-1.0-0.8.20120509SNAPSHOT.fc21.noarch
javapackages-tools-4.1.0-7.fc21.noarch
java-1.8.0-openjdk-devel-1.8.0.40-25.b25.fc21.x86_64
antlr3-java-3.5.2-2.fc21.noarch
javamail-1.5.1-3.fc21.noarch
xz-java-1.5-3.fc21.noarch
abrt-java-connector-1.1.0-2.fc21.x86_64
Please note that yes, actually, JavaMail is installed - version 1.5.1-3. However, just to be a belts and suspenders kinda person, I found the JavaMail project and downloaded the latest production version, and put it in the CLASSPATH.
To my great surprise, this did not cure the problem! Being the careful type, and keeping things simple to prove the way as I go, I simply removed the javax.mail.jar file from the library directory, then removed the two lines from my program, recompiled and it worked. Then, I added back in the import line, and it failed. Then I moved the jar file back into the library directory and the compile succeeded, confirming that the javax.mail package was being loaded.
However, when I added in the first reference to the library, MimeMessage (see the line above), the compile failed.
So, of course, I went to check the documentation! Indeed, MimeMessage is an available class.
What am I doing wrong?! I mean, geez, I've been using Java literally since version 1.0 - I'm not known for making too many dumb mistakes, but I figure I must be!
Two open questions come to my mind:
1) Why isn't the installed version of the JavaMail package being used? CLEARLY I had to add it. And do note that I don't have to do ANYTHING special to CLASSPATH (or anywhere else) to get all the rest of Java! And;
2) Now that I've got a JavaMail package in there, why is it not discovering the MimeMessage class?
Any / all help appreciated - and if you spot me being abjectly stupid, please point out my error gently!
Additional Information:
I added two more import lines, so there are now the three listed above. Curiously, when I have the .jar file in the path specified by CLASSPATH, but not explicitly cited, I get one error per import, but when I explicitly cite the .jar file as an explicit item, I only get ONE error! That one error is on:
import javax.mail.internet;
Naturally, knowing that the jar is actually just a zip, I unzipped and looked. Sure enough, a directory named "internet" is there, populated with 38 class files.
Somewhere along the way, I had a wild idea that somehow there was ANOTHER javax.mail entry on the system or in the CLASSPATH, so I looked. This is Fedora Core, so it's under /usr/lib, and I did NOT find another file including the string "mail" in its name, so I presume that's not it, either.
I noticed in the NOTES.txt file that there were some notes about not unpacking the jar for some applications because that was seen as a security risk, but I figured that for what I want to do there is no such risk and maybe it would work, but I couldn't get THAT to work either...
I've also been trying using -cp versus actually altering the CLASSPATH variable, but it doesn't seem to matter. I apparently get identical results either way, so I've just been using -cp for testing because it's faster to try various alternatives.
MimeMessage is in the javax.mail.internet package, which you haven't imported.
EDITED BY QUESTION ASKER:
Actually, I was trying to import, among other things:
import javax.mail.internet;
And that didn't work. What I was missing was that there's nothing to import on just javax.mail.internet. Changing it to:
import javax.mail.internet.*;
worked just fine!
So, while Bill wasn't quite correct, this answer plus his comment got me to see what I was blind to... and I feel silly!
I have written a Java Class for use in JMeter, packaged the project as a .jar file and moved that file into the lib/ext folder in the jmeter directory. I have seen documentation on how to proceed but they give contradictory answers.
The first way is to use the BeanShell Sampler to import my package and class, create an object of the class and run the methods that way. I have used this method using example classes with more simple file structures than that of class I want to run. The example classes work with the following BeanShell script.
import tools.JmeterTools;
JmeterTools jt = new JmeterTools();
jt.foo();
When I try to use this method for the class I want to run, it states that the variable declaration is an error and the Class cannot be found. I assume this is because I do not understand what to import exactly, as the file structure in my project is a little odd.
The second uses the BeanShell PreProcessor to add the jar to the class path. This method I have not been able to get to work at all, but have read many accounts of others finding success. It works as follows:
addClassPath("directory path to jar\lib\ext\foo.jar");
JMeterTest jtm = new JMeterTest();
jmt.test();
Would anyone have any knowledge of which way would work better or any ideas on how to fix the import?
The import I have been using in the BeanShell script is the following:
import client.JMeterTest;
The package line at the top of my class is the following
import com.x.foo.client;
You need to have your jar file in JMETER_HOME/lib folder.
lib/ext is for JMeter extensions/plugins etc.
Once you have placed your jar, you might have to restart JMeter.
Running external classes from Beanshell should work fine given the following preconditions met
Your test with dependencies is located in JMeter classpath.
JMeter restart is required to pick new libraries up
You need to provide full package name plus full class name (or wildcard) for import.
Either
import com.x.foo.client.JMeterTest;
or
import com.x.foo.client.*;
And finally it is recommended to use JSR223 Sampler and use "groovy" as a language. Beanshell interpreter has severe performance issues so use it for something very "light" like variable amendment, converting variable to property, etc. For generating the real load use JSR223 and groovy as it implements Compilable interface and hence you can achieve performance similar to native Java code. See Beanshell vs JSR223 vs Java JMeter Scripting: The Performance-Off You've Been Waiting For! guide for detailed explanation, benchmarking and instructions on installation of groovy scripting engine support.
For anyone who has this issue in the future. The answers given by others are correct. It wasn't working for me because I had forgotten that Maven does not package files in the test directory when a jar is made.
This link may help if anyone ever does this in the future.
Generate test-jar along with jar file in test package
I'm writing a Java class that will be used to send PDUs across a network- to do this, I am following the tutorial at: Tutorial
In the example, the line:
double lla[] = CoordinateConversions.xyzToLatLonDegrees(c);
appears towards the end of the class, and I see that CoordinateConversions has been imported with the line:
import edu.nps.moves.disutil.CoordinateConversions;
I have tried using the xyzToLatLonDegrees(); method in the class that I am writing- calling it in the same way as is done in the example. However, for some reason, I get a compile error that says:
CoordinateConversions cannot be resolved
on the line where I'm trying to use it, and
The import edu.nps.moves.disutil.CoordinateConversions cannot be resolved
on the line where I am importing it.
Does anyone know why this is, and how I can fix the import, so that I can use the xyzToLatLonDegrees() method?
You need to have the CoordinateConversions class on your classpath. Either by obtaining the source and dropping it into your project (possibly adjusting package names, and only if the license allows), or by finding a JAR containing that class and adding it to your build path in your IDE.
You probably need to download the Java files from here.