diff --git a/src/main/java/com/github/shautvast/reflective/InvokerFactory.java b/src/main/java/com/github/shautvast/reflective/InvokerFactory.java index 7e1f44e..8b19f0d 100644 --- a/src/main/java/com/github/shautvast/reflective/InvokerFactory.java +++ b/src/main/java/com/github/shautvast/reflective/InvokerFactory.java @@ -61,7 +61,6 @@ public class InvokerFactory { // put argument on the stack insns.add(new InsnNode(AALOAD)); 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); } @@ -164,7 +163,6 @@ public class InvokerFactory { } private static Class mapPrimitiveToWrapper(Class type) { - System.out.println(type); if (type == int.class) { return Integer.class; } else if (type == byte.class) { diff --git a/src/main/java/com/github/shautvast/reflective/Main.java b/src/main/java/com/github/shautvast/reflective/Main.java deleted file mode 100644 index fbe19c5..0000000 --- a/src/main/java/com/github/shautvast/reflective/Main.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.github.shautvast.reflective; - -import com.github.shautvast.reflective.MetaClass; -import com.github.shautvast.reflective.Reflective; - -public class Main { - public static void main(String[] args) { - Dummy dummy = new Dummy(); - dummy.setName("foo"); - MetaClass metaDummy = Reflective.getMetaClass(dummy.getClass()); - - metaDummy.getMethod("setName") - .ifPresent(m -> m.invoke(dummy, "bar")); - System.out.println(dummy.getName()); // prints "bar" - } - - public static class Dummy { - private String name; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - } -} \ No newline at end of file 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 e1d2416..0269b21 100644 --- a/src/main/java/com/github/shautvast/reflective/array/ArrayFactory.java +++ b/src/main/java/com/github/shautvast/reflective/array/ArrayFactory.java @@ -1,24 +1,18 @@ package com.github.shautvast.reflective.array; -import com.github.shautvast.reflective.java.ASM; -import com.github.shautvast.reflective.java.ByteClassLoader; +import com.github.shautvast.reflective.array.base.*; import com.github.shautvast.reflective.java.Java; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.tree.*; -import java.util.Arrays; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import static org.objectweb.asm.Opcodes.ACC_PUBLIC; -import static org.objectweb.asm.Opcodes.ARETURN; /** - * Factory class for dynamically creating arrays + * Factory class for dynamically working with arrays */ public class ArrayFactory { - private static final ConcurrentMap cache = new ConcurrentHashMap<>(); + private static final Map creatorCache = new ConcurrentHashMap<>(); + private static final Map, Map> setterCache = new ConcurrentHashMap<>(); /** * Creates a new array of the specified type and dimensions @@ -27,69 +21,127 @@ public class ArrayFactory { * @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 elementType, int... dimensions) { + public static Object newInstance(Class elementType, int... dimensions) { + return getCreatorInstance(elementType, dimensions).newInstance(); + } + + /** + * Sets an Object 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 set(Object array, int index, Object value) { + getSetterInstance(ObjectArraySetter.class, typeChecked(array)).set(array, index, value); + } + + /** + * Sets an int 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 set(Object array, int index, int value) { + getSetterInstance(IntArraySetter.class, typeChecked(array)).set(array, index, value); + } + + /** + * Sets a byte 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 set(Object array, int index, byte value) { + getSetterInstance(ByteArraySetter.class, typeChecked(array)).set(array, index, value); + } + + /** + * Sets a short 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 set(Object array, int index, short value) { + getSetterInstance(ShortArraySetter.class, typeChecked(array)).set(array, index, value); + } + + /** + * Sets a long 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 set(Object array, int index, long value) { + getSetterInstance(LongArraySetter.class, typeChecked(array)).set(array, index, value); + } + + /** + * Sets a byte 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 set(Object array, int index, float value) { + getSetterInstance(FloatArraySetter.class, typeChecked(array)).set(array, index, value); + } + + /** + * Sets a double 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 set(Object array, int index, double value) { + getSetterInstance(DoubleArraySetter.class, typeChecked(array)).set(array, index, value); + } + + public static void set(Object array, int index, char value) { + getSetterInstance(CharArraySetter.class, typeChecked(array)).set(array, index, value); + } + + public static void set(Object array, int index, boolean value) { + getSetterInstance(BooleanArraySetter.class, typeChecked(array)).set(array, index, value); + } + + private static Class typeChecked(Object array) { + Class arrayType = array.getClass(); + if (!arrayType.isArray()) { + throw new IllegalArgumentException("This is not an array"); + } + return arrayType; + } + + @SuppressWarnings("unchecked") + private static T getSetterInstance(Class setterBaseType, Class arrayType) { + String arrayTypeName = Java.internalName(arrayType); + String syntheticClassName = getSyntheticClassName(arrayType, arrayTypeName); + + return (T) setterCache.computeIfAbsent(setterBaseType, k -> new ConcurrentHashMap<>()). + computeIfAbsent(syntheticClassName, + k -> AsmArrayFactory.createSyntheticArraySetter(setterBaseType, arrayTypeName, syntheticClassName)); + } + + private static String getSyntheticClassName(Class arrayType, String arrayTypeName) { + return "com/shautvast/reflective/array/ArraySetter_" + + javaName(arrayTypeName) + Java.getNumDimensions(arrayType); + } + + private static ArrayCreator getCreatorInstance(Class elementType, int... dimensions) { String elementTypeName = Java.internalName(elementType); - String syntheticClassName = syntheticClassName(elementTypeName, dimensions); + String syntheticClassName = "com/shautvast/reflective/array/ArrayCreator_" + + javaName(elementTypeName) + dimensions.length; - return cache.computeIfAbsent(syntheticClassName, - k -> createSyntheticArrayCreator(elementTypeName, syntheticClassName, dimensions)).newInstance(); + return creatorCache.computeIfAbsent(syntheticClassName, + k -> AsmArrayFactory.createSyntheticArrayCreator(elementTypeName, syntheticClassName, dimensions)); } - private static String syntheticClassName(String elementTypeName, int[] dimensions) { - return "RAC" + elementTypeName + private static String javaName(String arrayTypeName) { + return arrayTypeName .replaceAll("[/.\\[;]", "") - .toLowerCase() + "L" + dimensions.length; + .toLowerCase(); } - - 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)); - MethodNode methodNode = new MethodNode(ACC_PUBLIC, - "newInstance", "()Ljava/lang/Object;", null, null); - classNode.methods.add(methodNode); - InsnList insns = methodNode.instructions; - Arrays.stream(dimensions).forEach(d -> insns.add(new LdcInsnNode(d))); - insns.add(new MultiANewArrayInsnNode(createArrayType(componentType, dimensions), dimensions.length)); - insns.add(new InsnNode(ARETURN)); - return classNode; - } - - private static String createArrayType(String componentType, int[] dimensions) { - StringBuilder s = new StringBuilder(); - s.append("[".repeat(dimensions.length)); - boolean isObject = !componentType.startsWith("[") && componentType.contains("/"); - if (isObject) { - s.append("L"); - s.append(componentType); - } else { - s.append(Java.mapPrimitiveOrArrayName(componentType)); - } - if (isObject) { - s.append(";"); - } - return s.toString(); - } - } diff --git a/src/main/java/com/github/shautvast/reflective/array/AsmArrayFactory.java b/src/main/java/com/github/shautvast/reflective/array/AsmArrayFactory.java new file mode 100644 index 0000000..bc0c623 --- /dev/null +++ b/src/main/java/com/github/shautvast/reflective/array/AsmArrayFactory.java @@ -0,0 +1,120 @@ +package com.github.shautvast.reflective.array; + +import com.github.shautvast.reflective.array.base.ArrayCreator; +import com.github.shautvast.reflective.array.base.ObjectArraySetter; +import com.github.shautvast.reflective.java.ASM; +import com.github.shautvast.reflective.java.ByteClassLoader; +import com.github.shautvast.reflective.java.Java; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.tree.*; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Arrays; + +import static org.objectweb.asm.Opcodes.*; + +class AsmArrayFactory { + static ArrayCreator createSyntheticArrayCreator(String elementType, String name, int... dimensions) { + ClassNode classNode = ASM.createDefaultClassNode(name, Java.internalName(ArrayCreator.class)); + classNode.methods.add(createNewInstanceMethodNode(elementType, 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); + } + } + + static T createSyntheticArraySetter(Class setterType, String arrayType, String name) { + ClassNode classNode = ASM.createDefaultClassNode(name, Java.internalName(setterType)); + classNode.methods.add(createSetMethodNode(setterType, arrayType)); + ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + classNode.accept(classWriter); + + byte[] byteArray = classWriter.toByteArray(); + + try (FileOutputStream out = new FileOutputStream("A.class")) { + out.write(byteArray); + } catch (IOException e) { + e.printStackTrace(); + } + + ByteClassLoader.INSTANCE.addClass(classNode.name, byteArray); + + try { + return setterType.cast(ByteClassLoader.INSTANCE.loadClass(classNode.name).getConstructor().newInstance()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static MethodNode createNewInstanceMethodNode(String componentType, int[] dimensions) { + MethodNode methodNode = new MethodNode(ACC_PUBLIC, + "newInstance", "()Ljava/lang/Object;", null, null); + InsnList insns = methodNode.instructions; + Arrays.stream(dimensions).forEach(d -> insns.add(new LdcInsnNode(d))); + insns.add(new MultiANewArrayInsnNode(Java.createArrayType(componentType, dimensions), dimensions.length)); + insns.add(new InsnNode(ARETURN)); + return methodNode; + } + + private static MethodNode createSetMethodNode(Class setterType, String arrayType) { + String elementType; + if (setterType == ObjectArraySetter.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); + InsnList insns = methodNode.instructions; + insns.add(new VarInsnNode(ALOAD, 1)); + insns.add(new TypeInsnNode(CHECKCAST, arrayType)); + insns.add(new VarInsnNode(ILOAD, 2)); + insns.add(new VarInsnNode(opcodes[0], 3)); + insns.add(new InsnNode(opcodes[1])); + insns.add(new InsnNode(RETURN)); + + return methodNode; + } + + /* + * gets the pair of appropriate load (type) and store (array of type) instructions + */ + private static int[] getInstructions(String type) { + switch (type) { + case "B": + case "Z": + return new int[]{ILOAD, BASTORE}; + case "S": + return new int[]{ILOAD, SASTORE}; + case "I": + return new int[]{ILOAD, IASTORE}; + case "J": + return new int[]{LLOAD, LASTORE}; + case "F": + return new int[]{FLOAD, FASTORE}; + case "D": + return new int[]{DLOAD, DASTORE}; + case "C": + return new int[]{ILOAD, CASTORE}; + + default: + return new int[]{ALOAD, AASTORE}; + } + } +} diff --git a/src/main/java/com/github/shautvast/reflective/array/ArrayCreator.java b/src/main/java/com/github/shautvast/reflective/array/base/ArrayCreator.java similarity index 61% rename from src/main/java/com/github/shautvast/reflective/array/ArrayCreator.java rename to src/main/java/com/github/shautvast/reflective/array/base/ArrayCreator.java index 54d62b6..d6dbb50 100644 --- a/src/main/java/com/github/shautvast/reflective/array/ArrayCreator.java +++ b/src/main/java/com/github/shautvast/reflective/array/base/ArrayCreator.java @@ -1,4 +1,4 @@ -package com.github.shautvast.reflective.array; +package com.github.shautvast.reflective.array.base; public abstract class ArrayCreator { 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 new file mode 100644 index 0000000..eaf9b2b --- /dev/null +++ b/src/main/java/com/github/shautvast/reflective/array/base/BooleanArraySetter.java @@ -0,0 +1,6 @@ +package com.github.shautvast.reflective.array.base; + +public abstract class BooleanArraySetter { + + 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/ByteArraySetter.java new file mode 100644 index 0000000..3e9b074 --- /dev/null +++ b/src/main/java/com/github/shautvast/reflective/array/base/ByteArraySetter.java @@ -0,0 +1,6 @@ +package com.github.shautvast.reflective.array.base; + +public abstract class ByteArraySetter { + + public abstract void set(Object array, int index, byte value); +} diff --git a/src/main/java/com/github/shautvast/reflective/array/base/CharArraySetter.java b/src/main/java/com/github/shautvast/reflective/array/base/CharArraySetter.java new file mode 100644 index 0000000..dc090b7 --- /dev/null +++ b/src/main/java/com/github/shautvast/reflective/array/base/CharArraySetter.java @@ -0,0 +1,6 @@ +package com.github.shautvast.reflective.array.base; + +public abstract class CharArraySetter { + + public abstract void set(Object array, int index, char value); +} 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 new file mode 100644 index 0000000..826a4bb --- /dev/null +++ b/src/main/java/com/github/shautvast/reflective/array/base/DoubleArraySetter.java @@ -0,0 +1,6 @@ +package com.github.shautvast.reflective.array.base; + +public abstract class DoubleArraySetter { + + public abstract void set(Object array, int index, double value); +} 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 new file mode 100644 index 0000000..5a67788 --- /dev/null +++ b/src/main/java/com/github/shautvast/reflective/array/base/FloatArraySetter.java @@ -0,0 +1,6 @@ +package com.github.shautvast.reflective.array.base; + +public abstract class FloatArraySetter { + + 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/IntArraySetter.java new file mode 100644 index 0000000..240fd86 --- /dev/null +++ b/src/main/java/com/github/shautvast/reflective/array/base/IntArraySetter.java @@ -0,0 +1,5 @@ +package com.github.shautvast.reflective.array.base; + +public abstract class IntArraySetter { + public abstract void set(Object array, int index, int value); +} diff --git a/src/main/java/com/github/shautvast/reflective/array/base/LongArraySetter.java b/src/main/java/com/github/shautvast/reflective/array/base/LongArraySetter.java new file mode 100644 index 0000000..9ab95f4 --- /dev/null +++ b/src/main/java/com/github/shautvast/reflective/array/base/LongArraySetter.java @@ -0,0 +1,6 @@ +package com.github.shautvast.reflective.array.base; + +public abstract class LongArraySetter { + + public abstract void set(Object array, int index, long value); +} 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 new file mode 100644 index 0000000..4616dbe --- /dev/null +++ b/src/main/java/com/github/shautvast/reflective/array/base/ObjectArraySetter.java @@ -0,0 +1,5 @@ +package com.github.shautvast.reflective.array.base; + +public abstract class ObjectArraySetter { + public abstract void set(Object array, int index, Object value); +} 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 new file mode 100644 index 0000000..8780e98 --- /dev/null +++ b/src/main/java/com/github/shautvast/reflective/array/base/ShortArraySetter.java @@ -0,0 +1,6 @@ +package com.github.shautvast.reflective.array.base; + +public abstract class ShortArraySetter { + + 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 5fb57a0..b6235dd 100644 --- a/src/main/java/com/github/shautvast/reflective/java/Java.java +++ b/src/main/java/com/github/shautvast/reflective/java/Java.java @@ -106,7 +106,6 @@ public class Java { } public static Class toClass(String descriptor) { - System.out.println("desc;" + descriptor); try { if (descriptor.length() == 1) { return mapIfPrimitive(descriptor.charAt(0)); @@ -126,7 +125,6 @@ public class Java { } type = Java.externalName(type); Class aClass = Class.forName(dims + type); - System.out.println(aClass); return aClass; } catch (ClassNotFoundException e) { throw new RuntimeException(e); @@ -154,7 +152,6 @@ public class Java { case 'V': return Void.class; default: - System.out.println("desc:" + descriptor); return null; } } @@ -185,4 +182,32 @@ public class Java { } } } + + public static int getNumDimensions(Class arrayType) { + return getNumDimensions(arrayType.getName()); + } + + public static int getNumDimensions(String arrayName) { + int i = 0; + while (arrayName.charAt(i) == '[') { + i++; + } + return i; + } + + public static String createArrayType(String componentType, int[] dimensions) { + StringBuilder s = new StringBuilder(); + s.append("[".repeat(dimensions.length)); + boolean isObject = !componentType.startsWith("[") && componentType.contains("/"); + if (isObject) { + s.append("L"); + s.append(componentType); + } else { + s.append(Java.mapPrimitiveOrArrayName(componentType)); + } + if (isObject) { + s.append(";"); + } + return s.toString(); + } } diff --git a/src/test/java/com/github/shautvast/reflective/DummyInvoker.java b/src/test/java/com/github/shautvast/reflective/DummyInvoker.java deleted file mode 100644 index 3589ebd..0000000 --- a/src/test/java/com/github/shautvast/reflective/DummyInvoker.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.github.shautvast.reflective; - -@SuppressWarnings("ALL") -public class DummyInvoker extends AbstractInvoker { - - public Object invoke(Object instance, Object... arguments) { - ((ReflectiveTest.Dummy) instance).setByteArrayValue((byte[][])arguments[0]); - return null; - } -} diff --git a/src/test/java/com/github/shautvast/reflective/array/ArraysTest.java b/src/test/java/com/github/shautvast/reflective/array/ArraysTest.java index d11891b..0d730e1 100644 --- a/src/test/java/com/github/shautvast/reflective/array/ArraysTest.java +++ b/src/test/java/com/github/shautvast/reflective/array/ArraysTest.java @@ -2,30 +2,92 @@ package com.github.shautvast.reflective.array; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; public class ArraysTest { @Test - void test1Dim() { - Object o = ArrayFactory.newArray(String.class, 1); - assertTrue(o instanceof String[]); + void testCreate1DimShortArray() { + Object o = ArrayFactory.newInstance(short.class, 1); + assertTrue(o instanceof short[]); } @Test - void test2Dims() { - int[][] ints = (int[][])ArrayFactory.newArray(int[].class, 1); + 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 test3Dims() { - String[][][] array = (String[][][]) ArrayFactory.newArray(String.class, 6, 7, 8); + 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