Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

getConstructor with no parameters

I can't seem to use getConstructor for constructors with no parameters.

I keep getting the following exception:

java.lang.NoSuchMethodException: classname.<init>()

Here is the code:

interface InfoInterface {
    String getClassName();
    String getMethodName();
    String getArgument();
}

class asa implements InfoInterface {
    @Override
    public String getClassName() {
        return ("jeden");
    }
    @Override
    public String getMethodName() {
        return ("metoda");
    }
    @Override
    public String getArgument() {
        return ("krzyk");
    }
}

class Jeden {
    Jeden() {
        System.out.println("konstruktor");
    }

    public void Metoda(String s) {
        System.out.println(s);
    }
}

class Start {
    public static void main(String[] argv) {
        if (argv.length == 0) {
            System.err.println("Uzycie programu: java Start nazwa_klasy nazwa_klasy2...");
            return;
        }

        try {
            for (int x = 0; x < argv.length; x++) {
                Class<?> c = Class.forName(argv[x]);
                InfoInterface d = (InfoInterface) c.newInstance();
                String klasa = d.getClassName();
                String metoda = d.getMethodName();
                String argument = d.getArgument();

                Class<?> o = Class.forName(klasa);
                // o.newInstance();

                Constructor<?> oCon = o.getConstructor();
                System.out.println("ASD");
                Class<?> p = (Class<?>) oCon.newInstance();
            }
        } catch (Exception e) {
            System.out.println(e);
        }

    }
}

o.newInstance(); prints "konstruktor" without problems.

like image 545
user3086720 Avatar asked Dec 20 '14 11:12

user3086720


4 Answers

The problem is clear when you read the javadoc of .getConstructor():

Returns a Constructor object that reflects the specified public constructor of the class represented by this Class object.

Emphasis mine.

In your code, the constructor is not public!

Example:

// Note: class is NOT public -- its default constructor won't be either
final class Test
{
    public static void main(final String... args)
        throws NoSuchMethodException
    {
        // throws NoSuchMethodException
        Test.class.getConstructor();
    }
}

Obligatory link to an SO answer which also gives the JLS reference. In particular, note that the default constructor has the same access modifier as the class.

like image 149
fge Avatar answered Oct 17 '22 02:10

fge


It seems as if your class provides a constructor that is NOT a default constructor. The call to getConstructor() without parameters requires the class to have a default constructor. The following test illustrates this.

import org.junit.Test;

public class ConstructorTest {
    public static class ClassWithParameterizedConstructor {
        public ClassWithParameterizedConstructor(final String param) {
            // A parameterized constructor, no default constructor exists
        }
    }

    @Test
    public void testFoo() throws NoSuchMethodException {
        // Parameterized constructor lookup works fine
        ClassWithParameterizedConstructor.class.getConstructor(String.class);

        // This doesn't work since there is no default constructor
        ClassWithParameterizedConstructor.class.getConstructor();
    }
}

So, a possible solution is to either change the call to getConstructor() to include the correct type or to provide a default constructor on the object itself (but why would you do that?).

like image 33
wassgren Avatar answered Oct 17 '22 00:10

wassgren


Read this: http://docs.oracle.com/javase/tutorial/reflect/member/ctorInstance.html

It seems that both classes Class and Constructor have the method newInstance the difference is that in the Class class you can only call newInstance with no arguments, so the called constructor must have an no arguments (this also brings a problem when you have more that one constructor). The methoe newInstance in the Constructor class allows you to call the constructor with arguments also, notice that you can also use the method getConstructors instead of getConstructor that returns you all the class constructors and allows you to call the constructor method you want.

In this case, since you only have one constructor only and with no arguments, Class.newInstance works fine. To use the getConstructor to have the same result you'll need to add in the end oCon.newInstance();

like image 42
Luis Alves Avatar answered Oct 17 '22 01:10

Luis Alves


You can use getDeclaredConstructors() which returns an array of Constructor objects reflecting all the constructors declared by the class represented by this Class object

class SomeClass{

    {
        System.out.println("I'am here!");
    }

}

public class Main {
    public static void main(String[] args) throws Exception{

        System.out.println(Arrays.toString(SomeClass.class.getDeclaredConstructors()));
        // returns public, protected, default (package) access, and private constructors

        // System.out.println(SomeClass.class.getConstructor());
        // in that case you got:
        // NoSuchMethodException: reflection.SomeClass.<init>()
        // because SomeClass don't have public constructor

        for (Constructor constructor : SomeClass.class.getDeclaredConstructors()){

            constructor.newInstance();
        }

    }
}

And if you have private constructor like this:

class SomeClass{

    private SomeClass(String val){
        System.out.println(val);
    }

}

You have to set accessible for constructor:

constructor.setAccessible(true);

And get something like this:

class SomeClass{

    private SomeClass(String val){
        System.out.println(val);
    }

}

public class Main {
    public static void main(String[] args) throws Exception{

        for (Constructor constructor : SomeClass.class.getDeclaredConstructors()){
            // constructor.newInstance("some arg");    // java.lang.IllegalAccessException
            constructor.setAccessible(true);
            constructor.newInstance("some arg");
        }

    }
}

Note: if your class declared as private his default constructor must be private too.

And be careful with nonstatic-inner classes, which receives an outer class instance

like image 38
Arthur Kupriyanov Avatar answered Oct 17 '22 02:10

Arthur Kupriyanov