[BAEL-5077] Hidden Classes (#11663)
This commit is contained in:
parent
53780ceaf2
commit
fa2b75a81c
|
@ -21,6 +21,11 @@
|
||||||
<artifactId>commons-lang3</artifactId>
|
<artifactId>commons-lang3</artifactId>
|
||||||
<version>${commons-lang3.version}</version>
|
<version>${commons-lang3.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
<version>${commons-io.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.baeldung.hidden.classes;
|
||||||
|
|
||||||
|
public class HiddenClass {
|
||||||
|
public String convertToUpperCase(String s) {
|
||||||
|
return s.toUpperCase();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package com.baeldung.hidden.classes;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodHandles.Lookup.ClassOption;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class HiddenClassUnitTest {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(HiddenClassUnitTest.class);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void whenInvokeMethodOnHiddenClass_thenSuccess() {
|
||||||
|
// Initiate lookup class
|
||||||
|
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||||
|
|
||||||
|
// Create a byte code of a class
|
||||||
|
|
||||||
|
Class<?> clazz = HiddenClass.class;
|
||||||
|
String className = clazz.getName();
|
||||||
|
String classAsPath = className.replace('.', '/') + ".class";
|
||||||
|
InputStream stream = clazz.getClassLoader()
|
||||||
|
.getResourceAsStream(classAsPath);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Define hidden class with byte code
|
||||||
|
Class<?> hiddenClass = lookup.defineHiddenClass(IOUtils.toByteArray(stream), true, ClassOption.NESTMATE)
|
||||||
|
.lookupClass();
|
||||||
|
Object hiddenClassObject = hiddenClass.getConstructor()
|
||||||
|
.newInstance();
|
||||||
|
|
||||||
|
Method method = hiddenClassObject.getClass()
|
||||||
|
.getDeclaredMethod("convertToUpperCase", String.class);
|
||||||
|
|
||||||
|
Assertions.assertEquals(true, hiddenClass.isHidden());
|
||||||
|
|
||||||
|
Assertions.assertEquals("HELLO", method.invoke(hiddenClassObject, "Hello"));
|
||||||
|
|
||||||
|
Assertions.assertEquals(this.getClass()
|
||||||
|
.getClassLoader(), hiddenClass.getClassLoader());
|
||||||
|
|
||||||
|
Assertions.assertEquals(null, hiddenClass.getCanonicalName());
|
||||||
|
|
||||||
|
Assertions.assertThrows(ClassNotFoundException.class, () -> Class.forName(hiddenClass.getName()));
|
||||||
|
|
||||||
|
Assertions.assertThrows(ClassNotFoundException.class, () -> lookup.findClass(hiddenClass.getName()));
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("Couldn't instantiate hidden class" + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue