1

I have a number of classes with constructors of different kind of perameters. I am getting the class I need to use as well as it's constructor from text as such:

"TheClassIWant parameter1 1234 parameter2 5678"

or:

"AnotherClass parameter1 3456"

I break the above string into a string with the class name ("TheClassIWant") and an array of parameters (p[]). Now I get the class using:

Class<?> cl = Class.forName("TheClassIWant")

and the constructor using:

Constructor<?>[] cons = cl.getDeclaredConstructors();

I can see the parameters of the constructor using:

Class<?>[] types  = cons[1].getParameterTypes();

How can I create a newInstance of the class when I have a number of constructor parameters that may vary each time? For example I could do this:

TheClassIWant cl = cons[1].newInstance(p[1],p[2],p[3],p[4]);

but the string "AnotherClass parameter1 3456" would cause an Exception in thread "main" java.lang.IllegalArgumentException: argument type mismatch

Jon Doe
  • 23
  • 5
  • A combination of your code and [this](https://stackoverflow.com/questions/3574065/instantiate-a-class-object-with-constructor-that-accepts-a-string-parameter) should help for parameters which are strings or a primitive type. – Andrew S Feb 14 '18 at 17:05

2 Answers2

0

The parameters passed to newInstance must fit the types of the constructor, so if there is a constructor

public TheClassIWant(String param1, int param2, String param3, int param4);

you need to call it

cons[1].invoke(p[1], Integer.valueOf(p[2]), p[3], Integer.valueOf(p[4]));

The exception you get is happening because you passed four Strings instead.

I'm not sure if there a general solution for this because there might be a class with two constructors:

public TheClassIWant(String param1, int param2, String param3, int param4);

and

public TheClassIWant(String param1, String param2, String param3, String param4);

Both "fit" and you can only guess which one is the correct one for that particular instantiation.

BTW: getDeclaredConstructors return the constructors in no specific order, so one day the first constructor might be returned and the second the day after that. Another reason why I doubt that you are having a working concept here.

Lothar
  • 5,323
  • 1
  • 11
  • 27
  • `you can only guess which one is the correct one` that's not true, you can `getParameterTypes()` to check a constructor's parameters' types. – cosh Feb 14 '18 at 17:36
  • @isaac Yes. And how do you know if `1234` is supposed to be a number or a text that happens to be a number to decide if you have to use the String-only constructor or the mixed types one? – Lothar Feb 14 '18 at 17:39
0

This is because newInstance method accept a various number of parameters, but they must be exactly of the type you get from getParameterTypes().

In your case you are passing String object to the constructor hence the IllegalArgumentException.

What you have to do is to parse the String arguments into the correct classes and then pass them to the constructor.

Using your example:

String[] tokens = "AnotherClass parameter1 3456".split(" ");
Object[] params = new Object[tokens.length-1];
Constructor c = Class.forName(tokens[0]).getDeclaredConstructors()[0];
Class<?>[] types  = c.getParameterTypes();
for (int i=0;i<params.length;i++) {
     params[0] = parse(tokens[i+1], types[i]);
}
Object obj = c.newInstance(params);

So the hard part is to code the method

private Object parse(String str, Class t);

for every parameter's class.

Also you cannot declare a variable of the class "AnotherClass" in your code, because you don't know what it is at runtime, so you have to use reflection to handle it.

Francesco Rogo
  • 343
  • 3
  • 13