This program randomly instantiates any Object by recursively iterating through the parameters of a constructor until it finds a primitive or wrapper parameter that it can randomize. However, when a constructor takes a primitive array as a parameter, I get a
java.lang.IllegalArgumentException: argument type mismatch
.
I have poured through Stack Overflow and the internet, but can't seem to find out how to feed a wrapper array into a constructor or turn a wrapper array into a primitive array.
I have considered the following methods of fixing this, but I am not sure of how to implement them:
- Create a custom subclass of
java.lang.reflect.Constructor
and change thegetParameterTypes()
method so that if a given parameter is a primitive array (such asint[]
), change it toInteger[]
. I think this may have some adverse effects however.- Figure out how I can "add" items to
varargs
/ theObject[] parameterValues
iteratively so that I can inspect eachparameterValues[i]
as I come across it, see if it is a wrapper array, then change it to a primitive array. This brings up the problem that a primitive array, such as abyte[]
, cannot go into theparameterValues
that is fed into constructor.newInstance(parameterValues).
- Figure out how I can "add" items to
You may read all of the code if you'd like, however the two enums are not particularly relevant. The bulk of the action and my problem occurs in nextRandom(Class<?> cls)
and some of it in randomBase(BASE_TYPE baseType)
.
Code:
import java.lang.reflect.*;
import java.util.Random;
/**
* Sources used:
* http://ift.tt/2eEQN16
object-is-of-primitive-type
* http://ift.tt/2gTGqr9
contains-a-given-string
* http://ift.tt/2eEOA5C
random-number-in-java
*
* Created by Ward Bradt/ BlueOxile on July 22, 2017
* http://ift.tt/2gTeh3c
*/
public class RandomGenerator {
public enum BASE_TYPE {
INTEGER (int.class, Integer.class),
DOUBLE (double.class, Double.class),
FLOAT (float.class, Float.class),
LONG (long.class, Long.class),
SHORT (short.class, Short.class),
BYTE (byte.class, Byte.class),
BOOLEAN (boolean.class, Boolean.class),
CHAR (char.class, Character.class);
private final Class<?> primitiveClass;
private final Class<?> wrapperClass;
BASE_TYPE(Class<?> primitive, Class<?> wrapper) {
this.primitiveClass = primitive;
this.wrapperClass = wrapper;
}
public Class<?> getPrimitiveClass() {
return primitiveClass;
}
public Class<?> getWrapperClass() {
return wrapperClass;
}
}
public enum BASE_TYPE_ARRAY {
INTEGER (int[].class, Integer[].class, BASE_TYPE.INTEGER),
DOUBLE (double[].class, Double[].class, BASE_TYPE.DOUBLE),
FLOAT (float[].class, Float[].class, BASE_TYPE.FLOAT),
LONG (long[].class, Long[].class, BASE_TYPE.LONG),
SHORT (short[].class, Short[].class, BASE_TYPE.SHORT),
BYTE (byte[].class, Byte[].class, BASE_TYPE.BYTE),
BOOLEAN (boolean[].class, Boolean[].class, BASE_TYPE.BOOLEAN),
CHAR (char[].class, Character[].class, BASE_TYPE.CHAR);
private final Class<?> primitiveArrayClass;
private final Class<?> wrapperArrayClass;
private final BASE_TYPE baseType;
BASE_TYPE_ARRAY(Class<?> primitiveArray, Class<?> wrapperArray, BASE_TYPE b) {
this.primitiveArrayClass = primitiveArray;
this.wrapperArrayClass = wrapperArray;
this.baseType = b;
}
public Class<?> getPrimitiveClass() {
return baseType.getPrimitiveClass();
}
public Class<?> getPrimitiveArrayClass() {
return primitiveArrayClass;
}
public Class<?> getWrapperClass() {
return baseType.getWrapperClass();
}
public Class<?> getWrapperArrayClass() {
return wrapperArrayClass;
}
public BASE_TYPE getBaseType() {
return baseType;
}
}
public static Object nextRandom(Class<?> cls) throws IllegalAccessException, InvocationTargetException, InstantiationException {
// base case: primitive array or wrapper array
if (cls.isArray()) {
for (BASE_TYPE_ARRAY i : BASE_TYPE_ARRAY.values()) {
if (cls.equals(i.getPrimitiveArrayClass()) || cls.equals(i.getWrapperArrayClass())) {
// later: random wrapper of cls if primitive
// later: is slightly inefficient because we iterate over BTA.values() than iterate in
// randomBase using a switch statement.
return randomBaseArray(i);
}
}
}
// base case: if primitive or wrapper
else {
for (BASE_TYPE i : BASE_TYPE.values()) {
if (cls.equals(i.getPrimitiveClass()) || cls.equals(i.getWrapperClass())) {
// later: random wrapper array of cls
return randomBase(i);
}
}
}
Constructor<?> constructor = cls.getConstructors()[0];
Class<?>[] parameterTypes = constructor.getParameterTypes();
Object[] parameterValues = new Object[parameterTypes.length];
for (int i = 0; i < parameterValues.length; i++) {
// Recursively creates objects/ parameters for constructor
parameterValues[i] = nextRandom(parameterTypes[i]);
}
// ----------------------
// EXCEPTION THROWN HERE
// ----------------------
return constructor.newInstance(parameterValues);
}
public static Object randomBase(BASE_TYPE baseType) {
Random rand = new Random();
switch (baseType) {
case BYTE:
return randomByte();
case CHAR:
return randomChar();
case LONG:
return rand.nextLong();
case FLOAT:
return rand.nextFloat();
case DOUBLE:
return rand.nextDouble();
case SHORT:
return randomShort();
case BOOLEAN:
return rand.nextBoolean();
case INTEGER:
return rand.nextInt();
}
throw new IllegalArgumentException();
}
public static Object[] randomBaseArray(BASE_TYPE_ARRAY baseTypeArray) {
short srt = (short) (1 + new Random().nextInt(Short.MAX_VALUE));
Object arr = Array.newInstance(baseTypeArray.getWrapperClass(), srt);
for (int i = 0; i < Array.getLength(arr); i++) {
Array.set(arr, i, randomBase(baseTypeArray.getBaseType()));
}
return (Object[])arr;
}
public static Byte randomByte() {
byte[] b = new byte[1];
new Random().nextBytes(b);
return b[0];
}
public static Character randomChar() {
return (char)(new Random().nextInt(85) + 32);
}
public static Short randomShort() {
return (short) (Short.MIN_VALUE + new Random().nextInt(Short.MAX_VALUE * 2 + 2));
}
public static void main(String[] args) throws IllegalAccessException, InstantiationException, InvocationTargetException {
// I don't fully know how to use @SuppressWarnings yet, so most of my methods throw these exceptions^
String str = (String)nextRandom(String.class);
}
}
Aucun commentaire:
Enregistrer un commentaire