Java Instantiate Class at run time with parameters

I use an abstract factory to return instances of specific subclasses. I would like to instantiate subclasses at runtime, given the string of the concrete class name. I also need to pass the parameter to the constructors. The structure of the class is as follows:

abstract class Parent { private static HashMap<String, Child> instances = new HashMap<String,Child>() private Object constructorParameter; public static Child factory(String childName, Object constructorParam){ if(instances.keyExists(childName)){ return instances.get(childName); } //Some code here to instantiate the Child using constructorParam, //then save Child into the HashMap, and then return the Child. //Currently, I am doing: Child instance = (Child) Class.forName(childClass).getConstructor().newInstance(new Object[] {constructorParam}); instances.put(childName, instance); return instance; } //Constructor is protected so unrelated classes can't instantiate protected Parent(Object param){ constructorParameter = param; } }//end Parent class Child extends Parent { protected Child(Object constructorParameter){ super(constructorParameter); } } 

My attmept above throws the following exception: java.lang.NoSuchMethodException: Child.<init>() , followed by a stack trace.

Any help is appreciated. Thanks!

+6
source share
2 answers
 Constructor<?> c = Class.forName(childClass).getDeclaredConstructor(constructorParam.getClass()); c.setAccessible(true); c.newInstance(new Object[] {constructorParam}); 

The getConstructor method takes Class arguments to distinguish between constructors. But it only returns public constructors, so you need getDeclaredConstructor(..) . Then you will need setAccessible(true)

+13
source

Error: you call the wrong constructor - and the compiler cannot help you.

The problem you are facing is that you were accessing the constructor with a null argument, not the argument with the arguments. Remember that constructors in java are ultimately just methods, albeit special ones - and with reflection all bets are disabled --- the compiler will not help you if you do something stupid. In your case, you had a problem with the scope, as well as a problem with the method signature at the same time.

How to solve this problem and NEVER have to deal with it again in this application

It is a good idea to wrap the constructor calls in a static helper method that can be directly tested and then explicitly test them in my unit tests, because if the constructor changes and you forget to update the reflection code, you will again see that these critical errors are creeping again.

You can also just call the constructor as follows:

 public static Child create(Integer i, String s) throws Exception { Constructor c = Class.forName(childClass).getConstructor(new Object[]{Integer.class, String.class}); c.setAccessible(true); Child instance = (Child) c.newInstance(new Object[]{i , s}) ; return instance; } 

and of course add to your tests

  @Test public void testInvoke() { try{ MyClass.create(1,"test"); } catch(Exception e) { Assert.fail("Invocation failed : check api for reflection classes in " + MyClass.class); } } 
+3
source

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


All Articles