8267796: vmTestbase/nsk/jvmti/scenarios/hotswap/HS201/hs201t002/TestDescription.java fails with NoClassDefFoundError
Reviewed-by: kevinw, cjplummer
This commit is contained in:
parent
12a822a287
commit
f12200cd11
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -24,6 +24,7 @@
|
||||
package nsk.jvmti.scenarios.hotswap.HS201;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import nsk.share.*;
|
||||
import nsk.share.jvmti.*;
|
||||
@ -73,14 +74,23 @@ public class hs201t002 extends DebugeeClass {
|
||||
timeout = argHandler.getWaitTime() * 60 * 1000; // milliseconds
|
||||
|
||||
log.display(">>> starting tested thread");
|
||||
Thread thread = new hs201t002Thread();
|
||||
hs201t002Thread thread = new hs201t002Thread();
|
||||
|
||||
// testing sync
|
||||
status = checkStatus(status);
|
||||
|
||||
setThread(thread);
|
||||
thread.start();
|
||||
|
||||
// setThread(thread) enables JVMTI events, and that can only be done on a live thread,
|
||||
// so wait until the thread has started.
|
||||
try {
|
||||
thread.ready.await();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
setThread(thread);
|
||||
|
||||
thread.go.countDown();
|
||||
|
||||
while (currentStep != 4) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
@ -114,6 +124,10 @@ public class hs201t002 extends DebugeeClass {
|
||||
}
|
||||
|
||||
log.display("Thread suspended in a wrong moment. Retrying...");
|
||||
for (int i = 0; i < stackTrace.length; i++) {
|
||||
log.display("\t" + i + ". " + stackTrace[i]);
|
||||
}
|
||||
log.display("Retrying...");
|
||||
resumeThread(thread);
|
||||
suspendTry++;
|
||||
// Test thread will be suspended at the top of the loop. Let it run for a while.
|
||||
@ -136,12 +150,20 @@ public class hs201t002 extends DebugeeClass {
|
||||
|
||||
class hs201t002Thread extends Thread {
|
||||
|
||||
CountDownLatch ready = new CountDownLatch(1);
|
||||
CountDownLatch go = new CountDownLatch(1);
|
||||
|
||||
hs201t002Thread() {
|
||||
setName("hs201t002Thread");
|
||||
}
|
||||
|
||||
public void run() {
|
||||
// run method
|
||||
ready.countDown();
|
||||
try {
|
||||
go.await();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
try {
|
||||
throwException();
|
||||
} catch (Exception e) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -71,7 +71,7 @@
|
||||
* newclass
|
||||
*
|
||||
* @run main/othervm/native
|
||||
* -agentlib:hs201t002=pathToNewByteCode=./bin,-waittime=5
|
||||
* nsk.jvmti.scenarios.hotswap.HS201.hs201t002
|
||||
* -agentlib:hs201t002=pathToNewByteCode=./bin,-waittime=5,-verbose
|
||||
* nsk.jvmti.scenarios.hotswap.HS201.hs201t002 -verbose
|
||||
*/
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -45,16 +45,18 @@ static jlong timeout = 0;
|
||||
#define PATH_TO_NEW_BYTECODE "pathToNewByteCode"
|
||||
|
||||
static jint testStep;
|
||||
static int redefineNumber;
|
||||
static jint newClassSize;
|
||||
static unsigned char* newClassBytes;
|
||||
static jthread testedThread;
|
||||
static jclass testClass;
|
||||
char chbuffer[255];
|
||||
|
||||
const char* getThreadName(JNIEnv* jni_env, jthread thread);
|
||||
// callbackException (isCatch == false) and callbackExceptionCatch (isCatch == true) handler
|
||||
void handleException(bool isCatch,
|
||||
jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread,
|
||||
jmethodID method, jlocation location,
|
||||
jobject exception);
|
||||
|
||||
const char* getThreadName(jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread);
|
||||
const char* getClassName(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jobject object);
|
||||
int readNewBytecode(jvmtiEnv* jvmti);
|
||||
int readNewBytecode(jvmtiEnv* jvmti, jint *newClassSize, unsigned char* *newClassBytes);
|
||||
int getLocalVariableValue(jvmtiEnv *jvmti_env, jthread thread, jmethodID method);
|
||||
|
||||
/* ============================================================================= */
|
||||
@ -99,17 +101,19 @@ void disableEvent(jvmtiEnv *jvmti_env, jvmtiEvent event, jthread thread) {
|
||||
void redefineClass(jvmtiEnv *jvmti_env, jclass klass) {
|
||||
|
||||
jvmtiClassDefinition classDef;
|
||||
|
||||
char *className;
|
||||
jint newClassSize;
|
||||
unsigned char* newClassBytes;
|
||||
|
||||
if (!NSK_JVMTI_VERIFY(jvmti_env->GetClassSignature(klass, &className, NULL))) {
|
||||
nsk_jvmti_setFailStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NSK_VERIFY(readNewBytecode(jvmti_env))) {
|
||||
if (!NSK_VERIFY(readNewBytecode(jvmti_env, &newClassSize, &newClassBytes))) {
|
||||
NSK_COMPLAIN0("TEST FAILED: new bytecode could not be read\n");
|
||||
nsk_jvmti_setFailStatus();
|
||||
jvmti_env->Deallocate((unsigned char*)className);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -121,12 +125,14 @@ void redefineClass(jvmtiEnv *jvmti_env, jclass klass) {
|
||||
if (!NSK_JVMTI_VERIFY(jvmti_env->RedefineClasses(1, &classDef))) {
|
||||
NSK_COMPLAIN1("TEST FAILED: while redefining class %s\n", className);
|
||||
nsk_jvmti_setFailStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*)className))) {
|
||||
nsk_jvmti_setFailStatus();
|
||||
}
|
||||
if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate(newClassBytes))) {
|
||||
nsk_jvmti_setFailStatus();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -136,7 +142,6 @@ void redefineClass(jvmtiEnv *jvmti_env, jclass klass) {
|
||||
static void JNICALL
|
||||
agentProc(jvmtiEnv* jvmti, JNIEnv* agentJNI, void* arg) {
|
||||
|
||||
redefineNumber = 1;
|
||||
jni = agentJNI;
|
||||
|
||||
NSK_DISPLAY0("Waiting for debuggee to become ready\n");
|
||||
@ -144,7 +149,7 @@ agentProc(jvmtiEnv* jvmti, JNIEnv* agentJNI, void* arg) {
|
||||
return;
|
||||
|
||||
testStep = 1;
|
||||
NSK_DISPLAY0("\n\n>>>> Debugge started, waiting for class loading \n");
|
||||
NSK_DISPLAY0(">>>> Debugge started, waiting for class loading \n");
|
||||
if (!nsk_jvmti_resumeSync())
|
||||
return;
|
||||
|
||||
@ -183,27 +188,20 @@ callbackClassLoad(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
|
||||
jclass klass) {
|
||||
|
||||
char *className;
|
||||
char *generic;
|
||||
|
||||
if (!NSK_JVMTI_VERIFY(jvmti_env->GetClassSignature(klass, &className, &generic))) {
|
||||
if (!NSK_JVMTI_VERIFY(jvmti_env->GetClassSignature(klass, &className, NULL))) {
|
||||
nsk_jvmti_setFailStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(className, EXPECTED_CLASS_SIGN) == 0) {
|
||||
NSK_DISPLAY1("\n\n>>>> Class loaded: %s", className);
|
||||
NSK_DISPLAY0(", activating breakpoint\n");
|
||||
NSK_DISPLAY1(">>>> Class loaded: %s, activating breakpoint\n", className);
|
||||
setBreakPoint(jvmti_env, jni_env, klass);
|
||||
}
|
||||
|
||||
if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*)className))) {
|
||||
nsk_jvmti_setFailStatus();
|
||||
}
|
||||
|
||||
if (generic != NULL)
|
||||
if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*)generic))) {
|
||||
nsk_jvmti_setFailStatus();
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================= */
|
||||
@ -216,7 +214,7 @@ JNIEXPORT void JNICALL
|
||||
callbackBreakpoint(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
|
||||
jmethodID method, jlocation location) {
|
||||
|
||||
NSK_DISPLAY0("\n\n>>>>Breakpoint fired, enabling SINGLE_STEP\n");
|
||||
NSK_DISPLAY0(">>>>Breakpoint fired, enabling SINGLE_STEP\n");
|
||||
enableEvent(jvmti_env, JVMTI_EVENT_SINGLE_STEP, thread);
|
||||
}
|
||||
|
||||
@ -266,7 +264,7 @@ callbackSingleStep(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
|
||||
|
||||
case 2:
|
||||
|
||||
NSK_DISPLAY1("\n\n>>>> Checking if redefined method is not obsolete\n", testStep);
|
||||
NSK_DISPLAY1(">>>> Checking if redefined method is not obsolete\n", testStep);
|
||||
|
||||
if (!NSK_JVMTI_VERIFY(jvmti->IsMethodObsolete(method, &is_obsolete))) {
|
||||
NSK_COMPLAIN0("TEST FAILED: unable to check method to be obsolete\n");
|
||||
@ -283,7 +281,7 @@ callbackSingleStep(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
|
||||
|
||||
case 3:
|
||||
|
||||
NSK_DISPLAY1("\n\n>>>> Popping the currently executing frame\n", testStep);
|
||||
NSK_DISPLAY1(">>>> Popping the currently executing frame\n", testStep);
|
||||
testStep++;
|
||||
setCurrentStep(jni_env, testStep);
|
||||
|
||||
@ -292,7 +290,7 @@ callbackSingleStep(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
|
||||
case 5:
|
||||
|
||||
if (value < 10) {
|
||||
NSK_DISPLAY1("\n\n>>>> Disabling single step\n", testStep);
|
||||
NSK_DISPLAY1(">>>> Disabling single step\n", testStep);
|
||||
disableEvent(jvmti_env, JVMTI_EVENT_SINGLE_STEP, thread);
|
||||
setCurrentStep(jni_env, testStep);
|
||||
}
|
||||
@ -302,7 +300,7 @@ callbackSingleStep(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
|
||||
}
|
||||
|
||||
if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*) declaringClassName))) {
|
||||
NSK_COMPLAIN0("TEST FAILED: unable to deallocate memory pointed to method name\n\n");
|
||||
NSK_COMPLAIN0("TEST FAILED: unable to deallocate memory pointed to declaringClassName\n\n");
|
||||
}
|
||||
|
||||
}
|
||||
@ -324,24 +322,7 @@ callbackException(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
|
||||
jmethodID method, jlocation location, jobject exception,
|
||||
jmethodID catch_method, jlocation catch_location) {
|
||||
|
||||
const char *className;
|
||||
|
||||
className = getClassName(jvmti_env, jni_env, exception);
|
||||
|
||||
if (strcmp(EXPECTED_CLASS_SIGN, className) == 0) {
|
||||
jclass klass;
|
||||
|
||||
NSK_DISPLAY2("\n\n>>>> Exception %s in thread - %s\n",
|
||||
className, getThreadName(jni_env, thread));
|
||||
|
||||
testStep++;
|
||||
if (!NSK_JNI_VERIFY(jni_env, (klass = jni_env->GetObjectClass(exception)) != NULL)) {
|
||||
nsk_jvmti_setFailStatus();
|
||||
return;
|
||||
}
|
||||
|
||||
redefineClass(jvmti_env, klass);
|
||||
}
|
||||
handleException(false, jvmti_env, jni_env, thread, method, location, exception);
|
||||
}
|
||||
|
||||
/* ============================================================================= */
|
||||
@ -355,15 +336,27 @@ callbackExceptionCatch(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
|
||||
jmethodID method, jlocation location,
|
||||
jobject exception) {
|
||||
|
||||
const char *className;
|
||||
handleException(true, jvmti_env, jni_env, thread, method, location, exception);
|
||||
}
|
||||
|
||||
className = getClassName(jvmti_env, jni_env, exception);
|
||||
/* ============================================================================= */
|
||||
|
||||
if (strcmp(EXPECTED_CLASS_SIGN, className) == 0) {
|
||||
void handleException(bool isCatch,
|
||||
jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread,
|
||||
jmethodID method, jlocation location,
|
||||
jobject exception) {
|
||||
const char* className = getClassName(jvmti_env, jni_env, exception);
|
||||
|
||||
if (className != NULL && strcmp(EXPECTED_CLASS_SIGN, className) == 0) {
|
||||
jclass klass;
|
||||
|
||||
NSK_DISPLAY2("\n\n>>>> Caught exception %s in thread - %s\n",
|
||||
className, getThreadName(jni_env, thread));
|
||||
const char* threadName = getThreadName(jvmti_env, jni_env, thread);
|
||||
NSK_DISPLAY3(">>>> %s %s in thread - %s\n", isCatch ? "Caught exception" : "Exception",
|
||||
className, threadName != NULL ? threadName : "NULL");
|
||||
jvmti->Deallocate((unsigned char*)className);
|
||||
if (threadName != NULL) {
|
||||
jvmti->Deallocate((unsigned char*)threadName);
|
||||
}
|
||||
|
||||
testStep++;
|
||||
if (!NSK_JNI_VERIFY(jni_env, (klass = jni_env->GetObjectClass(exception)) != NULL)) {
|
||||
@ -373,11 +366,11 @@ callbackExceptionCatch(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
|
||||
|
||||
redefineClass(jvmti_env, klass);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ============================================================================= */
|
||||
|
||||
int readNewBytecode(jvmtiEnv* jvmti) {
|
||||
int readNewBytecode(jvmtiEnv* jvmti, jint *newClassSize, unsigned char* *newClassBytes) {
|
||||
|
||||
char filename[256];
|
||||
FILE *bytecode;
|
||||
@ -403,17 +396,19 @@ int readNewBytecode(jvmtiEnv* jvmti) {
|
||||
}
|
||||
|
||||
fseek(bytecode, 0, SEEK_END);
|
||||
newClassSize = ftell(bytecode);
|
||||
*newClassSize = ftell(bytecode);
|
||||
rewind(bytecode);
|
||||
|
||||
if (!NSK_JVMTI_VERIFY(jvmti->Allocate(newClassSize, &newClassBytes))) {
|
||||
if (!NSK_JVMTI_VERIFY(jvmti->Allocate(*newClassSize, newClassBytes))) {
|
||||
NSK_COMPLAIN0("buffer couldn't be allocated\n");
|
||||
return NSK_FALSE;
|
||||
}
|
||||
read_bytes = (jint) fread(newClassBytes, 1, newClassSize, bytecode);
|
||||
read_bytes = (jint) fread(*newClassBytes, 1, *newClassSize, bytecode);
|
||||
fclose(bytecode);
|
||||
if (read_bytes != newClassSize) {
|
||||
if (read_bytes != *newClassSize) {
|
||||
NSK_COMPLAIN0("TEST FAILED: error reading file\n");
|
||||
jvmti->Deallocate(*newClassBytes);
|
||||
*newClassBytes = NULL;
|
||||
return NSK_FALSE;
|
||||
}
|
||||
|
||||
@ -422,34 +417,41 @@ int readNewBytecode(jvmtiEnv* jvmti) {
|
||||
|
||||
/* ============================================================================= */
|
||||
|
||||
const char* getThreadName(JNIEnv* jni_env, jthread thread) {
|
||||
const char* getThreadName(jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread) {
|
||||
jmethodID methodID;
|
||||
jclass klass;
|
||||
jstring jthreadName;
|
||||
jsize jthreadNameLen;
|
||||
unsigned char *result = NULL;
|
||||
const char *threadName;
|
||||
|
||||
strcpy(chbuffer, "");
|
||||
|
||||
if (!NSK_JNI_VERIFY(jni_env, (klass = jni_env->GetObjectClass(thread)) != NULL)) {
|
||||
nsk_jvmti_setFailStatus();
|
||||
return chbuffer;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!NSK_JNI_VERIFY(jni_env, (methodID =
|
||||
jni_env->GetMethodID(klass, "getName", "()Ljava/lang/String;")) != NULL)) {
|
||||
nsk_jvmti_setFailStatus();
|
||||
return chbuffer;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jthreadName = (jstring) jni_env->CallObjectMethod(thread, methodID);
|
||||
|
||||
jthreadNameLen = jni_env->GetStringUTFLength(jthreadName);
|
||||
|
||||
if (!NSK_JVMTI_VERIFY(jvmti_env->Allocate(jthreadNameLen + 1, &result))) {
|
||||
NSK_COMPLAIN0("buffer couldn't be allocated\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
threadName = jni_env->GetStringUTFChars(jthreadName, 0);
|
||||
|
||||
strcpy(chbuffer, threadName);
|
||||
memcpy(result, threadName, jthreadNameLen + 1);
|
||||
|
||||
jni_env->ReleaseStringUTFChars(jthreadName, threadName);
|
||||
|
||||
return chbuffer;
|
||||
return (char*)result;
|
||||
}
|
||||
|
||||
/* ============================================================================= */
|
||||
@ -457,33 +459,19 @@ const char* getThreadName(JNIEnv* jni_env, jthread thread) {
|
||||
const char* getClassName(jvmtiEnv *jvmti_env, JNIEnv* jni_env, jobject object) {
|
||||
|
||||
char *className;
|
||||
char *generic;
|
||||
jclass klass;
|
||||
|
||||
strcpy(chbuffer, "");
|
||||
|
||||
if (!NSK_JNI_VERIFY(jni_env, (klass = jni_env->GetObjectClass(object)) != NULL)) {
|
||||
nsk_jvmti_setFailStatus();
|
||||
return chbuffer;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!NSK_JVMTI_VERIFY(jvmti_env->GetClassSignature(klass, &className, &generic))) {
|
||||
if (!NSK_JVMTI_VERIFY(jvmti_env->GetClassSignature(klass, &className, NULL))) {
|
||||
nsk_jvmti_setFailStatus();
|
||||
return chbuffer;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strcpy(chbuffer, className);
|
||||
|
||||
if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*)className))) {
|
||||
nsk_jvmti_setFailStatus();
|
||||
}
|
||||
|
||||
if (generic != NULL)
|
||||
if (!NSK_JVMTI_VERIFY(jvmti_env->Deallocate((unsigned char*)generic))) {
|
||||
nsk_jvmti_setFailStatus();
|
||||
}
|
||||
|
||||
return chbuffer;
|
||||
return className;
|
||||
}
|
||||
|
||||
/* ============================================================================= */
|
||||
@ -546,6 +534,10 @@ Java_nsk_jvmti_scenarios_hotswap_HS201_hs201t002_setThread(JNIEnv *env,
|
||||
if (!NSK_JNI_VERIFY(env, (testedThread = env->NewGlobalRef(thread)) != NULL))
|
||||
nsk_jvmti_setFailStatus();
|
||||
|
||||
enableEvent(jvmti, JVMTI_EVENT_CLASS_LOAD, testedThread);
|
||||
enableEvent(jvmti, JVMTI_EVENT_BREAKPOINT, testedThread);
|
||||
enableEvent(jvmti, JVMTI_EVENT_EXCEPTION, testedThread);
|
||||
enableEvent(jvmti, JVMTI_EVENT_EXCEPTION_CATCH, testedThread);
|
||||
}
|
||||
|
||||
/* ============================================================================= */
|
||||
@ -665,11 +657,6 @@ jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
|
||||
|
||||
NSK_DISPLAY0("Enable events\n");
|
||||
|
||||
enableEvent(jvmti, JVMTI_EVENT_CLASS_LOAD, testedThread);
|
||||
enableEvent(jvmti, JVMTI_EVENT_BREAKPOINT, testedThread);
|
||||
enableEvent(jvmti, JVMTI_EVENT_EXCEPTION, testedThread);
|
||||
enableEvent(jvmti, JVMTI_EVENT_EXCEPTION_CATCH, testedThread);
|
||||
|
||||
if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
|
||||
return JNI_ERR;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,6 +26,7 @@ package nsk.jvmti.scenarios.hotswap.HS201;
|
||||
public class hs201t002a extends Exception {
|
||||
|
||||
public hs201t002a () {
|
||||
System.out.println("Current step: " + hs201t002.currentStep); // Avoid calling classloader to find hs201t002 in doInit()
|
||||
doInit();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user