1

I am trying to write a java program where the user enters a testclass and then my program make sure it is a testclass. That is, checking for constructor without parameter, and testing the methods so that they are working (return true or false).

Now, what I am confused about is this API reflection. I am trying to follow the tutorial located at https://docs.oracle.com/javase/tutorial/reflect/index.html but I am getting confused and I am wondering if anyone could explain it and maybe help me get started. In the tutorial it says for example how to get the testclass, but you can do it in so many different ways. I tried using the

...
Class c = str.getClass();
...

where str is the name of the class I want to look at. How do I proceed from here to obtain information about the class's methods, constructor and their parameters? I simply just want examples and explaining. Not a fully written program. Thanks in advance.

Fjodor
  • 529
  • 1
  • 7
  • 19

3 Answers3

1

Firstly, using Class c = str.getClass(); won't do what you want. It will return the class of the str object, which is just String. What you should do instead is use Class.forName(str); note that this will require the fully qualified name of the class.

Once you have the class object, you can use it's methods to get the relevant information. It sounds like the most useful to you would be .getConstructors(). With that, you could use (for example) the .getParameterCount() method of the Constructors to find any constructors which take no parameters. For more information, I'd advice looking at the documentation.

resueman
  • 10,572
  • 10
  • 31
  • 45
0

You can just invoke the appropriate methods from the Class class found Here. Namely, getDeclaredFields() and getDeclaredMethods()

Zymus
  • 1,673
  • 1
  • 18
  • 38
0

Retrieving class

Class.forName(str) will return the class with the given name. You must pass the fully qualified name, like "org.example.MyTestSuite". In other use cases where you want to create another instance of a given object, you can just call Object#getClass().

Constructors and Instantiation

You can get all constructor with Class#getConstructors(), so that you could check if a nullary constructor (without parameters) is available. Class#newInstance() will try to create an instance with the nullary constructor and throw an IllegalAccessException if none is available. Constructors with parameters can be invoked with Constructor#newInstance(Object...).

Methods

A class' methods will be listed with Class#getDeclaredMethods(). For further examination Method#getGenericParameterTypes() returns the parameters' classes. You can even make private methods invokable by using Method#setAccessible(true). Then finally Method#invoke(Class) executes the method on the given class instance. Use Method#invoke(Class, Object...) for methods with arguments, whereas the var-args represents the arguments.

Example

The Java Documentation contains some good examples, I modified one a little bit for your use case:

try {
    // retrieving class
    Class<?> c = Class.forName(str);

    // will throw IllegalAccessException if the class
    // or its nullary constructor is not accessible:
    Object t = c.newInstance();

    Method[] allMethods = c.getDeclaredMethods();
    for (Method m : allMethods) {
        String mname = m.getName();

        // run only test methods
        if (!mname.startsWith("test")) {
            continue;
        }

        Type[] pType = m.getGenericParameterTypes();
        if (pType.length != 0) {
            throw new RuntimeException("Test methods must not have parameters.");
        }

        try {
            // you can call private methods by setting this flag
            m.setAccessible(true);

            // invoking method m of instance t
            m.invoke(t);

        } catch (InvocationTargetException x) {
            // Handle any exceptions thrown by method to be invoked.
            Throwable cause = x.getCause();
            err.format("invocation of %s failed: %s%n",
               mname, cause.getMessage());
        }
    }

    // production code should handle these exceptions more gracefully
} catch (ClassNotFoundException x) {
    x.printStackTrace();
} catch (InstantiationException x) {
    x.printStackTrace();
} catch (IllegalAccessException x) {
    x.printStackTrace();
}
Christian Strempfer
  • 7,291
  • 6
  • 50
  • 75
  • How do I do if I don't want instead of "Handle any exceptions thrown by method to be invoked" and instead it would print that the method failed and print the exception? – Fjodor Nov 18 '14 at 15:40
  • @Fjodor: You have to print it in a catch block, and the example exactly does print the method and the exception. You could add the stacktrace of you want. What happens in the catch block has nothing to do with reflection. – Christian Strempfer Nov 18 '14 at 15:46
  • Okay, thanks. And if there's a method in the class that I want to call everytime, with the name "hello" (it doesn't have to exist). Can I somehow save this method in a variable so that incase that method exists, I invoke it every time before the other method? – Fjodor Nov 18 '14 at 16:07
  • @Fjodor: Sure. Look at the loop, it's storing a method in variable `m`. You can pass it around as any other Java object. – Christian Strempfer Nov 18 '14 at 16:15
  • @Fjodor: If you have problems besides reflection, you should ask another question. See this for the stacktrace problem: [http://stackoverflow.com/q/1149703/199048](http://stackoverflow.com/q/1149703/199048). – Christian Strempfer Nov 18 '14 at 18:20
  • Okay, sorry. Just one more thing, if I try to print the exception now. It always says InvocationTargetException but different methods will generate different exceptions and I want to print out if it's a nullPointerException or something else. To make it more specific – Fjodor Nov 18 '14 at 18:26
  • @Fjodor: Try `x.getCause().printStacktrace()`. InvocationTargetException just wraps the real exception. ([More details](http://stackoverflow.com/q/6020719/199048)) – Christian Strempfer Nov 18 '14 at 18:39
  • It works that it prints out the right exception. But I am having problem with printing it in my jtextarea.append(...); – Fjodor Nov 20 '14 at 08:59
  • @Fjodor: Please ask that in a new question, it's easier than discussing it in comments, and you'll get an answer faster. – Christian Strempfer Nov 20 '14 at 12:37