diff --git a/src/main/java/com/github/shautvast/reflective/array/ArrayFactory.java b/src/main/java/com/github/shautvast/reflective/array/ArrayFactory.java index 6763dff..3af44a9 100644 --- a/src/main/java/com/github/shautvast/reflective/array/ArrayFactory.java +++ b/src/main/java/com/github/shautvast/reflective/array/ArrayFactory.java @@ -2,11 +2,17 @@ package com.github.shautvast.reflective.array; import com.github.shautvast.reflective.array.base.*; +import java.lang.reflect.Array; + /** * Public interface for dynamically working with arrays (create, set and get operations) + *

+ * 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 @@ -27,7 +33,18 @@ public class ArrayFactory { * @param value the value to set */ 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 value the value to set */ - public static void set(Object array, int index, int value) { - ArrayHandlerFactory.getSetterInstance(IntArraySetter.class, typeChecked(array)).set(array, index, value); + public static void setInt(Object array, int index, int 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 value the value to set */ - public static void set(Object array, int index, byte value) { - ArrayHandlerFactory.getSetterInstance(ByteArraySetter.class, typeChecked(array)).set(array, index, value); + public static void setByte(Object array, int index, byte 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 value the value to set */ - public static void set(Object array, int index, short value) { - ArrayHandlerFactory.getSetterInstance(ShortArraySetter.class, typeChecked(array)).set(array, index, value); + public static void setShort(Object array, int index, short 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 value the value to set */ - public static void set(Object array, int index, long value) { - ArrayHandlerFactory.getSetterInstance(LongArraySetter.class, typeChecked(array)).set(array, index, value); + public static void setLong(Object array, int index, long 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 value the value to set */ - public static void set(Object array, int index, float value) { - ArrayHandlerFactory.getSetterInstance(FloatArraySetter.class, typeChecked(array)).set(array, index, value); + public static void setFloat(Object array, int index, float 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 value the value to set */ - public static void set(Object array, int index, double value) { - ArrayHandlerFactory.getSetterInstance(DoubleArraySetter.class, typeChecked(array)).set(array, index, value); + public static void setDouble(Object array, int index, double 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 */ private static Class typeChecked(Object array) { + if (array == null) { + throw new NullPointerException("Argument is null"); + } Class arrayType = array.getClass(); if (!arrayType.isArray()) { - throw new IllegalArgumentException("This is not an array"); + throw new IllegalArgumentException("Argument is not an array"); } return arrayType; } + } diff --git a/src/main/java/com/github/shautvast/reflective/array/ArrayHandlerFactory.java b/src/main/java/com/github/shautvast/reflective/array/ArrayHandlerFactory.java index 1ca274a..446b773 100644 --- a/src/main/java/com/github/shautvast/reflective/array/ArrayHandlerFactory.java +++ b/src/main/java/com/github/shautvast/reflective/array/ArrayHandlerFactory.java @@ -1,8 +1,8 @@ package com.github.shautvast.reflective.array; import com.github.shautvast.reflective.array.base.ArrayCreator; -import com.github.shautvast.reflective.array.base.ArraySetter; -import com.github.shautvast.reflective.array.base.ObjectArraySetter; +import com.github.shautvast.reflective.array.base.ArrayAccessor; +import com.github.shautvast.reflective.array.base.ObjectArrayAccessor; import com.github.shautvast.reflective.java.ASM; import com.github.shautvast.reflective.java.ByteClassLoader; import com.github.shautvast.reflective.java.Java; @@ -21,45 +21,38 @@ class ArrayHandlerFactory { /* cache for the compiled creator classes */ private static final Map creatorCache = new ConcurrentHashMap<>(); - /* Cache for the compiled setter classes. - * The outer Map contains the ArraySetter type (some primitive or Object Setter) - * That maps to the concrete calculated ArraySetter instance name which maps to the instance itself. + /* Cache for the compiled accessor classes. + * The outer Map contains the ArrayAccessor type (some primitive or Object Accessor) + * That maps to the concrete calculated ArrayAccessor instance name which maps to the instance itself. * TODO see if this can be optimized */ - private static final Map, Map> setterCache = new ConcurrentHashMap<>(); + private static final Map, Map> accessorCache = new ConcurrentHashMap<>(); /* - * generic method for creating array setters (primitives and objects) + * generic method for creating array accessors (primitives and objects) */ @SuppressWarnings("unchecked") - static T getSetterInstance(Class setterBaseType, Class arrayType) { + static T getAccessorInstance(Class accessorBaseType, Class arrayType) { String arrayTypeName = Java.internalName(arrayType); - String syntheticClassName = "com/shautvast/reflective/array/ArraySetter_" - + javaName(arrayTypeName) + Java.getNumDimensions(arrayType); + String syntheticClassName = "com/shautvast/reflective/array/ArrayAccessor_" + + Java.javaName(arrayTypeName) + Java.getNumDimensions(arrayType); - return (T) setterCache.computeIfAbsent(setterBaseType, k -> new ConcurrentHashMap<>()). + return (T) accessorCache.computeIfAbsent(accessorBaseType, k -> new ConcurrentHashMap<>()). computeIfAbsent(syntheticClassName, - k -> ArrayHandlerFactory.createSyntheticArraySetter(setterBaseType, arrayTypeName, syntheticClassName)); + k -> ArrayHandlerFactory.createSyntheticArrayAccessor(accessorBaseType, arrayTypeName, syntheticClassName)); } /* creates an instance of an ArrayCreator of the specified type */ static ArrayCreator getCreatorInstance(Class elementType, int... dimensions) { String elementTypeName = Java.internalName(elementType); String syntheticClassName = "com/shautvast/reflective/array/ArrayCreator_" - + javaName(elementTypeName) + dimensions.length; + + Java.javaName(elementTypeName) + dimensions.length; return creatorCache.computeIfAbsent(syntheticClassName, 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 */ static ArrayCreator createSyntheticArrayCreator(String elementType, String name, int... dimensions) { ClassNode classNode = ASM.createDefaultClassNode(name, Java.internalName(ArrayCreator.class)); @@ -84,10 +77,11 @@ class ArrayHandlerFactory { } } - /* Creates the ASM ClassNode for an ArraySetter */ - static T createSyntheticArraySetter(Class setterType, String arrayType, String name) { - ClassNode classNode = ASM.createDefaultClassNode(name, Java.internalName(setterType)); - classNode.methods.add(createSetMethodNode(setterType, arrayType)); + /* Creates the ASM ClassNode for an ArrayAccessor */ + static T createSyntheticArrayAccessor(Class accessorType, String arrayType, String name) { + ClassNode classNode = ASM.createDefaultClassNode(name, Java.internalName(accessorType)); + classNode.methods.add(createSetMethodNode(accessorType, arrayType)); + classNode.methods.add(createGetMethodNode(accessorType, arrayType)); ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES); classNode.accept(classWriter); @@ -102,7 +96,7 @@ class ArrayHandlerFactory { ByteClassLoader.INSTANCE.addClass(classNode.name, byteArray); try { - return setterType.cast(ByteClassLoader.INSTANCE.loadClass(classNode.name).getConstructor().newInstance()); + return accessorType.cast(ByteClassLoader.INSTANCE.loadClass(classNode.name).getConstructor().newInstance()); } catch (Exception e) { throw new RuntimeException(e); } @@ -119,17 +113,17 @@ class ArrayHandlerFactory { return methodNode; } - /* Creates the set method for ArraySetter classes */ - private static MethodNode createSetMethodNode(Class setterType, String arrayType) { + /* Creates the set method for ArrayAccessor classes */ + private static MethodNode createSetMethodNode(Class accessorType, String arrayType) { String elementType; - if (setterType == ObjectArraySetter.class) { + if (accessorType == ObjectArrayAccessor.class) { elementType = "Ljava/lang/Object;"; } else { elementType = arrayType.substring(1); } MethodNode methodNode = new MethodNode(ACC_PUBLIC, "set", "(Ljava/lang/Object;I" + elementType + ")V", null, null); - int[] opcodes = getInstructions(elementType); + int[] opcodes = arrayStoreInstructions(elementType); InsnList insns = methodNode.instructions; insns.add(new VarInsnNode(ALOAD, 1)); insns.add(new TypeInsnNode(CHECKCAST, arrayType)); @@ -141,14 +135,34 @@ class ArrayHandlerFactory { 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 */ - private static int[] getInstructions(String type) { + private static int[] arrayStoreInstructions(String type) { switch (type) { case "B": case "Z": - return new int[]{ILOAD, BASTORE}; // load int, store byte?? + return new int[]{ILOAD, BASTORE}; case "S": return new int[]{ILOAD, SASTORE}; case "I": @@ -165,4 +179,29 @@ class ArrayHandlerFactory { 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}; + } + } } diff --git a/src/main/java/com/github/shautvast/reflective/array/base/ArraySetter.java b/src/main/java/com/github/shautvast/reflective/array/base/ArrayAccessor.java similarity index 80% rename from src/main/java/com/github/shautvast/reflective/array/base/ArraySetter.java rename to src/main/java/com/github/shautvast/reflective/array/base/ArrayAccessor.java index ca4ae27..b7e35b2 100644 --- a/src/main/java/com/github/shautvast/reflective/array/base/ArraySetter.java +++ b/src/main/java/com/github/shautvast/reflective/array/base/ArrayAccessor.java @@ -3,5 +3,5 @@ package com.github.shautvast.reflective.array.base; /** * Empty interface because you can't be generic over primitives in Java */ -public interface ArraySetter { +public interface ArrayAccessor { } diff --git a/src/main/java/com/github/shautvast/reflective/array/base/BooleanArrayAccessor.java b/src/main/java/com/github/shautvast/reflective/array/base/BooleanArrayAccessor.java new file mode 100644 index 0000000..088a96f --- /dev/null +++ b/src/main/java/com/github/shautvast/reflective/array/base/BooleanArrayAccessor.java @@ -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); +} diff --git a/src/main/java/com/github/shautvast/reflective/array/base/BooleanArraySetter.java b/src/main/java/com/github/shautvast/reflective/array/base/BooleanArraySetter.java deleted file mode 100644 index fef0909..0000000 --- a/src/main/java/com/github/shautvast/reflective/array/base/BooleanArraySetter.java +++ /dev/null @@ -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); -} diff --git a/src/main/java/com/github/shautvast/reflective/array/base/ByteArraySetter.java b/src/main/java/com/github/shautvast/reflective/array/base/ByteArrayAccessor.java similarity index 50% rename from src/main/java/com/github/shautvast/reflective/array/base/ByteArraySetter.java rename to src/main/java/com/github/shautvast/reflective/array/base/ByteArrayAccessor.java index 06796b0..dd66a95 100644 --- a/src/main/java/com/github/shautvast/reflective/array/base/ByteArraySetter.java +++ b/src/main/java/com/github/shautvast/reflective/array/base/ByteArrayAccessor.java @@ -1,6 +1,8 @@ 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 byte get(Object array, int index); } diff --git a/src/main/java/com/github/shautvast/reflective/array/base/CharArraySetter.java b/src/main/java/com/github/shautvast/reflective/array/base/CharArrayAccessor.java similarity index 50% rename from src/main/java/com/github/shautvast/reflective/array/base/CharArraySetter.java rename to src/main/java/com/github/shautvast/reflective/array/base/CharArrayAccessor.java index 8453275..2245368 100644 --- a/src/main/java/com/github/shautvast/reflective/array/base/CharArraySetter.java +++ b/src/main/java/com/github/shautvast/reflective/array/base/CharArrayAccessor.java @@ -1,6 +1,7 @@ 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 char get(Object array, int index); } diff --git a/src/main/java/com/github/shautvast/reflective/array/base/DoubleArrayAccessor.java b/src/main/java/com/github/shautvast/reflective/array/base/DoubleArrayAccessor.java new file mode 100644 index 0000000..5820ac1 --- /dev/null +++ b/src/main/java/com/github/shautvast/reflective/array/base/DoubleArrayAccessor.java @@ -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); +} diff --git a/src/main/java/com/github/shautvast/reflective/array/base/DoubleArraySetter.java b/src/main/java/com/github/shautvast/reflective/array/base/DoubleArraySetter.java deleted file mode 100644 index a4b1275..0000000 --- a/src/main/java/com/github/shautvast/reflective/array/base/DoubleArraySetter.java +++ /dev/null @@ -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); -} diff --git a/src/main/java/com/github/shautvast/reflective/array/base/FloatArrayAccessor.java b/src/main/java/com/github/shautvast/reflective/array/base/FloatArrayAccessor.java new file mode 100644 index 0000000..2fd3fa6 --- /dev/null +++ b/src/main/java/com/github/shautvast/reflective/array/base/FloatArrayAccessor.java @@ -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); +} diff --git a/src/main/java/com/github/shautvast/reflective/array/base/FloatArraySetter.java b/src/main/java/com/github/shautvast/reflective/array/base/FloatArraySetter.java deleted file mode 100644 index f279048..0000000 --- a/src/main/java/com/github/shautvast/reflective/array/base/FloatArraySetter.java +++ /dev/null @@ -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); -} diff --git a/src/main/java/com/github/shautvast/reflective/array/base/IntArraySetter.java b/src/main/java/com/github/shautvast/reflective/array/base/IntArrayAccessor.java similarity index 50% rename from src/main/java/com/github/shautvast/reflective/array/base/IntArraySetter.java rename to src/main/java/com/github/shautvast/reflective/array/base/IntArrayAccessor.java index c04d0a9..89f8aa3 100644 --- a/src/main/java/com/github/shautvast/reflective/array/base/IntArraySetter.java +++ b/src/main/java/com/github/shautvast/reflective/array/base/IntArrayAccessor.java @@ -1,5 +1,7 @@ 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 int get(Object array, int index); } diff --git a/src/main/java/com/github/shautvast/reflective/array/base/LongArraySetter.java b/src/main/java/com/github/shautvast/reflective/array/base/LongArrayAccessor.java similarity index 50% rename from src/main/java/com/github/shautvast/reflective/array/base/LongArraySetter.java rename to src/main/java/com/github/shautvast/reflective/array/base/LongArrayAccessor.java index ecf8309..37b2a57 100644 --- a/src/main/java/com/github/shautvast/reflective/array/base/LongArraySetter.java +++ b/src/main/java/com/github/shautvast/reflective/array/base/LongArrayAccessor.java @@ -1,6 +1,8 @@ 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 long get(Object array, int index); } diff --git a/src/main/java/com/github/shautvast/reflective/array/base/ObjectArrayAccessor.java b/src/main/java/com/github/shautvast/reflective/array/base/ObjectArrayAccessor.java new file mode 100644 index 0000000..30f2838 --- /dev/null +++ b/src/main/java/com/github/shautvast/reflective/array/base/ObjectArrayAccessor.java @@ -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); +} diff --git a/src/main/java/com/github/shautvast/reflective/array/base/ObjectArraySetter.java b/src/main/java/com/github/shautvast/reflective/array/base/ObjectArraySetter.java deleted file mode 100644 index f7f71fb..0000000 --- a/src/main/java/com/github/shautvast/reflective/array/base/ObjectArraySetter.java +++ /dev/null @@ -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); -} diff --git a/src/main/java/com/github/shautvast/reflective/array/base/ShortArrayAccessor.java b/src/main/java/com/github/shautvast/reflective/array/base/ShortArrayAccessor.java new file mode 100644 index 0000000..1b17c15 --- /dev/null +++ b/src/main/java/com/github/shautvast/reflective/array/base/ShortArrayAccessor.java @@ -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); +} diff --git a/src/main/java/com/github/shautvast/reflective/array/base/ShortArraySetter.java b/src/main/java/com/github/shautvast/reflective/array/base/ShortArraySetter.java deleted file mode 100644 index 3be5d80..0000000 --- a/src/main/java/com/github/shautvast/reflective/array/base/ShortArraySetter.java +++ /dev/null @@ -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); -} diff --git a/src/main/java/com/github/shautvast/reflective/java/Java.java b/src/main/java/com/github/shautvast/reflective/java/Java.java index b6235dd..1cda97e 100644 --- a/src/main/java/com/github/shautvast/reflective/java/Java.java +++ b/src/main/java/com/github/shautvast/reflective/java/Java.java @@ -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) { switch (type) { case "byte": diff --git a/src/test/java/com/github/shautvast/reflective/array/ArrayFactoryTest.java b/src/test/java/com/github/shautvast/reflective/array/ArrayFactoryTest.java new file mode 100644 index 0000000..bc81efb --- /dev/null +++ b/src/test/java/com/github/shautvast/reflective/array/ArrayFactoryTest.java @@ -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)); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/shautvast/reflective/array/ArraysTest.java b/src/test/java/com/github/shautvast/reflective/array/ArraysTest.java deleted file mode 100644 index 0d730e1..0000000 --- a/src/test/java/com/github/shautvast/reflective/array/ArraysTest.java +++ /dev/null @@ -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); - } -} \ No newline at end of file