How to create a new instance of a class by passing Object [] instead of a list of parameters with reflection

Do you have any information on how to write such a method?

public abstract class AbstractClass{} public class TrialClass extends AbstractClass{ public TrialClass(final String a, final String b){} public TrialClass(final String a, final String b, final String c){} } public class getNewInstance(final Class<? extends AbstractClass> clazz, Object... constructorParameters){ //??? } TrialClass trialClass = getNewInstance(TrialClass.class, "A", "B"); 
+5
source share
2 answers

The Class method contains the getConstructor method, which takes an array of Class as a parameter that matches the constructor arguments. You must build this array from your parameters array.

Something like that:

 public <T> T getNewInstance(final Class<T> clazz, Object... constructorParameters) throws InstantiationException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException{ Class[] parameterTypes = new Class[constructorParameters.length]; for(int i = 0; i < constructorParameters.length; i++) { parameterTypes[i] = constructorParameters[i].getClass(); } Constructor<T> constructor = clazz.getConstructor(parameterTypes); return constructor.newInstance(constructorParameters); } 

Edit: as Codebender said, this does not work when a subtype is passed as an argument.

+2
source

Probably a more flexible approach is to check all the constructors and search for a compatible type:

 public static <T> T getNewInstance(final Class<T> clazz, Object... constructorParameters) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Constructor<?> candidate = null; for(Constructor<?> constructor : clazz.getConstructors()) { if(Modifier.isPublic(constructor.getModifiers()) && isConstructorCompatible(constructor, constructorParameters)) { if(candidate == null) candidate = constructor; else throw new IllegalArgumentException("Several constructors found which are compatible with given arguments"); } } if(candidate == null) throw new IllegalArgumentException("No constructor found which is compatible with given arguments"); return (T) candidate.newInstance(constructorParameters); } private static boolean isConstructorCompatible(Constructor<?> constructor, Object[] constructorParameters) { Class<?>[] parameterTypes = constructor.getParameterTypes(); if(parameterTypes.length != constructorParameters.length) return false; for(int i=0; i<parameterTypes.length; i++) if(!isParameterCompatible(parameterTypes[i], constructorParameters[i])) return false; return true; } private static boolean isParameterCompatible(Class<?> type, Object parameter) { if(parameter == null) return !type.isPrimitive(); if(type.isInstance(parameter)) return true; if(type.isPrimitive()) { if (type == int.class && parameter instanceof Integer || type == char.class && parameter instanceof Character || type == byte.class && parameter instanceof Byte || type == short.class && parameter instanceof Short || type == long.class && parameter instanceof Long || type == float.class && parameter instanceof Float || type == double.class && parameter instanceof Double || type == boolean.class && parameter instanceof Boolean) return true; } return false; } 

There are still open issues, such as varargs-constructors. Also, cases of ambiguity will not be resolved, as javac did (for example, if you have the constructor MyObj(Object) and MyObj(String) , you cannot use the latter, both are the same).

+3
source

Source: https://habr.com/ru/post/1236213/


All Articles