API reflection confusion - java

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.

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.

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();
}

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

Related

How do I use a method of a class that I got via Class.forName(String)?

I need to use a method from a class that I obtained via the Class.forName() method. I'll give you an example:
public class Greeter {
public String getGreeting() {
return "Hello World!";
}
}
Now I want to dynamically obtain this class using a string and use it's method like so:
Class c = Class.forName("Greeter");
System.out.println(c.getGreeting());
Now this obviously didn't work, because Java doesn't recognize the class as a Greeter class yet. How would I go about doing this without having to hard-code the fact that it's a Greeter class?
Not directly, you would need an instance of the Class in order to invoke the method. For example,
Class<?> cls = Class.forName("Greeter");
try {
Object o = cls.getConstructor(null).newInstance(null);
System.out.println(((Greeter) o).getGreeting());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
You mention in the comments that you don't "know" it's a Greeter. You should program to a common interface, but failing that; it's possible to get the method by name as well. For example,
Object o = cls.getConstructor(null).newInstance(null);
Method m = cls.getMethod("getGreeting", null);
System.out.println(m.invoke(o, null));
If you want to use methods of a class without knowing what the class is at compile time, you can use reflection:
Class<?> clazz = Class.forName("Greeter");
Object obj = clazz.getConstructor().newInstance(); // Use default constructor
Method method = clazz.getMethod("methodName",<array of class objects representing argument types>);
Object result = method.invoke(obj,<array of arguments>);
However as noted in the first answer, it is better to use a common interface instead of reflection.
Edit: looks like the other answer beat me to the punch.

Is there a way to check if a class has a method and then invoke it on an already existing instance of the object?

I have this odd case which I'd like to handle through reflection or some library, if possible.
Is there a way to check if a class has a method and then invoke it on an already existing instance of the object?
For example, let's say I have:
Foo foo = new Foo();
Foo has a close() method. Let's say I know that a lot of the classes will have a close() method but since they were poorly devised and are legacy that I cannot re-write, I would like to find out a generic solution to invoke a method I know they all have, despite them not inheriting from a base class or interface.
I would like to have a method in my FooHandling class that accepts initialized objects and invokes their close() method. The objects will by no means inherit from the same base class, so they're totally different in nature, but all have a method with the same name. So, in FooHandler I'd like to have something like this:
void coolGenericClosingMethod(Object o)
{
// 1) Check via reflection if the class `o` represents contains a `close()`
// 2) Invoke the method, if it exists, but on the passed in object `o`.
}
So is there some neat trick I could use on an already instantiated object and still do that?
Is there a way to check if a class has a method
Class#getMethods()
Returns an array containing Method objects reflecting all the public member methods of the class or interface represented by this Class object, including those declared by the class or interface and those inherited from superclasses and superinterfaces
Class#getMethod(String,Class...)
Returns a Method object that reflects the specified public member method of the class or interface represented by this Class object. The name parameter is a String specifying the simple name of the desired method.
Throws:
NoSuchMethodException - if a matching method is not found
Sample code:
class Foo {
public void close() {
System.out.println("close method is invoked");
}
}
Foo foo = new Foo();
try {
Method m = Foo.class.getMethod("close");
m.invoke(foo);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
output:
close method is invoked
Yes you could use reflection for this, something like this would do it
public static Object invokeIfExists(Object obj, String methodName,
Class<?>[] argTypes, Object[] args) throws IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
Method method = null;
Object result = null;
try {
method = obj.getClass().getMethod(methodName, argTypes);
} catch(NoSuchMethodException | SecurityException e) {
// method not available in class or a security constrain has denied access
// ignore or at least do some loggin
}
if(method != null) {
result = method.invoke(obj, args);
}
return result;
}
The method to get the method object is Class#getMethod(String, Class...), it allows you to find the specific method you are looking for using it's signature (the formal parameter list) so among all overloaded methods you get exactly the one you need.
In all the exception thrown the one you might be the most interested in is InvocationTargetException which tells you that the method invoked has thrown an exception.
You could do what others have already answered, but there are some ready-made options if you do not want to mess too much with reflection. An example is Apache Commons BeanUtils:
import org.apache.commons.beanutils.MethodUtils;
...
try {
// 1st param: object reference
// 2nd param: method name
// 3rd param: args (null if no args)
MethodUtils.invoke(obj, "close", null);
} catch (NoSuchMethodException ex) {
// obj does not have a "close" method with no args
} catch (InvocatonTargetException ex) {
// obj.close() was called, and threw ex.getCause()
} catch (IllegalAccessException ex) {
// obj.close() exists, but you don't have permissions to invoke it
}
...
These libraries also tend to keep a method cache, so you get fast reflection; by caching you skip the slow part of reflection: method lookup.

Get reflection Constructor inside the Constructor itself

Let's say I have a class of Books which can be instantiate using a constructor like this:
class Book {
public Book(String name) {
Constructor<Book> cons = null;
try {
cons = Book.class.getConstructor(String.class);
} catch (NoSuchMethodException | SecurityException e) {
throw new RuntimeException(e);
}
//Additional detail. I will pass the 'cons' to Hibernate's constructor validation
}
}
Inside the constructor Book(String name), I have a need to get the reference to the constructor itself. But the problem is I have to wrap the statement with a pointless try-catch block as I know the constructor definitely exists and it sure is accessible. So I would like to know if Java provides a way to get the reference to the constructor inside itself without having to check for those Exceptions.
IMHO, you can't get rid of the try-catch.
The "class.getConstructor" is not sure about the availability of the constructor you are querying, so it doesnt matter whether you are sure about the availability or not.
However,you may try google reflections instead. Here is the javadoc
I didnot use it before, but I do see a method for getting all constructors. and there is no "throws"
public static Set<Constructor> getAllConstructors(Class<?> type,
com.google.common.base.Predicate<? super Constructor>... predicates)
get all constructors of given type, up the super class hierarchy, optionally filtered by predicates

Java Reflection, getMethod()

I'm working with the basics of Java reflection and observing information on methods of classes. I need to get a method that matches specifications as described by the getMethod() function. However, when I do this I get a NoSuchMethodException, and I was hoping you could tell me why my implementation is incorrect.
static void methodInfo2(String className) throws ClassNotFoundException,
NoSuchMethodException{
Class cls = null;
try{
cls = Class.forName(className);
} catch(ClassNotFoundException e){
e.printStackTrace();
}
System.out.println("Cls: "+cls);
Method method1 = cls.getMethod("test", null);
System.out.println("method1: "+method1);
}
EDIT1:When I print out "Cls: "+cls, the output is "Cls: class a8.myclass2". Why does it append the class part? (the a8 is correct, so don't worry about that) /EDIT1
This is the function I use to read in a class from my main function, and then I want to getMethod() with the parameters "test" and null, where "test" is the name of the method and null means the method has no parameters. The class I am reading in is called myclass2 which is here:
package a8;
public class myclass2 {
void test(){
//"takes no parameters"
//"returns bool"
//"name starts with test"
//return true;
}
}
As you can see, the method does infact exist in the class. If you could point out my mistake, I would really appreciate it.
Make your test method public. I believe Class.getMethod() is limited to public methods.
Without you posting the exact exception and your output, its hard to tell, but I suspect it is because the classes are in two separate packages, and since the default modifiers for a method are just protected it fails.
Use getDeclaredMethod() to get a method that isn't normally visible.

Why can't I use a try block around my super() call?

So, in Java, the first line of your constructor HAS to be a call to super... be it implicitly calling super(), or explicitly calling another constructor. What I want to know is, why can't I put a try block around that?
My specific case is that I have a mock class for a test. There is no default constructor, but I want one to make the tests simpler to read. I also want to wrap the exceptions thrown from the constructor into a RuntimeException.
So, what I want to do is effectively this:
public class MyClassMock extends MyClass {
public MyClassMock() {
try {
super(0);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// Mocked methods
}
But Java complains that super isn't the first statement.
My workaround:
public class MyClassMock extends MyClass {
public static MyClassMock construct() {
try {
return new MyClassMock();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public MyClassMock() throws Exception {
super(0);
}
// Mocked methods
}
Is this the best workaround? Why doesn't Java let me do the former?
My best guess as to the "why" is that Java doesn't want to let me have a constructed object in a potentially inconsistent state... however, in doing a mock, I don't care about that. It seems I should be able to do the above... or at least I know that the above is safe for my case... or seems as though it should be anyways.
I am overriding any methods I use from the tested class, so there is no risk that I am using uninitialized variables.
Unfortunately, compilers can't work on theoretical principles, and even though you may know that it is safe in your case, if they allowed it, it would have to be safe for all cases.
In other words, the compiler isn't stopping just you, it's stopping everyone, including all those that don't know that it is unsafe and needs special handling. There are probably other reasons for this as well, as all languages usually have ways to do unsafe things if one knows how to deal with them.
In C# .NET there are similar provisions, and the only way to declare a constructor that calls a base constructor is this:
public ClassName(...) : base(...)
in doing so, the base constructor will be called before the body of the constructor, and you cannot change this order.
It's done to prevent someone from creating a new SecurityManager object from untrusted code.
public class Evil : SecurityManager {
Evil()
{
try {
super();
} catch { Throwable t }
{
}
}
}
I know this is an old question, but I liked it, and as such, I decided to give it an answer of my own. Perhaps my understanding of why this cannot be done will contribute to the discussion and to future readers of your interesting question.
Let me start with an example of failing object construction.
Let's define a class A, such that:
class A {
private String a = "A";
public A() throws Exception {
throw new Exception();
}
}
Now, let's assume we would like to create an object of type A in a try...catch block.
A a = null;
try{
a = new A();
}catch(Exception e) {
//...
}
System.out.println(a);
Evidently, the output of this code will be: null.
Why Java does not return a partially constructed version of A? After all, by the point the constructor fails, the object's name field has already been initialized, right?
Well, Java can't return a partially constructed version of A because the object was not successfully built. The object is in a inconsistent state, and it is therefore discarded by Java. Your variable A is not even initialized, it is kept as null.
Now, as you know, to fully build a new object, all its super classes must be initialized first. If one of the super classes failed to execute, what would be the final state of the object? It is impossible to determine that.
Look at this more elaborate example
class A {
private final int a;
public A() throws Exception {
a = 10;
}
}
class B extends A {
private final int b;
public B() throws Exception {
methodThatThrowsException();
b = 20;
}
}
class C extends B {
public C() throws Exception { super(); }
}
When the constructor of C is invoked, if an exception occurs while initializing B, what would be the value of the final int variable b?
As such, the object C cannot be created, it is bogus, it is trash, it is not fully initialized.
For me, this explains why your code is illegal.
I can't presume to have a deep understanding of Java internals, but it is my understanding that, when a compiler needs to instantiate a derived class, it has to first create the base (and its base before that(...)) and then slap on the extensions made in the subclass.
So it is not even the danger of uninited variables or anything like that at all. When you try to do something in the subclass' constructor before the base class' constructor, you are basically asking the compiler to extend a base object instance that doesn't exist yet.
Edit:In your case, MyClass becomes the base object, and MyClassMock is a subclass.
I don't know how Java is implemented internally, but if the constructor of the superclass throws an exception, then there isn't a instance of the class you extend. It would be impossible to call the toString() or equals() methods, for example, since they are inherited in most cases.
Java may allow a try/catch around the super() call in the constructor if 1. you override ALL methods from the superclasses, and 2. you don't use the super.XXX() clause, but that all sounds too complicated to me.
I know this question has numerous answers, but I'd like to give my little tidbit on why this wouldn't be allowed, specifically to answer why Java does not allow you to do this. So here you go...
Now, keep in mind that super() has to be called before anything else in a subclass's constructor, so, if you did use try and catch blocks around your super() call, the blocks would have to look like this:
try {
super();
...
} catch (Exception e) {
super(); //This line will throw the same error...
...
}
If super() fails in the try block, it HAS to be executed first in the catch block, so that super runs before anything in your subclass`s constructor. This leaves you with the same problem you had at the beginning: if an exception is thrown, it isn't caught. (In this case it just gets thrown again in the catch block.)
Now, the above code is in no way allowed by Java either. This code may execute half of the first super call, and then call it again, which could cause some problems with some super classes.
Now, the reason that Java doesn't let you throw an exception instead of calling super() is because the exception could be caught somewhere else, and the program would continue without calling super() on your subclass object, and possibly because the exception could take your object as a parameter and try to change the value of inherited instance variables, which would not yet have been initialized.
One way to get around it is by calling a private static function. The try-catch can then be placed in the function body.
public class Test {
public Test() {
this(Test.getObjectThatMightThrowException());
}
public Test(Object o) {
//...
}
private static final Object getObjectThatMightThrowException() {
try {
return new ObjectThatMightThrowAnException();
} catch(RuntimeException rtx) {
throw new RuntimeException("It threw an exception!!!", rtx);
}
}
}

Categories