wip Array Factory
This commit is contained in:
parent
bba00f1cbd
commit
58c2afcce0
6 changed files with 156 additions and 0 deletions
5
pom.xml
5
pom.xml
|
|
@ -24,6 +24,11 @@
|
|||
<artifactId>asm-tree</artifactId>
|
||||
<version>9.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjdk.jol</groupId>
|
||||
<artifactId>jol-core</artifactId>
|
||||
<version>0.17</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<distributionManagement>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
package com.github.shautvast.reflective.array;
|
||||
|
||||
public abstract class ArrayCreator {
|
||||
|
||||
public abstract Object newInstance();
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package com.github.shautvast.reflective.array;
|
||||
|
||||
import com.github.shautvast.reflective.java.ASM;
|
||||
import com.github.shautvast.reflective.java.ByteClassLoader;
|
||||
import com.github.shautvast.reflective.java.Java;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.tree.*;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class ArrayFactory {
|
||||
|
||||
/*
|
||||
should become
|
||||
public static <T> T newArray(Class<T> componentType)
|
||||
or
|
||||
public static <T> T newArray(Class<T> componentType, int... dimensions)
|
||||
*/
|
||||
public static Object newArray(Class<?> componentType, int... dimensions) {
|
||||
return newArray(componentType.getName(), dimensions);
|
||||
}
|
||||
|
||||
public static Object newArray(String componentType, int... dimensions) {
|
||||
ClassNode classNode = ASM.createDefaultClassNode(
|
||||
"ReflectiveCreator" + dimensions.length,
|
||||
Java.internalName(ArrayCreator.class));
|
||||
MethodNode methodNode = new MethodNode(ACC_PUBLIC,
|
||||
"newInstance", "()Ljava/lang/Object;", null, null);
|
||||
classNode.methods.add(methodNode);
|
||||
InsnList insns = methodNode.instructions;
|
||||
|
||||
int localVarIndex = 0;
|
||||
StringBuilder arrayType = new StringBuilder(dimensions.length);
|
||||
String post = "";
|
||||
String pre = "";
|
||||
insns.add(new LdcInsnNode(1));
|
||||
insns.add(new LdcInsnNode(1));
|
||||
insns.add(new LdcInsnNode(1));
|
||||
insns.add(new MultiANewArrayInsnNode("[[[Ljava/lang/String;",3));
|
||||
|
||||
// for (int dim : dimensions) {
|
||||
// insns.add(new LdcInsnNode(dim));
|
||||
// String type = arrayType + pre + Java.internalName(componentType) + post;
|
||||
// insns.add(new TypeInsnNode(ANEWARRAY, type));
|
||||
// insns.add(new VarInsnNode(ASTORE, ++localVarIndex));
|
||||
// arrayType.append("[");
|
||||
// pre = "L";
|
||||
// post = ";";
|
||||
//
|
||||
// }
|
||||
|
||||
// insns.add(new VarInsnNode(ALOAD, localVarIndex));
|
||||
insns.add(new InsnNode(ARETURN));
|
||||
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
classNode.accept(classWriter);
|
||||
byte[] byteArray = classWriter.toByteArray();
|
||||
|
||||
try (FileOutputStream out = new FileOutputStream("A.class")) {
|
||||
out.write(byteArray);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// load it into the JVM
|
||||
ByteClassLoader.INSTANCE.addClass(classNode.name, byteArray);
|
||||
try {
|
||||
return ((ArrayCreator) ByteClassLoader.INSTANCE.loadClass(classNode.name).getConstructor().newInstance()).newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.github.shautvast.reflective.array;
|
||||
|
||||
public class Arrays {
|
||||
private Arrays() {
|
||||
}
|
||||
|
||||
public static Object newInstance(Class<?> componentType, int... dimensions)
|
||||
throws IllegalArgumentException, NegativeArraySizeException {
|
||||
return new String[dimensions[1]][2][3];
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String[][][] a = (String[][][])newInstance(String.class, 1, 2, 3);
|
||||
a[0]=new String[1][2];
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -54,7 +54,9 @@ public class ReflectiveTest {
|
|||
Dummy dummy = new Dummy("bar");
|
||||
MetaMethod getName = Reflective.getMetaClass(dummy.getClass()).getMethod("getName").orElseGet(Assertions::fail);
|
||||
|
||||
// passing "foo" as the instance is not allowed
|
||||
assertThrows(Panic.class, () -> getName.invoke("foo").unwrap());
|
||||
// we should pass a valid dummy instance
|
||||
assertEquals("bar", getName.invoke(dummy).unwrap());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
package com.github.shautvast.reflective.array;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class ArraysTest {
|
||||
|
||||
|
||||
@Test
|
||||
void test1Dim() {
|
||||
Object o = ArrayFactory.newArray(String.class, 1);
|
||||
assertTrue(o instanceof String[]);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test2Dims() {
|
||||
Object o = ArrayFactory.newArray(String.class, 1, 2);
|
||||
assertTrue(o instanceof String[][]);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test3Dims() {
|
||||
String[][][] array = (String[][][]) ArrayFactory.newArray(String[][][].class, 1, 2, 3);
|
||||
assertEquals(1, array.length);
|
||||
array[0] = new String[2][1];
|
||||
array[0][1] = new String[1];
|
||||
}
|
||||
|
||||
@Test
|
||||
void test3DimsT() {
|
||||
String[][][] array = new String[1][1][1];
|
||||
assertEquals(1, array.length);
|
||||
array[0] = new String[2][1];
|
||||
|
||||
array[0][0] = new String[1];
|
||||
array[0][1] = new String[1];
|
||||
array[0][0][0]="0,0,0";
|
||||
array[0][1][0]="0,1,0"; // WTF?
|
||||
System.out.println(array[0][1][0]);
|
||||
}
|
||||
|
||||
@Test
|
||||
void forName() throws ClassNotFoundException {
|
||||
Class.forName("[Ljava.lang.String;");
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue