jni define метод класса возвращает сообщение об исключении: ls.Hello (неправильное имя: ls / Hello) - PullRequest
0 голосов
/ 16 февраля 2012

Я пытаюсь обойти вызов метода JNIEnv-> DefineClass со всеми необходимыми параметрами, но он всегда возвращает ошибку java.lang.NoClassDefFoundError: ls.Hello (неправильное имя: ls / Hello), когда я пытаюсь вызвать метод из Java , Я не уверен, что не так. Пожалуйста, смотрите код JNI ниже:

#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;
}

Вот код TestClassLoader, который вызывает нативный

Также содержимое txt файла является файлом двоичного класса

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

Любая помощь очень ценится.

Спасибо

1 Ответ

1 голос
/ 16 февраля 2012

Последний параметр для DefineClass - это длина массива, но вы указали постоянное значение.Хотя в JNI не указано, что DefineClass выбрасывает NoClassDefFoundError, посмотрите на этот отчет об ошибках .

ClassLoader.defineClass (имя строки, byte [] b, int off, intlen) выбрасывает NoClassDefFoundError, если имя не соответствует имени, полученному из массива данных класса.

Возможно, что-то не так с названием класса, которое вы указали.Неясно, какое имя класса вы передаете.Что действует как разделитель имен пакетов?""или "/"?

UPD.

Я пробовал ваш код.Проблема в следующей строке (код Java):

result = defineClassX(className, classByte, classByte.length);

Передаваемый вами className равен "ls.Hello".Но JNI требует, чтобы все имена классов были в форме «aaa / bbb / ccc / ClassName», а не «aaa.bbb.ccc.ClassName».Просто замените . на /, и он загрузит ваш класс.

Также обратите внимание, что вы звоните GetStringUTFChars и GetByteArrayElements, но не балансируете их с ReleaseStringUTFChars и ReleaseByteArrayElements.Это может привести к утечке памяти и непредсказуемому поведению.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...