簡體   English   中英

如果缺少類依賴項,如何確定缺少哪個類?

[英]If a class dependency is missing, how can I determine which class is missing?

我收到錯誤“無法找到或加載主類”,即使班級在那里。 這個答案中 ,我了解到由於缺少依賴性,可能會找到該類,但是沒有加載。

除了手動反編譯類,檢查它的所有依賴項,以及它們是否在類路徑上,依此類推,每個依賴類廣告無限....有沒有辦法確定類路徑中缺少哪個類因此導致Java無法加載我的主類?

另一個問題是缺少父/接口類的問題。 但我已手動檢查所有祖先類是在指定的類路徑上還是在JDK中,如下所示。

$ cd ~/picketbox
$ java -cp picketbox-4.1.1.Final-redhat-1.jar org.picketbox.datasource.security.SecureIdentityLoginModule HelloWorld
Error: Could not find or load main class org.picketbox.datasource.security.SecureIdentityLoginModule
$ jar xvf picketbox-4.1.1.Final-redhat-1.jar > jarxvf.txt
$ cat jarxvf.txt | grep SecureIdentityLoginModule
 inflated: org/picketbox/datasource/security/SecureIdentityLoginModule.class
$ cd org/picketbox/datasource/security/
$ javap SecureIdentityLoginModule.class | grep main
  public static void main(java.lang.String[]) throws java.lang.Exception;
$ javap SecureIdentityLoginModule.class | grep extends
public class org.picketbox.datasource.security.SecureIdentityLoginModule extends org.picketbox.datasource.security.AbstractPasswordCredentialLoginModule {
$ cat ~/picketbox/jarxvf.txt | grep AbstractPasswordCredentialLoginModule
 inflated: org/picketbox/datasource/security/AbstractPasswordCredentialLoginModule.class
$ javap AbstractPasswordCredentialLoginModule.class | grep extends
public abstract class org.picketbox.datasource.security.AbstractPasswordCredentialLoginModule extends org.jboss.security.auth.spi.AbstractServerLoginModule {
$ cat ~/picketbox/jarxvf.txt | grep AbstractServerLoginModule
 inflated: org/jboss/security/auth/spi/AbstractServerLoginModule.class
$ cd ~/picketbox/org/jboss/security/auth/spi/
$ javap AbstractServerLoginModule.class | grep implements
public abstract class org.jboss.security.auth.spi.AbstractServerLoginModule implements javax.security.auth.spi.LoginModule {
$ cd ~/rtjar
$ cp /usr/java/jdk1.8.0_141/jre/lib/rt.jar ./
$ jar xvf rt.jar | grep spi/LoginModule
extracted: javax/security/auth/spi/LoginModule.class
$ cd javax/security/auth/spi/
$ javap LoginModule.class | grep interface
public interface javax.security.auth.spi.LoginModule {
$

創建一個幫助器類:

public class Helper {
    public static void main(String[] args) {
        YourActualMainClass.main(args);
    }
}

並嘗試運行此助手類而不是YourActualMainClass

關鍵是Helper的繼承樹和其成員的簽名都不依賴於有問題的類,因此加載甚至初始化都會成功,因為HotSpot的延遲解析策略,所以它只會嘗試加載和解析YourActualMainClass執行Helper.main方法。 此時,它會拋出一個詳細錯誤,告訴您實際上缺少哪個類。

這與鏈接答案中描述的行為相匹配,即當使用類的繼承不依賴於它時,類的使用會導致特定的錯誤消息。


或者,您可以嘗試使用Java 9運行應用程序,因為它的啟動程序將在主類加載失敗時打印原因。

您可以嘗試使用JVMTI顯示拋出的所有異常。 通過JVMTI識別異常開始。 只需使用以下更新的agent.c源代碼即可。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <jni.h>
#include <jvmti.h>

#define CHECK_JVMTI_ERROR(x,call) \
    { if (x != JVMTI_ERROR_NONE) { fprintf (stderr, "Error during %s in %s:%d\n", #call, __FILE__, __LINE__); } }

/* Global static data */
static jvmtiEnv     *jvmti;

static void JNICALL cb_Exception (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
    jthread thread, jmethodID method, jlocation location, jobject exception,
    jmethodID catch_method, jlocation catch_location)
{
    jclass exceptionClass = (*jni_env)->GetObjectClass(jni_env, exception);

    jmethodID methodId = (*jni_env)->GetMethodID(jni_env, exceptionClass,
                         "printStackTrace",
                         "()V");

    (*jni_env)->CallVoidMethod(jni_env, exception, methodId);
}

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
{
    jint                rc;
    jvmtiError          r;
    jvmtiCapabilities   capabilities;
    jvmtiEventCallbacks callbacks;

    /* Get JVMTI environment */
    rc = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION);
    if (rc != JNI_OK)
    {
        fprintf (stderr, "Error!: Unable to create jvmtiEnv, rc=%d\n", rc);
        return -1;
    }

    /* Get/Add JVMTI capabilities */
    memset(&capabilities, 0, sizeof(capabilities));
    capabilities.can_generate_exception_events = 1;
    r = (*jvmti)->AddCapabilities(jvmti, &capabilities);
    CHECK_JVMTI_ERROR(r, AddCapabilities);

    /* Set callbacks and enable event notifications */
    memset(&callbacks, 0, sizeof(callbacks));
    callbacks.Exception               = &cb_Exception;
    r = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
    CHECK_JVMTI_ERROR(r, SetEventCallbacks);

    /* Exception events */
    r = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, 
      JVMTI_EVENT_EXCEPTION, NULL);
    CHECK_JVMTI_ERROR(r, SetEventNotificationMode);

    return 0;
}

JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm)
{
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM