I am trying to bypass the call JNIEnv->DefineClass method with all necessary parameter but it always returns java.lang.NoClassDefFoundError: ls.Hello (wrong name: ls/Hello) error when I try to call the method from java. I am not sure what is wrong.
Please see the JNI Code below:
#include<jni.h>
#include<ls_TestClassLoader.h>
#include<iostream>
using namespace std;
//JNIEnv *, jobject, jstring, jbyteArray, jint
JNIEXPORT jclass JNICALL Java_ls_TestClassLoader_defineClassX(JNIEnv *env, jobject obj, jstring name, jbyteArray data, jint len){
JNIEnv &e=*env;
jboolean isCopy;
jclass cls= e.DefineClass(e.GetStringUTFChars(name,&isCopy),obj,e.GetByteArrayElements(data,&isCopy),500);
return cls;
}
Here is the TestClassLoader code which calls the native
Also contents of txt file is binary class file
public class TestClassLoader extends ClassLoader {
static {
System.loadLibrary("TestClassLoader");
}
private native Class defineClassX(String name, byte[] b, int len);
public TestClassLoader() {
super(TestClassLoader.class.getClassLoader());
}
@Override
public Class<?> findClass(String className) {
byte classByte[];
Class result = null;
result = (Class) classes.get(className);
if (result != null) {
return result;
}
try {
return findSystemClass(className);
} catch (Exception e) {
}
try {
classByte = loadData(className);
result = defineClassX(className, classByte, classByte.length);
classes.put(className, result);
return result;
} catch (Exception e) {
Logger.getLogger(TestClassLoader.class.getName()).log(Level.SEVERE, null, e);
return null;
}
}
private byte[] loadData(String name) {
try {
String res = "/"+name.replace(".", "/") + ".txt";
InputStream is = TestClassLoader.class.getResourceAsStream(res);
ByteArrayOutputStream os = new ByteArrayOutputStream();
int d = 0;
while ((d = is.read()) != -1) {
os.write(d);
}
return os.toByteArray();
} catch (IOException ex) {
Logger.getLogger(TestClassLoader.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
private Hashtable classes = new Hashtable();
}
Any help is greatly appreciated.
Thanks
The last parameter for
DefineClassis length of the array, but you specified constant value. Although JNI docs not states thatDefineClassthrowsNoClassDefFoundError, look at this bugreport.Maybe it is really something wrong with the name of class you specified. It is unclear what class name you passing. What acts as package name separator? "." or "/"?
UPD.
I’ve tried your code. The problem is in line below (Java code):
The
classNameyou passing is"ls.Hello". But JNI requires all class names to be in the form "aaa/bbb/ccc/ClassName", not the "aaa.bbb.ccc.ClassName". Just replace.with/and it will load your class.Also note that you call
GetStringUTFCharsandGetByteArrayElements, but not balance them withReleaseStringUTFCharsandReleaseByteArrayElements. It may lead to memory leak and unpredictable behavior.