completed the ArrayFactory
This commit is contained in:
parent
7ccf137898
commit
31f2b7c0f5
12 changed files with 198 additions and 164 deletions
|
|
@ -7,6 +7,8 @@ import com.github.shautvast.rusty.Result;
|
||||||
import org.objectweb.asm.ClassWriter;
|
import org.objectweb.asm.ClassWriter;
|
||||||
import org.objectweb.asm.tree.*;
|
import org.objectweb.asm.tree.*;
|
||||||
|
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
import static com.github.shautvast.reflective.java.Java.DOUBLE;
|
import static com.github.shautvast.reflective.java.Java.DOUBLE;
|
||||||
|
|
@ -58,7 +60,9 @@ public class InvokerFactory {
|
||||||
}
|
}
|
||||||
// put argument on the stack
|
// put argument on the stack
|
||||||
insns.add(new InsnNode(AALOAD));
|
insns.add(new InsnNode(AALOAD));
|
||||||
insns.add(new TypeInsnNode(CHECKCAST, Java.internalName(mapPrimitiveToWrapper(method.getParameters().get(i).getType()).getName())));
|
String type = internalName(mapPrimitiveToWrapper(method.getParameters().get(i).getType()).getName());
|
||||||
|
System.out.println("--" + type);
|
||||||
|
insns.add(new TypeInsnNode(CHECKCAST, type));
|
||||||
unwrapPrimitive(method.getParameters().get(i), insns);
|
unwrapPrimitive(method.getParameters().get(i), insns);
|
||||||
}
|
}
|
||||||
// call the method
|
// call the method
|
||||||
|
|
@ -76,11 +80,11 @@ public class InvokerFactory {
|
||||||
classNode.accept(classWriter);
|
classNode.accept(classWriter);
|
||||||
byte[] byteArray = classWriter.toByteArray();
|
byte[] byteArray = classWriter.toByteArray();
|
||||||
|
|
||||||
// try (FileOutputStream out = new FileOutputStream("C"+method.getName() + ".class")) {
|
try (FileOutputStream out = new FileOutputStream(method.getMetaClass().getName() + "_" + method.getName() + ".class")) {
|
||||||
// out.write(byteArray);
|
out.write(byteArray);
|
||||||
// } catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// e.printStackTrace();
|
e.printStackTrace();
|
||||||
// }
|
}
|
||||||
|
|
||||||
// load it into the JVM
|
// load it into the JVM
|
||||||
ByteClassLoader.INSTANCE.addClass(className, byteArray);
|
ByteClassLoader.INSTANCE.addClass(className, byteArray);
|
||||||
|
|
@ -160,6 +164,7 @@ public class InvokerFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Class<?> mapPrimitiveToWrapper(Class<?> type) {
|
private static Class<?> mapPrimitiveToWrapper(Class<?> type) {
|
||||||
|
System.out.println(type);
|
||||||
if (type == int.class) {
|
if (type == int.class) {
|
||||||
return Integer.class;
|
return Integer.class;
|
||||||
} else if (type == byte.class) {
|
} else if (type == byte.class) {
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ public class MetaClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
void addField(int access, String name, String descriptor) {
|
void addField(int access, String name, String descriptor) {
|
||||||
fields.put(name, new MetaField(name, access)); //ASM access same as reflect modifiers?
|
fields.put(name, new MetaField(name, access, Java.toClass(descriptor))); //ASM access same as reflect modifiers?
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMethod(int access, String name, String descriptor) {
|
public void addMethod(int access, String name, String descriptor) {
|
||||||
|
|
@ -62,4 +62,6 @@ public class MetaClass {
|
||||||
public String getRawName() {
|
public String getRawName() {
|
||||||
return rawName;
|
return rawName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,12 @@ public class MetaField {
|
||||||
private final String name;
|
private final String name;
|
||||||
private final int modifiers;
|
private final int modifiers;
|
||||||
|
|
||||||
public MetaField(String name, int modifiers) {
|
private final Class<?> type;
|
||||||
|
|
||||||
|
public MetaField(String name, int modifiers, Class<?> type) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.modifiers = modifiers;
|
this.modifiers = modifiers;
|
||||||
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
|
|
|
||||||
|
|
@ -78,13 +78,13 @@ public class MetaMethod {
|
||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
for (int i = 0; i < parms.length(); i++) {
|
for (int i = 0; i < parms.length(); i++) {
|
||||||
String t = Character.toString(parms.charAt(i));
|
String t = Character.toString(parms.charAt(i));
|
||||||
if (!"L".equals(t) && buf.length() == 0) {
|
if (!"[".equals(t) && !"L".equals(t) && buf.length() == 0) {
|
||||||
mutableParams.add(new Parameter<>(Java.getClassFromDescriptor(t), t));
|
mutableParams.add(new Parameter<>(Java.toClass(t), t));
|
||||||
}
|
}
|
||||||
if (";".equals(t)) {
|
if (";".equals(t)) {
|
||||||
buf.append(t);
|
buf.append(t);
|
||||||
String desc = buf.toString();
|
String desc = buf.toString();
|
||||||
mutableParams.add(new Parameter<>(Java.getClassFromDescriptor(desc), correct(desc)));
|
mutableParams.add(new Parameter<>(Java.toClass(desc), correct(desc)));
|
||||||
buf = new StringBuilder();
|
buf = new StringBuilder();
|
||||||
} else {
|
} else {
|
||||||
buf.append(t);
|
buf.append(t);
|
||||||
|
|
@ -93,7 +93,7 @@ public class MetaMethod {
|
||||||
|
|
||||||
String returnDesc = split[2];
|
String returnDesc = split[2];
|
||||||
this.returnParameter = new Parameter<>(
|
this.returnParameter = new Parameter<>(
|
||||||
Java.getClassFromDescriptor(returnDesc),
|
Java.toClass(returnDesc),
|
||||||
correct(returnDesc));
|
correct(returnDesc));
|
||||||
|
|
||||||
return Collections.unmodifiableList(mutableParams);
|
return Collections.unmodifiableList(mutableParams);
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@ public class Parameter<T> {
|
||||||
private final String descriptor;
|
private final String descriptor;
|
||||||
|
|
||||||
public Parameter(Class<T> type, String descriptor) {
|
public Parameter(Class<T> type, String descriptor) {
|
||||||
|
if (type ==null){
|
||||||
|
throw new IllegalArgumentException("Type cannot be null");
|
||||||
|
}
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.descriptor = descriptor;
|
this.descriptor = descriptor;
|
||||||
}
|
}
|
||||||
|
|
@ -17,10 +20,6 @@ public class Parameter<T> {
|
||||||
return type == Void.class;
|
return type == Void.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPrimitive(){
|
|
||||||
return !descriptor.startsWith("L");
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescriptor() {
|
public String getDescriptor() {
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,70 +6,90 @@ import com.github.shautvast.reflective.java.Java;
|
||||||
import org.objectweb.asm.ClassWriter;
|
import org.objectweb.asm.ClassWriter;
|
||||||
import org.objectweb.asm.tree.*;
|
import org.objectweb.asm.tree.*;
|
||||||
|
|
||||||
import java.io.FileOutputStream;
|
import java.util.Arrays;
|
||||||
import java.io.IOException;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
import static org.objectweb.asm.Opcodes.*;
|
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
|
||||||
|
import static org.objectweb.asm.Opcodes.ARETURN;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory class for dynamically creating arrays
|
||||||
|
*/
|
||||||
public class ArrayFactory {
|
public class ArrayFactory {
|
||||||
|
|
||||||
/*
|
private static final ConcurrentMap<String, ArrayCreator> cache = new ConcurrentHashMap<>();
|
||||||
should become
|
|
||||||
public static <T> T newArray(Class<T> componentType)
|
/**
|
||||||
or
|
* Creates a new array of the specified type and dimensions
|
||||||
public static <T> T newArray(Class<T> componentType, int... dimensions)
|
*
|
||||||
|
* @param elementType the array element type
|
||||||
|
* @param dimensions array of ints, ie {10} means 1 dimension, length 10. {10,20} means 2 dimensions, size 10 by 20
|
||||||
|
* @return an object that you can cast to the expected array type
|
||||||
*/
|
*/
|
||||||
public static Object newArray(Class<?> componentType, int... dimensions) {
|
public static Object newArray(Class<?> elementType, int... dimensions) {
|
||||||
return newArray(componentType.getName(), dimensions);
|
String elementTypeName = Java.internalName(elementType);
|
||||||
|
String syntheticClassName = syntheticClassName(elementTypeName, dimensions);
|
||||||
|
|
||||||
|
return cache.computeIfAbsent(syntheticClassName,
|
||||||
|
k -> createSyntheticArrayCreator(elementTypeName, syntheticClassName, dimensions)).newInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object newArray(String componentType, int... dimensions) {
|
private static String syntheticClassName(String elementTypeName, int[] dimensions) {
|
||||||
ClassNode classNode = ASM.createDefaultClassNode(
|
return "RAC" + elementTypeName
|
||||||
"ReflectiveCreator" + dimensions.length,
|
.replaceAll("[/.\\[;]", "")
|
||||||
|
.toLowerCase() + "L" + dimensions.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ArrayCreator createSyntheticArrayCreator(String componentType, String name, int... dimensions) {
|
||||||
|
ClassNode classNode = createASMClassNode(componentType, name, dimensions);
|
||||||
|
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||||
|
classNode.accept(classWriter);
|
||||||
|
|
||||||
|
byte[] byteArray = classWriter.toByteArray();
|
||||||
|
|
||||||
|
// try (FileOutputStream out = new FileOutputStream(name + ".class")) {
|
||||||
|
// out.write(byteArray);
|
||||||
|
// } catch (IOException e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
|
||||||
|
ByteClassLoader.INSTANCE.addClass(classNode.name, byteArray);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return (ArrayCreator) (ByteClassLoader.INSTANCE.loadClass(classNode.name).getConstructor().newInstance());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ClassNode createASMClassNode(String componentType, String name, int[] dimensions) {
|
||||||
|
ClassNode classNode = ASM.createDefaultClassNode(name,
|
||||||
Java.internalName(ArrayCreator.class));
|
Java.internalName(ArrayCreator.class));
|
||||||
MethodNode methodNode = new MethodNode(ACC_PUBLIC,
|
MethodNode methodNode = new MethodNode(ACC_PUBLIC,
|
||||||
"newInstance", "()Ljava/lang/Object;", null, null);
|
"newInstance", "()Ljava/lang/Object;", null, null);
|
||||||
classNode.methods.add(methodNode);
|
classNode.methods.add(methodNode);
|
||||||
InsnList insns = methodNode.instructions;
|
InsnList insns = methodNode.instructions;
|
||||||
|
Arrays.stream(dimensions).forEach(d -> insns.add(new LdcInsnNode(d)));
|
||||||
int localVarIndex = 0;
|
insns.add(new MultiANewArrayInsnNode(createArrayType(componentType, dimensions), dimensions.length));
|
||||||
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));
|
insns.add(new InsnNode(ARETURN));
|
||||||
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
return classNode;
|
||||||
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
|
private static String createArrayType(String componentType, int[] dimensions) {
|
||||||
ByteClassLoader.INSTANCE.addClass(classNode.name, byteArray);
|
StringBuilder s = new StringBuilder();
|
||||||
try {
|
s.append("[".repeat(dimensions.length));
|
||||||
return ((ArrayCreator) ByteClassLoader.INSTANCE.loadClass(classNode.name).getConstructor().newInstance()).newInstance();
|
boolean isObject = !componentType.startsWith("[") && componentType.contains("/");
|
||||||
} catch (Exception e) {
|
if (isObject) {
|
||||||
throw new RuntimeException(e);
|
s.append("L");
|
||||||
|
s.append(componentType);
|
||||||
|
} else {
|
||||||
|
s.append(Java.mapPrimitiveOrArrayName(componentType));
|
||||||
}
|
}
|
||||||
|
if (isObject) {
|
||||||
|
s.append(";");
|
||||||
}
|
}
|
||||||
|
return s.toString();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
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];
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -23,7 +23,7 @@ public class ByteClassLoader extends ClassLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addClass(String name, byte[] bytecode) {
|
public void addClass(String name, byte[] bytecode) {
|
||||||
Class<?> classDef = defineClass(name, bytecode, 0, bytecode.length);
|
Class<?> classDef = defineClass(null, bytecode, 0, bytecode.length);
|
||||||
classes.put(name, classDef);
|
classes.put(name, classDef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,6 @@ import org.objectweb.asm.ClassReader;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import static java.lang.reflect.Array.newInstance;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* common utils not for external use
|
* common utils not for external use
|
||||||
*/
|
*/
|
||||||
|
|
@ -107,48 +105,83 @@ public class Java {
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Class<?> getClassFromDescriptor(String descriptor) {
|
public static Class<?> toClass(String descriptor) {
|
||||||
int arrayDims = 0;
|
System.out.println("desc;" + descriptor);
|
||||||
while (descriptor.startsWith("[")) {
|
|
||||||
arrayDims++;
|
|
||||||
descriptor = descriptor.substring(1);
|
|
||||||
} //could be cheaper
|
|
||||||
|
|
||||||
if (descriptor.startsWith("L") && descriptor.endsWith(";")) {
|
|
||||||
try {
|
try {
|
||||||
String className = descriptor.substring(1, descriptor.length() - 1).replaceAll("/", ".");
|
if (descriptor.length() == 1) {
|
||||||
Class<?> clazz = Class.forName(className);
|
return mapIfPrimitive(descriptor.charAt(0));
|
||||||
if (arrayDims > 0) {
|
|
||||||
clazz = newInstance(clazz, new int[arrayDims]).getClass();
|
|
||||||
}
|
}
|
||||||
return clazz;
|
if (!descriptor.startsWith("[") && descriptor.endsWith(";")) {
|
||||||
|
descriptor = descriptor.substring(0, descriptor.length() - 1);
|
||||||
|
}
|
||||||
|
int i = 0;
|
||||||
|
while (descriptor.charAt(i) == '[' && i < 256) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
assert i < 256;
|
||||||
|
String dims = descriptor.substring(0, i);
|
||||||
|
String type = descriptor.substring(i);
|
||||||
|
if (i == 0 && type.startsWith("L")) {
|
||||||
|
type = type.substring(1);
|
||||||
|
}
|
||||||
|
type = Java.externalName(type);
|
||||||
|
Class<?> aClass = Class.forName(dims + type);
|
||||||
|
System.out.println(aClass);
|
||||||
|
return aClass;
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
throw new RuntimeException(e); // not supposed to happen
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
char typeChar = descriptor.charAt(0);
|
|
||||||
boolean isArray = arrayDims != 0;
|
private static Class<?> mapIfPrimitive(char descriptor) {
|
||||||
switch (typeChar) {
|
switch (descriptor) {
|
||||||
case 'B':
|
case 'B':
|
||||||
return isArray ? newInstance(byte.class, new int[arrayDims]).getClass() : byte.class;
|
return byte.class;
|
||||||
case 'C':
|
|
||||||
return isArray ? newInstance(char.class, new int[arrayDims]).getClass() : char.class;
|
|
||||||
case 'D':
|
|
||||||
return isArray ? newInstance(double.class, new int[arrayDims]).getClass() : double.class;
|
|
||||||
case 'F':
|
|
||||||
return isArray ? newInstance(float.class, new int[arrayDims]).getClass() : float.class;
|
|
||||||
case 'I':
|
|
||||||
return isArray ? newInstance(int.class, new int[arrayDims]).getClass() : int.class;
|
|
||||||
case 'J':
|
|
||||||
return isArray ? newInstance(long.class, new int[arrayDims]).getClass() : long.class;
|
|
||||||
case 'S':
|
case 'S':
|
||||||
return isArray ? newInstance(short.class, new int[arrayDims]).getClass() : short.class;
|
return short.class;
|
||||||
|
case 'I':
|
||||||
|
return int.class;
|
||||||
|
case 'J':
|
||||||
|
return long.class;
|
||||||
|
case 'F':
|
||||||
|
return float.class;
|
||||||
|
case 'D':
|
||||||
|
return double.class;
|
||||||
|
case 'C':
|
||||||
|
return char.class;
|
||||||
case 'Z':
|
case 'Z':
|
||||||
return isArray ? newInstance(boolean.class, new int[arrayDims]).getClass() : boolean.class;
|
return boolean.class;
|
||||||
case 'V':
|
case 'V':
|
||||||
return Void.class;
|
return Void.class;
|
||||||
default:
|
default:
|
||||||
throw new RuntimeException(new ClassNotFoundException("unknown descriptor: " + descriptor)); //must not happen
|
System.out.println("desc:" + descriptor);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String mapPrimitiveOrArrayName(String type) {
|
||||||
|
switch (type) {
|
||||||
|
case "byte":
|
||||||
|
return "B";
|
||||||
|
case "short":
|
||||||
|
return "S";
|
||||||
|
case "int":
|
||||||
|
return "I";
|
||||||
|
case "long":
|
||||||
|
return "J";
|
||||||
|
case "float":
|
||||||
|
return "F";
|
||||||
|
case "double":
|
||||||
|
return "D";
|
||||||
|
case "char":
|
||||||
|
return "C";
|
||||||
|
case "boolean":
|
||||||
|
return "Z";
|
||||||
|
default:
|
||||||
|
if (type.startsWith("[") || type.contains("/")) {
|
||||||
|
return type;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(type + "?");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ package com.github.shautvast.reflective;
|
||||||
public class DummyInvoker extends AbstractInvoker {
|
public class DummyInvoker extends AbstractInvoker {
|
||||||
|
|
||||||
public Object invoke(Object instance, Object... arguments) {
|
public Object invoke(Object instance, Object... arguments) {
|
||||||
((ReflectiveTest.Dummy) instance).setIntValue((int)arguments[0]);
|
((ReflectiveTest.Dummy) instance).setByteArrayValue((byte[][])arguments[0]);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ public class ReflectiveTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testMethods() {
|
void testMethods() {
|
||||||
Dummy dummy = new Dummy((byte) 42, (short) 43, 44, 45, 46.0F, 47.0, 'D', true, "don't panic!");
|
Dummy dummy = getDummy();
|
||||||
MetaClass metaDummy = Reflective.getMetaClass(dummy.getClass());
|
MetaClass metaDummy = Reflective.getMetaClass(dummy.getClass());
|
||||||
assertEquals("com.github.shautvast.reflective.ReflectiveTest$Dummy", metaDummy.getName());
|
assertEquals("com.github.shautvast.reflective.ReflectiveTest$Dummy", metaDummy.getName());
|
||||||
|
|
||||||
|
|
@ -49,7 +49,7 @@ public class ReflectiveTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testInvokeGetter() {
|
void testInvokeGetter() {
|
||||||
Dummy dummy = new Dummy((byte) 42, (short) 43, 44, 45, 46.0F, 47.0, 'D', true, "don't panic!");
|
Dummy dummy = getDummy();
|
||||||
MetaMethod getStringValue = Reflective.getMetaClass(dummy.getClass()).getMethod("getStringValue").orElseGet(Assertions::fail);
|
MetaMethod getStringValue = Reflective.getMetaClass(dummy.getClass()).getMethod("getStringValue").orElseGet(Assertions::fail);
|
||||||
|
|
||||||
// passing "foo" as the instance is not allowed
|
// passing "foo" as the instance is not allowed
|
||||||
|
|
@ -60,7 +60,7 @@ public class ReflectiveTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testInvokeSetters() {
|
void testInvokeSetters() {
|
||||||
Dummy dummy = new Dummy((byte) 42, (short) 43, 44, 45, 46.0F, 47.0, 'D', true, "don't panic!");
|
Dummy dummy = getDummy();
|
||||||
MetaClass metaForClass = Reflective.getMetaClass(dummy.getClass());
|
MetaClass metaForClass = Reflective.getMetaClass(dummy.getClass());
|
||||||
|
|
||||||
MetaMethod setByte = metaForClass.getMethod("setByteValue").orElseGet(Assertions::fail);
|
MetaMethod setByte = metaForClass.getMethod("setByteValue").orElseGet(Assertions::fail);
|
||||||
|
|
@ -102,7 +102,7 @@ public class ReflectiveTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testInvocationExceptionHappened() {
|
void testInvocationExceptionHappened() {
|
||||||
Dummy dummy = new Dummy((byte) 42, (short) 43, 44, 45, 46.0F, 47.0, 'D', true, "don't panic!");
|
Dummy dummy = getDummy();
|
||||||
MetaClass metaForClass = Reflective.getMetaClass(dummy.getClass());
|
MetaClass metaForClass = Reflective.getMetaClass(dummy.getClass());
|
||||||
MetaMethod throwEx = metaForClass.getMethod("throwEx").orElseGet(Assertions::fail);
|
MetaMethod throwEx = metaForClass.getMethod("throwEx").orElseGet(Assertions::fail);
|
||||||
|
|
||||||
|
|
@ -110,6 +110,13 @@ public class ReflectiveTest {
|
||||||
assertFalse(result.isOk());
|
assertFalse(result.isOk());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Dummy getDummy() {
|
||||||
|
return new Dummy((byte) 42, (short) 43,
|
||||||
|
44, 45, 46.0F, 47.0,
|
||||||
|
'D', true, "don't panic!",
|
||||||
|
new byte[1][1], new String[]{"Please don't touch that button"});
|
||||||
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
|
@ -123,6 +130,8 @@ public class ReflectiveTest {
|
||||||
private char charValue;
|
private char charValue;
|
||||||
private boolean booleanValue;
|
private boolean booleanValue;
|
||||||
private String stringValue;
|
private String stringValue;
|
||||||
|
private byte[][] byteArrayValue;
|
||||||
|
private String[] stringArrayValue;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
|
|
|
||||||
|
|
@ -2,50 +2,30 @@ package com.github.shautvast.reflective.array;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
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.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
public class ArraysTest {
|
public class ArraysTest {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void test1Dim() {
|
void test1Dim() {
|
||||||
Object o = ArrayFactory.newArray(String.class, 1);
|
Object o = ArrayFactory.newArray(String.class, 1);
|
||||||
// assertTrue(o instanceof String[]);
|
assertTrue(o instanceof String[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void test2Dims() {
|
void test2Dims() {
|
||||||
Object o = ArrayFactory.newArray(String.class, 1, 2);
|
int[][] ints = (int[][])ArrayFactory.newArray(int[].class, 1);
|
||||||
// assertTrue(o instanceof String[][]);
|
assertEquals(1, ints.length);
|
||||||
|
ints[0] = new int[1]; // will fail if array is not correctly created
|
||||||
|
assertEquals(1, ints[0].length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void test3Dims() {
|
void test3Dims() {
|
||||||
String[][][] array = (String[][][]) ArrayFactory.newArray(String[][][].class, 1, 2, 3);
|
String[][][] array = (String[][][]) ArrayFactory.newArray(String.class, 6, 7, 8);
|
||||||
assertEquals(1, array.length);
|
assertEquals(6, array.length);
|
||||||
array[0] = new String[2][1];
|
assertEquals(7, array[0].length);
|
||||||
array[0][1] = new String[1];
|
assertEquals(8, array[0][0].length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@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