added the getters
This commit is contained in:
parent
021304a5d8
commit
fbfd8d5e93
20 changed files with 440 additions and 176 deletions
|
|
@ -2,11 +2,17 @@ package com.github.shautvast.reflective.array;
|
||||||
|
|
||||||
import com.github.shautvast.reflective.array.base.*;
|
import com.github.shautvast.reflective.array.base.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public interface for dynamically working with arrays (create, set and get operations)
|
* Public interface for dynamically working with arrays (create, set and get operations)
|
||||||
|
* <p>
|
||||||
|
* Drop in replacement for java.lang.reflect.Array
|
||||||
*/
|
*/
|
||||||
public class ArrayFactory {
|
public final class ArrayFactory {
|
||||||
|
|
||||||
|
private ArrayFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new array of the specified type and dimensions
|
* Creates a new array of the specified type and dimensions
|
||||||
|
|
@ -27,7 +33,18 @@ public class ArrayFactory {
|
||||||
* @param value the value to set
|
* @param value the value to set
|
||||||
*/
|
*/
|
||||||
public static void set(Object array, int index, Object value) {
|
public static void set(Object array, int index, Object value) {
|
||||||
ArrayHandlerFactory.getSetterInstance(ObjectArraySetter.class, typeChecked(array)).set(array, index, value);
|
ArrayHandlerFactory.getAccessorInstance(ObjectArrayAccessor.class, typeChecked(array)).set(array, index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a Object value from an array
|
||||||
|
*
|
||||||
|
* @param array the array to access
|
||||||
|
* @param index
|
||||||
|
* @return the value of the array at the index
|
||||||
|
*/
|
||||||
|
public static Object get(Object array, int index) {
|
||||||
|
return ArrayHandlerFactory.getAccessorInstance(ObjectArrayAccessor.class, typeChecked(array)).get(array, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -37,8 +54,19 @@ public class ArrayFactory {
|
||||||
* @param index the array index
|
* @param index the array index
|
||||||
* @param value the value to set
|
* @param value the value to set
|
||||||
*/
|
*/
|
||||||
public static void set(Object array, int index, int value) {
|
public static void setInt(Object array, int index, int value) {
|
||||||
ArrayHandlerFactory.getSetterInstance(IntArraySetter.class, typeChecked(array)).set(array, index, value);
|
ArrayHandlerFactory.getAccessorInstance(IntArrayAccessor.class, typeChecked(array)).set(array, index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an int value from an array
|
||||||
|
*
|
||||||
|
* @param array the array to access
|
||||||
|
* @param index
|
||||||
|
* @return the value of the array at the index
|
||||||
|
*/
|
||||||
|
public static int getInt(Object array, int index) {
|
||||||
|
return ArrayHandlerFactory.getAccessorInstance(IntArrayAccessor.class, typeChecked(array)).get(array, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -48,8 +76,19 @@ public class ArrayFactory {
|
||||||
* @param index the array index
|
* @param index the array index
|
||||||
* @param value the value to set
|
* @param value the value to set
|
||||||
*/
|
*/
|
||||||
public static void set(Object array, int index, byte value) {
|
public static void setByte(Object array, int index, byte value) {
|
||||||
ArrayHandlerFactory.getSetterInstance(ByteArraySetter.class, typeChecked(array)).set(array, index, value);
|
ArrayHandlerFactory.getAccessorInstance(ByteArrayAccessor.class, typeChecked(array)).set(array, index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a byte value from an array
|
||||||
|
*
|
||||||
|
* @param array the array to access
|
||||||
|
* @param index
|
||||||
|
* @return the value of the array at the index
|
||||||
|
*/
|
||||||
|
public static byte getByte(Object array, int index) {
|
||||||
|
return ArrayHandlerFactory.getAccessorInstance(ByteArrayAccessor.class, typeChecked(array)).get(array, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -59,8 +98,19 @@ public class ArrayFactory {
|
||||||
* @param index the array index
|
* @param index the array index
|
||||||
* @param value the value to set
|
* @param value the value to set
|
||||||
*/
|
*/
|
||||||
public static void set(Object array, int index, short value) {
|
public static void setShort(Object array, int index, short value) {
|
||||||
ArrayHandlerFactory.getSetterInstance(ShortArraySetter.class, typeChecked(array)).set(array, index, value);
|
ArrayHandlerFactory.getAccessorInstance(ShortArrayAccessor.class, typeChecked(array)).set(array, index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a short value from an array
|
||||||
|
*
|
||||||
|
* @param array the array to access
|
||||||
|
* @param index
|
||||||
|
* @return the value of the array at the index
|
||||||
|
*/
|
||||||
|
public static short getShort(Object array, int index) {
|
||||||
|
return ArrayHandlerFactory.getAccessorInstance(ShortArrayAccessor.class, typeChecked(array)).get(array, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -70,8 +120,19 @@ public class ArrayFactory {
|
||||||
* @param index the array index
|
* @param index the array index
|
||||||
* @param value the value to set
|
* @param value the value to set
|
||||||
*/
|
*/
|
||||||
public static void set(Object array, int index, long value) {
|
public static void setLong(Object array, int index, long value) {
|
||||||
ArrayHandlerFactory.getSetterInstance(LongArraySetter.class, typeChecked(array)).set(array, index, value);
|
ArrayHandlerFactory.getAccessorInstance(LongArrayAccessor.class, typeChecked(array)).set(array, index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a long value from an array
|
||||||
|
*
|
||||||
|
* @param array the array to access
|
||||||
|
* @param index
|
||||||
|
* @return the value of the array at the index
|
||||||
|
*/
|
||||||
|
public static long getLong(Object array, int index) {
|
||||||
|
return ArrayHandlerFactory.getAccessorInstance(LongArrayAccessor.class, typeChecked(array)).get(array, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -81,8 +142,19 @@ public class ArrayFactory {
|
||||||
* @param index the array index
|
* @param index the array index
|
||||||
* @param value the value to set
|
* @param value the value to set
|
||||||
*/
|
*/
|
||||||
public static void set(Object array, int index, float value) {
|
public static void setFloat(Object array, int index, float value) {
|
||||||
ArrayHandlerFactory.getSetterInstance(FloatArraySetter.class, typeChecked(array)).set(array, index, value);
|
ArrayHandlerFactory.getAccessorInstance(FloatArrayAccessor.class, typeChecked(array)).set(array, index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a float value from an array
|
||||||
|
*
|
||||||
|
* @param array the array to access
|
||||||
|
* @param index
|
||||||
|
* @return the value of the array at the index
|
||||||
|
*/
|
||||||
|
public static float getFloat(Object array, int index) {
|
||||||
|
return ArrayHandlerFactory.getAccessorInstance(FloatArrayAccessor.class, typeChecked(array)).get(array, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -92,26 +164,77 @@ public class ArrayFactory {
|
||||||
* @param index the array index
|
* @param index the array index
|
||||||
* @param value the value to set
|
* @param value the value to set
|
||||||
*/
|
*/
|
||||||
public static void set(Object array, int index, double value) {
|
public static void setDouble(Object array, int index, double value) {
|
||||||
ArrayHandlerFactory.getSetterInstance(DoubleArraySetter.class, typeChecked(array)).set(array, index, value);
|
ArrayHandlerFactory.getAccessorInstance(DoubleArrayAccessor.class, typeChecked(array)).set(array, index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void set(Object array, int index, char value) {
|
/**
|
||||||
ArrayHandlerFactory.getSetterInstance(CharArraySetter.class, typeChecked(array)).set(array, index, value);
|
* Gets a double value from an array
|
||||||
|
*
|
||||||
|
* @param array the array to access
|
||||||
|
* @param index
|
||||||
|
* @return the value of the array at the index
|
||||||
|
*/
|
||||||
|
public static double getDouble(Object array, int index) {
|
||||||
|
return ArrayHandlerFactory.getAccessorInstance(DoubleArrayAccessor.class, typeChecked(array)).get(array, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void set(Object array, int index, boolean value) {
|
/**
|
||||||
ArrayHandlerFactory.getSetterInstance(BooleanArraySetter.class, typeChecked(array)).set(array, index, value);
|
* Sets a char value on an array
|
||||||
|
*
|
||||||
|
* @param array the array on which the value is set
|
||||||
|
* @param index the array index
|
||||||
|
* @param value the value to set
|
||||||
|
*/
|
||||||
|
public static void setChar(Object array, int index, char value) {
|
||||||
|
ArrayHandlerFactory.getAccessorInstance(CharArrayAccessor.class, typeChecked(array)).set(array, index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a char value from an array
|
||||||
|
*
|
||||||
|
* @param array the array to access
|
||||||
|
* @param index
|
||||||
|
* @return the value of the array at the index
|
||||||
|
*/
|
||||||
|
public static char getChar(Object array, int index) {
|
||||||
|
return ArrayHandlerFactory.getAccessorInstance(CharArrayAccessor.class, typeChecked(array)).get(array, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a boolean value on an array
|
||||||
|
*
|
||||||
|
* @param array the array on which the value is set
|
||||||
|
* @param index the array index
|
||||||
|
* @param value the value to set
|
||||||
|
*/
|
||||||
|
public static void setBoolean(Object array, int index, boolean value) {
|
||||||
|
ArrayHandlerFactory.getAccessorInstance(BooleanArrayAccessor.class, typeChecked(array)).set(array, index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a boolean value from an array
|
||||||
|
*
|
||||||
|
* @param array the array to access
|
||||||
|
* @param index
|
||||||
|
* @return the value of the array at the index
|
||||||
|
*/
|
||||||
|
public static boolean getBoolean(Object array, int index) {
|
||||||
|
return ArrayHandlerFactory.getAccessorInstance(BooleanArrayAccessor.class, typeChecked(array)).get(array, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only checks if object is an array, not the type of that array. TODO
|
* Only checks if object is an array, not the type of that array. TODO
|
||||||
*/
|
*/
|
||||||
private static Class<?> typeChecked(Object array) {
|
private static Class<?> typeChecked(Object array) {
|
||||||
|
if (array == null) {
|
||||||
|
throw new NullPointerException("Argument is null");
|
||||||
|
}
|
||||||
Class<?> arrayType = array.getClass();
|
Class<?> arrayType = array.getClass();
|
||||||
if (!arrayType.isArray()) {
|
if (!arrayType.isArray()) {
|
||||||
throw new IllegalArgumentException("This is not an array");
|
throw new IllegalArgumentException("Argument is not an array");
|
||||||
}
|
}
|
||||||
return arrayType;
|
return arrayType;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package com.github.shautvast.reflective.array;
|
package com.github.shautvast.reflective.array;
|
||||||
|
|
||||||
import com.github.shautvast.reflective.array.base.ArrayCreator;
|
import com.github.shautvast.reflective.array.base.ArrayCreator;
|
||||||
import com.github.shautvast.reflective.array.base.ArraySetter;
|
import com.github.shautvast.reflective.array.base.ArrayAccessor;
|
||||||
import com.github.shautvast.reflective.array.base.ObjectArraySetter;
|
import com.github.shautvast.reflective.array.base.ObjectArrayAccessor;
|
||||||
import com.github.shautvast.reflective.java.ASM;
|
import com.github.shautvast.reflective.java.ASM;
|
||||||
import com.github.shautvast.reflective.java.ByteClassLoader;
|
import com.github.shautvast.reflective.java.ByteClassLoader;
|
||||||
import com.github.shautvast.reflective.java.Java;
|
import com.github.shautvast.reflective.java.Java;
|
||||||
|
|
@ -21,45 +21,38 @@ class ArrayHandlerFactory {
|
||||||
/* cache for the compiled creator classes */
|
/* cache for the compiled creator classes */
|
||||||
private static final Map<String, ArrayCreator> creatorCache = new ConcurrentHashMap<>();
|
private static final Map<String, ArrayCreator> creatorCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
/* Cache for the compiled setter classes.
|
/* Cache for the compiled accessor classes.
|
||||||
* The outer Map contains the ArraySetter type (some primitive or Object Setter)
|
* The outer Map contains the ArrayAccessor type (some primitive or Object Accessor)
|
||||||
* That maps to the concrete calculated ArraySetter instance name which maps to the instance itself.
|
* That maps to the concrete calculated ArrayAccessor instance name which maps to the instance itself.
|
||||||
* TODO see if this can be optimized
|
* TODO see if this can be optimized
|
||||||
*/
|
*/
|
||||||
private static final Map<Class<? extends ArraySetter>, Map<String, Object>> setterCache = new ConcurrentHashMap<>();
|
private static final Map<Class<? extends ArrayAccessor>, Map<String, Object>> accessorCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* generic method for creating array setters (primitives and objects)
|
* generic method for creating array accessors (primitives and objects)
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
static <T extends ArraySetter> T getSetterInstance(Class<T> setterBaseType, Class<?> arrayType) {
|
static <T extends ArrayAccessor> T getAccessorInstance(Class<T> accessorBaseType, Class<?> arrayType) {
|
||||||
String arrayTypeName = Java.internalName(arrayType);
|
String arrayTypeName = Java.internalName(arrayType);
|
||||||
String syntheticClassName = "com/shautvast/reflective/array/ArraySetter_"
|
String syntheticClassName = "com/shautvast/reflective/array/ArrayAccessor_"
|
||||||
+ javaName(arrayTypeName) + Java.getNumDimensions(arrayType);
|
+ Java.javaName(arrayTypeName) + Java.getNumDimensions(arrayType);
|
||||||
|
|
||||||
return (T) setterCache.computeIfAbsent(setterBaseType, k -> new ConcurrentHashMap<>()).
|
return (T) accessorCache.computeIfAbsent(accessorBaseType, k -> new ConcurrentHashMap<>()).
|
||||||
computeIfAbsent(syntheticClassName,
|
computeIfAbsent(syntheticClassName,
|
||||||
k -> ArrayHandlerFactory.createSyntheticArraySetter(setterBaseType, arrayTypeName, syntheticClassName));
|
k -> ArrayHandlerFactory.createSyntheticArrayAccessor(accessorBaseType, arrayTypeName, syntheticClassName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* creates an instance of an ArrayCreator of the specified type */
|
/* creates an instance of an ArrayCreator of the specified type */
|
||||||
static ArrayCreator getCreatorInstance(Class<?> elementType, int... dimensions) {
|
static ArrayCreator getCreatorInstance(Class<?> elementType, int... dimensions) {
|
||||||
String elementTypeName = Java.internalName(elementType);
|
String elementTypeName = Java.internalName(elementType);
|
||||||
String syntheticClassName = "com/shautvast/reflective/array/ArrayCreator_"
|
String syntheticClassName = "com/shautvast/reflective/array/ArrayCreator_"
|
||||||
+ javaName(elementTypeName) + dimensions.length;
|
+ Java.javaName(elementTypeName) + dimensions.length;
|
||||||
|
|
||||||
return creatorCache.computeIfAbsent(syntheticClassName,
|
return creatorCache.computeIfAbsent(syntheticClassName,
|
||||||
k -> ArrayHandlerFactory.createSyntheticArrayCreator(elementTypeName, syntheticClassName, dimensions));
|
k -> ArrayHandlerFactory.createSyntheticArrayCreator(elementTypeName, syntheticClassName, dimensions));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* strips all disallowed characters from a classname */
|
|
||||||
private static String javaName(String arrayTypeName) {
|
|
||||||
return arrayTypeName
|
|
||||||
.replaceAll("[/.\\[;]", "")
|
|
||||||
.toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Creates the ASM ClassNode for an ArrayCreator */
|
/* Creates the ASM ClassNode for an ArrayCreator */
|
||||||
static ArrayCreator createSyntheticArrayCreator(String elementType, String name, int... dimensions) {
|
static ArrayCreator createSyntheticArrayCreator(String elementType, String name, int... dimensions) {
|
||||||
ClassNode classNode = ASM.createDefaultClassNode(name, Java.internalName(ArrayCreator.class));
|
ClassNode classNode = ASM.createDefaultClassNode(name, Java.internalName(ArrayCreator.class));
|
||||||
|
|
@ -84,10 +77,11 @@ class ArrayHandlerFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Creates the ASM ClassNode for an ArraySetter */
|
/* Creates the ASM ClassNode for an ArrayAccessor */
|
||||||
static <T> T createSyntheticArraySetter(Class<T> setterType, String arrayType, String name) {
|
static <T> T createSyntheticArrayAccessor(Class<T> accessorType, String arrayType, String name) {
|
||||||
ClassNode classNode = ASM.createDefaultClassNode(name, Java.internalName(setterType));
|
ClassNode classNode = ASM.createDefaultClassNode(name, Java.internalName(accessorType));
|
||||||
classNode.methods.add(createSetMethodNode(setterType, arrayType));
|
classNode.methods.add(createSetMethodNode(accessorType, arrayType));
|
||||||
|
classNode.methods.add(createGetMethodNode(accessorType, arrayType));
|
||||||
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||||
classNode.accept(classWriter);
|
classNode.accept(classWriter);
|
||||||
|
|
||||||
|
|
@ -102,7 +96,7 @@ class ArrayHandlerFactory {
|
||||||
ByteClassLoader.INSTANCE.addClass(classNode.name, byteArray);
|
ByteClassLoader.INSTANCE.addClass(classNode.name, byteArray);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return setterType.cast(ByteClassLoader.INSTANCE.loadClass(classNode.name).getConstructor().newInstance());
|
return accessorType.cast(ByteClassLoader.INSTANCE.loadClass(classNode.name).getConstructor().newInstance());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
@ -119,17 +113,17 @@ class ArrayHandlerFactory {
|
||||||
return methodNode;
|
return methodNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Creates the set method for ArraySetter classes */
|
/* Creates the set method for ArrayAccessor classes */
|
||||||
private static MethodNode createSetMethodNode(Class<?> setterType, String arrayType) {
|
private static MethodNode createSetMethodNode(Class<?> accessorType, String arrayType) {
|
||||||
String elementType;
|
String elementType;
|
||||||
if (setterType == ObjectArraySetter.class) {
|
if (accessorType == ObjectArrayAccessor.class) {
|
||||||
elementType = "Ljava/lang/Object;";
|
elementType = "Ljava/lang/Object;";
|
||||||
} else {
|
} else {
|
||||||
elementType = arrayType.substring(1);
|
elementType = arrayType.substring(1);
|
||||||
}
|
}
|
||||||
MethodNode methodNode = new MethodNode(ACC_PUBLIC,
|
MethodNode methodNode = new MethodNode(ACC_PUBLIC,
|
||||||
"set", "(Ljava/lang/Object;I" + elementType + ")V", null, null);
|
"set", "(Ljava/lang/Object;I" + elementType + ")V", null, null);
|
||||||
int[] opcodes = getInstructions(elementType);
|
int[] opcodes = arrayStoreInstructions(elementType);
|
||||||
InsnList insns = methodNode.instructions;
|
InsnList insns = methodNode.instructions;
|
||||||
insns.add(new VarInsnNode(ALOAD, 1));
|
insns.add(new VarInsnNode(ALOAD, 1));
|
||||||
insns.add(new TypeInsnNode(CHECKCAST, arrayType));
|
insns.add(new TypeInsnNode(CHECKCAST, arrayType));
|
||||||
|
|
@ -141,14 +135,34 @@ class ArrayHandlerFactory {
|
||||||
return methodNode;
|
return methodNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static MethodNode createGetMethodNode(Class<?> accessorType, String arrayType) {
|
||||||
|
String elementType;
|
||||||
|
if (accessorType == ObjectArrayAccessor.class) {
|
||||||
|
elementType = "Ljava/lang/Object;";
|
||||||
|
} else {
|
||||||
|
elementType = arrayType.substring(1);
|
||||||
|
}
|
||||||
|
MethodNode methodNode = new MethodNode(ACC_PUBLIC,
|
||||||
|
"get", "(Ljava/lang/Object;I)" + elementType, null, null);
|
||||||
|
InsnList insns = methodNode.instructions;
|
||||||
|
int[] opcodes = arrayLoadAndReturnInstructions(elementType);
|
||||||
|
insns.add(new VarInsnNode(ALOAD, 1));
|
||||||
|
insns.add(new TypeInsnNode(CHECKCAST, arrayType));
|
||||||
|
insns.add(new VarInsnNode(ILOAD, 2));
|
||||||
|
insns.add(new InsnNode(opcodes[0]));
|
||||||
|
insns.add(new InsnNode(opcodes[1]));
|
||||||
|
|
||||||
|
return methodNode;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* gets the pair of appropriate load (type) and store (array of type) instructions
|
* gets the pair of appropriate load (type) and store (array of type) instructions
|
||||||
*/
|
*/
|
||||||
private static int[] getInstructions(String type) {
|
private static int[] arrayStoreInstructions(String type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "B":
|
case "B":
|
||||||
case "Z":
|
case "Z":
|
||||||
return new int[]{ILOAD, BASTORE}; // load int, store byte??
|
return new int[]{ILOAD, BASTORE};
|
||||||
case "S":
|
case "S":
|
||||||
return new int[]{ILOAD, SASTORE};
|
return new int[]{ILOAD, SASTORE};
|
||||||
case "I":
|
case "I":
|
||||||
|
|
@ -165,4 +179,29 @@ class ArrayHandlerFactory {
|
||||||
return new int[]{ALOAD, AASTORE};
|
return new int[]{ALOAD, AASTORE};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gets the pair of appropriate load (type) and store (array of type) instructions
|
||||||
|
*/
|
||||||
|
private static int[] arrayLoadAndReturnInstructions(String type) {
|
||||||
|
switch (type) {
|
||||||
|
case "B":
|
||||||
|
case "Z":
|
||||||
|
return new int[]{BALOAD, IRETURN};
|
||||||
|
case "I":
|
||||||
|
return new int[]{IALOAD, IRETURN};
|
||||||
|
case "S":
|
||||||
|
return new int[]{SALOAD, IRETURN};
|
||||||
|
case "C":
|
||||||
|
return new int[]{CALOAD, IRETURN};
|
||||||
|
case "J":
|
||||||
|
return new int[]{LALOAD, LRETURN};
|
||||||
|
case "F":
|
||||||
|
return new int[]{FALOAD, FRETURN};
|
||||||
|
case "D":
|
||||||
|
return new int[]{DALOAD, DRETURN};
|
||||||
|
default:
|
||||||
|
return new int[]{AALOAD, ARETURN};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,5 @@ package com.github.shautvast.reflective.array.base;
|
||||||
/**
|
/**
|
||||||
* Empty interface because you can't be generic over primitives in Java
|
* Empty interface because you can't be generic over primitives in Java
|
||||||
*/
|
*/
|
||||||
public interface ArraySetter {
|
public interface ArrayAccessor {
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.github.shautvast.reflective.array.base;
|
||||||
|
|
||||||
|
public abstract class BooleanArrayAccessor implements ArrayAccessor {
|
||||||
|
public abstract void set(Object array, int index, boolean value);
|
||||||
|
public abstract boolean get(Object array, int index);
|
||||||
|
}
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
package com.github.shautvast.reflective.array.base;
|
|
||||||
|
|
||||||
public abstract class BooleanArraySetter implements ArraySetter {
|
|
||||||
public abstract void set(Object array, int index, boolean value);
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package com.github.shautvast.reflective.array.base;
|
package com.github.shautvast.reflective.array.base;
|
||||||
|
|
||||||
public abstract class ByteArraySetter implements ArraySetter {
|
public abstract class ByteArrayAccessor implements ArrayAccessor {
|
||||||
|
|
||||||
public abstract void set(Object array, int index, byte value);
|
public abstract void set(Object array, int index, byte value);
|
||||||
|
|
||||||
|
public abstract byte get(Object array, int index);
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.github.shautvast.reflective.array.base;
|
package com.github.shautvast.reflective.array.base;
|
||||||
|
|
||||||
public abstract class CharArraySetter implements ArraySetter {
|
public abstract class CharArrayAccessor implements ArrayAccessor {
|
||||||
|
|
||||||
public abstract void set(Object array, int index, char value);
|
public abstract void set(Object array, int index, char value);
|
||||||
|
public abstract char get(Object array, int index);
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.github.shautvast.reflective.array.base;
|
||||||
|
|
||||||
|
public abstract class DoubleArrayAccessor implements ArrayAccessor {
|
||||||
|
|
||||||
|
public abstract void set(Object array, int index, double value);
|
||||||
|
public abstract double get(Object array, int index);
|
||||||
|
}
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
package com.github.shautvast.reflective.array.base;
|
|
||||||
|
|
||||||
public abstract class DoubleArraySetter implements ArraySetter {
|
|
||||||
|
|
||||||
public abstract void set(Object array, int index, double value);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package com.github.shautvast.reflective.array.base;
|
||||||
|
|
||||||
|
public abstract class FloatArrayAccessor implements ArrayAccessor {
|
||||||
|
|
||||||
|
public abstract void set(Object array, int index, float value);
|
||||||
|
|
||||||
|
public abstract float get(Object array, int index);
|
||||||
|
}
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
package com.github.shautvast.reflective.array.base;
|
|
||||||
|
|
||||||
public abstract class FloatArraySetter implements ArraySetter {
|
|
||||||
|
|
||||||
public abstract void set(Object array, int index, float value);
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package com.github.shautvast.reflective.array.base;
|
package com.github.shautvast.reflective.array.base;
|
||||||
|
|
||||||
public abstract class IntArraySetter implements ArraySetter {
|
public abstract class IntArrayAccessor implements ArrayAccessor {
|
||||||
public abstract void set(Object array, int index, int value);
|
public abstract void set(Object array, int index, int value);
|
||||||
|
|
||||||
|
public abstract int get(Object array, int index);
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package com.github.shautvast.reflective.array.base;
|
package com.github.shautvast.reflective.array.base;
|
||||||
|
|
||||||
public abstract class LongArraySetter implements ArraySetter {
|
public abstract class LongArrayAccessor implements ArrayAccessor {
|
||||||
|
|
||||||
public abstract void set(Object array, int index, long value);
|
public abstract void set(Object array, int index, long value);
|
||||||
|
|
||||||
|
public abstract long get(Object array, int index);
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.github.shautvast.reflective.array.base;
|
||||||
|
|
||||||
|
public abstract class ObjectArrayAccessor implements ArrayAccessor {
|
||||||
|
public abstract void set(Object array, int index, Object value);
|
||||||
|
public abstract Object get(Object array, int index);
|
||||||
|
}
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
package com.github.shautvast.reflective.array.base;
|
|
||||||
|
|
||||||
public abstract class ObjectArraySetter implements ArraySetter {
|
|
||||||
public abstract void set(Object array, int index, Object value);
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package com.github.shautvast.reflective.array.base;
|
||||||
|
|
||||||
|
public abstract class ShortArrayAccessor implements ArrayAccessor {
|
||||||
|
|
||||||
|
public abstract void set(Object array, int index, short value);
|
||||||
|
|
||||||
|
public abstract short get(Object array, int index);
|
||||||
|
}
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
package com.github.shautvast.reflective.array.base;
|
|
||||||
|
|
||||||
public abstract class ShortArraySetter implements ArraySetter {
|
|
||||||
|
|
||||||
public abstract void set(Object array, int index, short value);
|
|
||||||
}
|
|
||||||
|
|
@ -156,6 +156,13 @@ public class Java {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* strips all disallowed characters from a classname */
|
||||||
|
public static String javaName(String arrayTypeName) {
|
||||||
|
return arrayTypeName
|
||||||
|
.replaceAll("[/.\\[;]", "")
|
||||||
|
.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
public static String mapPrimitiveOrArrayName(String type) {
|
public static String mapPrimitiveOrArrayName(String type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "byte":
|
case "byte":
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,174 @@
|
||||||
|
package com.github.shautvast.reflective.array;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
public class ArrayFactoryTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCreate1DimShortArray() {
|
||||||
|
Object o = ArrayFactory.newInstance(short.class, 1);
|
||||||
|
assertTrue(o instanceof short[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCreate2DimIntArray() {
|
||||||
|
int[][] ints = (int[][]) ArrayFactory.newInstance(int[].class, 1);
|
||||||
|
assertEquals(1, ints.length);
|
||||||
|
ints[0] = new int[1]; // will fail if array is not correctly created
|
||||||
|
assertEquals(1, ints[0].length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCreate3DimStringArray() {
|
||||||
|
String[][][] array = (String[][][]) ArrayFactory.newInstance(String.class, 6, 7, 8);
|
||||||
|
assertEquals(6, array.length);
|
||||||
|
assertEquals(7, array[0].length);
|
||||||
|
assertEquals(8, array[0][0].length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSetObject() {
|
||||||
|
String[] strings = new String[1];
|
||||||
|
ArrayFactory.set(strings, 0, "helloworld");
|
||||||
|
assertArrayEquals(new String[]{"helloworld"}, strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSetInt() {
|
||||||
|
int[] ints = new int[1];
|
||||||
|
ArrayFactory.setInt(ints, 0, 11);
|
||||||
|
assertArrayEquals(new int[]{11}, ints);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSetByte() {
|
||||||
|
byte[] bytes = new byte[1];
|
||||||
|
ArrayFactory.setByte(bytes, 0, (byte) 11);
|
||||||
|
assertArrayEquals(new byte[]{11}, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSetShort() {
|
||||||
|
short[] shorts = new short[1];
|
||||||
|
ArrayFactory.setShort(shorts, 0, (short) 11);
|
||||||
|
assertArrayEquals(new short[]{11}, shorts);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSetLong() {
|
||||||
|
long[] longs = new long[1];
|
||||||
|
ArrayFactory.setLong(longs, 0, 11L);
|
||||||
|
assertArrayEquals(new long[]{11}, longs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSetFloat() {
|
||||||
|
float[] floats = new float[1];
|
||||||
|
ArrayFactory.setFloat(floats, 0, 11.1F);
|
||||||
|
assertArrayEquals(new float[]{11.1F}, floats);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSetDouble() {
|
||||||
|
double[] doubles = new double[1];
|
||||||
|
ArrayFactory.setDouble(doubles, 0, 11.1D);
|
||||||
|
assertArrayEquals(new double[]{11.1D}, doubles);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSetBoolean() {
|
||||||
|
boolean[] booleans = new boolean[]{false};
|
||||||
|
ArrayFactory.setBoolean(booleans, 0, true);
|
||||||
|
assertArrayEquals(new boolean[]{true}, booleans);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSetChar() {
|
||||||
|
char[] chars = new char[]{'C'};
|
||||||
|
ArrayFactory.setChar(chars, 0, 'D');
|
||||||
|
assertArrayEquals(new char[]{'D'}, chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetFromObjectArray() {
|
||||||
|
String[] strings = new String[]{"helloworld"};
|
||||||
|
Object o = ArrayFactory.get(strings, 0);
|
||||||
|
assertTrue(o instanceof String);
|
||||||
|
String string = (String) o;
|
||||||
|
assertEquals("helloworld", string);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetFromByteArray() {
|
||||||
|
byte[] bytes = new byte[]{17};
|
||||||
|
byte b = ArrayFactory.getByte(bytes, 0);
|
||||||
|
assertEquals(17, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetFromShortArray() {
|
||||||
|
short[] shorts = new short[]{17};
|
||||||
|
short s = ArrayFactory.getShort(shorts, 0);
|
||||||
|
assertEquals(17, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetFromIntArray() {
|
||||||
|
int[] ints = new int[]{17};
|
||||||
|
int i = ArrayFactory.getInt(ints, 0);
|
||||||
|
assertEquals(17, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetFromLongArray() {
|
||||||
|
long[] longs = new long[]{17};
|
||||||
|
long l = ArrayFactory.getLong(longs, 0);
|
||||||
|
assertEquals(17, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetFromCharArray() {
|
||||||
|
char[] chars = new char[]{17};
|
||||||
|
char c = ArrayFactory.getChar(chars, 0);
|
||||||
|
assertEquals(17, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetFromBooleanArray() {
|
||||||
|
boolean[] booleans = new boolean[]{true};
|
||||||
|
boolean b = ArrayFactory.getBoolean(booleans, 0);
|
||||||
|
assertEquals(true, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetFromFloatArray() {
|
||||||
|
float[] floats = new float[]{17.5F};
|
||||||
|
float f = ArrayFactory.getFloat(floats, 0);
|
||||||
|
assertEquals(17.5, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetFromDoubleArray() {
|
||||||
|
double[] doubles = new double[]{17.5F};
|
||||||
|
double d = ArrayFactory.getDouble(doubles, 0);
|
||||||
|
assertEquals(17.5, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void arrayIndexOutOfBoundsException() {
|
||||||
|
double[] doubles = new double[]{};
|
||||||
|
assertThrows(ArrayIndexOutOfBoundsException.class, () -> ArrayFactory.getDouble(doubles, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void notAnArray() {
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> ArrayFactory.get("foo", 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void arrayIsNull() {
|
||||||
|
assertThrows(NullPointerException.class, () -> ArrayFactory.get(null, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
package com.github.shautvast.reflective.array;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
public class ArraysTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testCreate1DimShortArray() {
|
|
||||||
Object o = ArrayFactory.newInstance(short.class, 1);
|
|
||||||
assertTrue(o instanceof short[]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testCreate2DimIntArray() {
|
|
||||||
int[][] ints = (int[][]) ArrayFactory.newInstance(int[].class, 1);
|
|
||||||
assertEquals(1, ints.length);
|
|
||||||
ints[0] = new int[1]; // will fail if array is not correctly created
|
|
||||||
assertEquals(1, ints[0].length);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testCreate3DimStringArray() {
|
|
||||||
String[][][] array = (String[][][]) ArrayFactory.newInstance(String.class, 6, 7, 8);
|
|
||||||
assertEquals(6, array.length);
|
|
||||||
assertEquals(7, array[0].length);
|
|
||||||
assertEquals(8, array[0][0].length);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSetObject() {
|
|
||||||
String[] strings = new String[1];
|
|
||||||
ArrayFactory.set(strings, 0, "helloworld");
|
|
||||||
assertArrayEquals(new String[]{"helloworld"}, strings);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSetInt() {
|
|
||||||
int[] ints = new int[1];
|
|
||||||
ArrayFactory.set(ints, 0, 11);
|
|
||||||
assertArrayEquals(new int[]{11}, ints);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSetByte() {
|
|
||||||
byte[] bytes = new byte[1];
|
|
||||||
ArrayFactory.set(bytes, 0, (byte) 11);
|
|
||||||
assertArrayEquals(new byte[]{11}, bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSetShort() {
|
|
||||||
short[] shorts = new short[1];
|
|
||||||
ArrayFactory.set(shorts, 0, (short) 11);
|
|
||||||
assertArrayEquals(new short[]{11}, shorts);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSetLong() {
|
|
||||||
long[] longs = new long[1];
|
|
||||||
ArrayFactory.set(longs, 0, 11L);
|
|
||||||
assertArrayEquals(new long[]{11}, longs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSetFloat() {
|
|
||||||
float[] floats = new float[1];
|
|
||||||
ArrayFactory.set(floats, 0, 11.1F);
|
|
||||||
assertArrayEquals(new float[]{11.1F}, floats);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSetDouble() {
|
|
||||||
double[] doubles = new double[1];
|
|
||||||
ArrayFactory.set(doubles, 0, 11.1D);
|
|
||||||
assertArrayEquals(new double[]{11.1D}, doubles);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSetBoolean() {
|
|
||||||
boolean[] booleans = new boolean[]{false};
|
|
||||||
ArrayFactory.set(booleans, 0, true);
|
|
||||||
assertArrayEquals(new boolean[]{true}, booleans);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testSetChar() {
|
|
||||||
char[] chars = new char[]{'C'};
|
|
||||||
ArrayFactory.set(chars, 0, 'D');
|
|
||||||
assertArrayEquals(new char[]{'D'}, chars);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Reference in a new issue