javapythonjavacjpype

How do I build my java classes to not result in NoClassDefFoundException from JPype?


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.


Solution

  • 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.