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>
|
<artifactId>asm-tree</artifactId>
|
||||||
<version>9.4</version>
|
<version>9.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openjdk.jol</groupId>
|
||||||
|
<artifactId>jol-core</artifactId>
|
||||||
|
<version>0.17</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<distributionManagement>
|
<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");
|
Dummy dummy = new Dummy("bar");
|
||||||
MetaMethod getName = Reflective.getMetaClass(dummy.getClass()).getMethod("getName").orElseGet(Assertions::fail);
|
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());
|
assertThrows(Panic.class, () -> getName.invoke("foo").unwrap());
|
||||||
|
// we should pass a valid dummy instance
|
||||||
assertEquals("bar", getName.invoke(dummy).unwrap());
|
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