wip Array Factory

This commit is contained in:
Shautvast 2023-08-22 15:28:23 +02:00
parent bba00f1cbd
commit 58c2afcce0
6 changed files with 156 additions and 0 deletions

View file

@ -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>

View file

@ -0,0 +1,6 @@
package com.github.shautvast.reflective.array;
public abstract class ArrayCreator {
public abstract Object newInstance();
}

View file

@ -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);
}
}
}

View file

@ -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];
}
}

View file

@ -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());
} }

View file

@ -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;");
}
}