我正在尝试在Windows上测试libhdfs,它使用JNI调用Java函数(创建的JVM),但是在加载hadoop类时,findclass总是失败。

我已经搜索并搜索了stackoverflow,找不到适合我的问题,请帮忙。

系统:

Windows 7 32-bit
Visual Studio 2013 Express
JDK 1.6.0_32
Hadoop 2.5.0 (it's working fine using command)

问题:
when program executed to getGlobalJNIEnv -> globalClassReference -> FindClass

    local_clazz = (*env)->FindClass(env, className); // classname = org/apache/hadoop/fs/FileSystem

org.apache.hadoop.fs.FileSystem is in C:\hadoop\share\hadoop\common\hadoop-common-2.5.0.jar, which is in CLASSPATH

FindClass always return null.

libhdfs 代码:
static JNIEnv* getGlobalJNIEnv(void)
{
    JavaVM* vmBuf[VM_BUF_LENGTH];
    JNIEnv *env;
    jint rv = 0;
    jint noVMs = 0;
    jthrowable jthr;
    char *hadoopClassPath;
    const char *hadoopClassPathVMArg = "-Djava.class.path=";
    size_t optHadoopClassPathLen;
    char *optHadoopClassPath;
    const int noArgs = 6;
    char *hadoopJvmArgs;
    char jvmArgDelims[] = " ";
    char *str, *token, *savePtr;
    JavaVMInitArgs vm_args;
    JavaVM *vm;
    JavaVMOption *options;

    rv = JNI_GetCreatedJavaVMs(&(vmBuf[0]), VM_BUF_LENGTH, &noVMs);
    if (rv != 0) {
        fprintf(stderr, "JNI_GetCreatedJavaVMs failed with error: %d\n", rv);
        return NULL;
    }

    if (noVMs == 0) {
        //Get the environment variables for initializing the JVM
        hadoopClassPath = getenv("CLASSPATH");
        if (hadoopClassPath == NULL) {
            fprintf(stderr, "Environment variable CLASSPATH not set!\n");
            return NULL;
        }
        optHadoopClassPathLen = strlen(hadoopClassPath) +
            strlen(hadoopClassPathVMArg) + 1;
        optHadoopClassPath = malloc(sizeof(char)*optHadoopClassPathLen);
        snprintf(optHadoopClassPath, optHadoopClassPathLen,
            "%s%s", hadoopClassPathVMArg, hadoopClassPath);



        // Now that we know the # args, populate the options array
        options = calloc(noArgs, sizeof(JavaVMOption));
        if (!options) {
            fputs("Call to calloc failed\n", stderr);
            free(optHadoopClassPath);
            return NULL;
        }

        options[0].optionString = optHadoopClassPath;
        options[1].optionString = "-Djava.library.path=C:\\Progra~1\\Java\\jdk1.6.0_32\\lib";
        options[2].optionString = "-Djava.compiler=NONE";
        options[3].optionString = "-verbose:jni";
        options[4].optionString = "-verbose:class";
        options[5].optionString = "-verbose:gc";



        //Create the VM
        vm_args.version = JNI_VERSION_1_6;
        vm_args.options = options;
        vm_args.nOptions = noArgs;
        vm_args.ignoreUnrecognized = JNI_FALSE;

        rv = JNI_CreateJavaVM(&vm, (void*)&env, &vm_args);

        if (rv != 0) {
            fprintf(stderr, "Call to JNI_CreateJavaVM failed "
                "with error: %d\n", rv);
            return NULL;
        }
        jthr = invokeMethod(env, NULL, STATIC, NULL,
            "org/apache/hadoop/fs/FileSystem",
            "loadFileSystems", "()V");

        free(optHadoopClassPath);
        free(options);

        if (jthr) {
            printExceptionAndFree(env, jthr, PRINT_EXC_ALL, "loadFileSystems");
        }

    }
    else {
        //Attach this thread to the VM
        vm = vmBuf[0];
        rv = (*vm)->AttachCurrentThread(vm, (void*)&env, 0);
        if (rv != 0) {
            fprintf(stderr, "Call to AttachCurrentThread "
                "failed with error: %d\n", rv);
            return NULL;
        }
    }

    return env;
}


jthrowable globalClassReference(const char *className, JNIEnv *env, jclass *out)
{
    jthrowable jthr = NULL;
    jclass local_clazz = NULL;
    jclass clazz = NULL;
    int ret;

    mutexLock(&hdfsHashMutex);
    if (!gClassRefHTable) {
        gClassRefHTable = htable_alloc(MAX_HASH_TABLE_ELEM, ht_hash_string,
            ht_compare_string);
        if (!gClassRefHTable) {
            jthr = newRuntimeError(env, "htable_alloc failed\n");
            goto done;
        }
    }
    clazz = htable_get(gClassRefHTable, className);
    if (clazz) {
        *out = clazz;
        goto done;
    }

    local_clazz = (*env)->FindClass(env, className);

    if (!local_clazz) {

        (*env)->ExceptionDescribe(env);

        jthr = getPendingExceptionAndClear(env);
        goto done;
    }
    clazz = (*env)->NewGlobalRef(env, local_clazz);
    if (!clazz) {
        jthr = getPendingExceptionAndClear(env);
        goto done;
    }
    ret = htable_put(gClassRefHTable, (void*)className, clazz);
    if (ret) {
        jthr = newRuntimeError(env, "htable_put failed with error "
            "code %d\n", ret);
        goto done;
    }
    *out = clazz;
    jthr = NULL;
done:
    mutexUnlock(&hdfsHashMutex);
    (*env)->DeleteLocalRef(env, local_clazz);
    if (jthr && clazz) {
        (*env)->DeleteGlobalRef(env, clazz);
    }
    return jthr;
}

jthrowable getPendingExceptionAndClear(JNIEnv *env)
{
    jthrowable jthr = (*env)->ExceptionOccurred(env);
    if (!jthr)
        return NULL;
    (*env)->ExceptionClear(env);
    return jthr;
}

int printExceptionAndFreeV(JNIEnv *env, jthrowable exc, int noPrintFlags,
        const char *fmt, va_list ap)
{
    int i, noPrint, excErrno;
    char *className = NULL;
    jstring jStr = NULL;
    jvalue jVal;
    jthrowable jthr;

    jthr = classNameOfObject(exc, env, &className);
    if (jthr) {
        fprintf(stderr, "PrintExceptionAndFree: error determining class name "
            "of exception.\n");
        className = strdup("(unknown)");
        destroyLocalReference(env, jthr);
    }
    for (i = 0; i < EXCEPTION_INFO_LEN; i++) {
        if (!strcmp(gExceptionInfo[i].name, className)) {
            break;
        }
    }
    if (i < EXCEPTION_INFO_LEN) {
        noPrint = (gExceptionInfo[i].noPrintFlag & noPrintFlags);
        excErrno = gExceptionInfo[i].excErrno;
    } else {
        noPrint = 0;
        excErrno = EINTERNAL;
    }
    if (!noPrint) {
        vfprintf(stderr, fmt, ap);
        fprintf(stderr, " error:\n");

        // We don't want to  use ExceptionDescribe here, because that requires a
        // pending exception.  Instead, use ExceptionUtils.
        jthr = invokeMethod(env, &jVal, STATIC, NULL,
            "org/apache/commons/lang/exception/ExceptionUtils",
            "getStackTrace", "(Ljava/lang/Throwable;)Ljava/lang/String;", exc);
        if (jthr) {
            fprintf(stderr, "(unable to get stack trace for %s exception: "
                    "ExceptionUtils::getStackTrace error.)\n", className);
            destroyLocalReference(env, jthr);
        } else {
            jStr = jVal.l;
            const char *stackTrace = (*env)->GetStringUTFChars(env, jStr, NULL);
            if (!stackTrace) {
                fprintf(stderr, "(unable to get stack trace for %s exception: "
                        "GetStringUTFChars error.)\n", className);
            } else {
                fprintf(stderr, "%s", stackTrace);
                (*env)->ReleaseStringUTFChars(env, jStr, stackTrace);
            }
        }
    }
    destroyLocalReference(env, jStr);
    destroyLocalReference(env, exc);
    free(className);
    return excErrno;
}

int printExceptionAndFree(JNIEnv *env, jthrowable exc, int noPrintFlags,
        const char *fmt, ...)
{
    va_list ap;
    int ret;

    va_start(ap, fmt);
    ret = printExceptionAndFreeV(env, exc, noPrintFlags, fmt, ap);
    va_end(ap);
    return ret;
}

环境变量:
C:\>hadoop classpath
c:\hadoop\etc\hadoop;C:\hadoop\share\hadoop\common\lib\*;C:\hadoop\share\hadoop\
common\*;C:\hadoop\share\hadoop\hdfs;C:\hadoop\share\hadoop\hdfs\lib\*;C:\hadoop
\share\hadoop\hdfs\*;C:\hadoop\share\hadoop\yarn\lib\*;C:\hadoop\share\hadoop\ya
rn\*;C:\hadoop\share\hadoop\mapreduce\lib\*;C:\hadoop\share\hadoop\mapreduce\*

CLASSPATH = c:\Progra~1\Java\jdk1.6.0_32\lib;c:\Progra~1\Java\jdk1.6.0_32\jre\lib;c:\hadoop\etc\hadoop;C:\hadoop\share\hadoop\common\lib\*;C:\hadoop\share\hadoop\common\*;C:\hadoop\share\hadoop\hdfs;C:\hadoop\share\hadoop\hdfs\lib\*;C:\hadoop\share\hadoop\hdfs\*;C:\hadoop\share\hadoop\yarn\lib\*;C:\hadoop\share\hadoop\yarn\*;C:\hadoop\share\hadoop\mapreduce\lib\*;C:\hadoop\share\hadoop\mapreduce\*

JAVA_HOME = c:\Progra~1\Java\jdk1.6.0_32

控制台输出:(在findclass之后添加ExceptionDescribe后更新)
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/hadoop/fs/
FileSystem
Caused by: java.lang.ClassNotFoundException: org.apache.hadoop.fs.FileSystem
        at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/hadoop/fs/
FileSystem
Caused by: java.lang.ClassNotFoundException: org.apache.hadoop.fs.FileSystem
        at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
could not find method loadFileSystems from class org/apache/hadoop/fs/FileSystem
 with signature ()V
loadFileSystems error:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/la
ng/exception/ExceptionUtils
Caused by: java.lang.ClassNotFoundException: org.apache.commons.lang.exception.E
xceptionUtils
        at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/la
ng/exception/ExceptionUtils
Caused by: java.lang.ClassNotFoundException: org.apache.commons.lang.exception.E
xceptionUtils
        at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
could not find method getStackTrace from class org/apache/commons/lang/exception
/ExceptionUtils with signature (Ljava/lang/Throwable;)Ljava/lang/String;
(unable to get stack trace for java.lang.NoSuchMethodError exception: ExceptionU
tils::getStackTrace error.)
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/hadoop/con
f/Configuration
Caused by: java.lang.ClassNotFoundException: org.apache.hadoop.conf.Configuratio
n
        at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/hadoop/con
f/Configuration
Caused by: java.lang.ClassNotFoundException: org.apache.hadoop.conf.Configuratio
n
        at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)

最佳答案

Caused by: java.lang.ClassNotFoundException: org.apache.hadoop.fs.FileSystem

您在CLASSPATH上没有该类。

09-10 03:16