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.
Related
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()
I'm loading a class with following statement:
Class classToLoad = Class.forName("com.somePackage.SomeotherPackage.classname" );
Later i wd use reflection to get the methods of this class. now for invoking the methods with methodname.invoke() function i'd require the object of the loaded class. thus i want to create the object of the loaded class. I try to do it this way:
Object obj = classToLoad.newInstance();
but the problem in this is that this way i don't get the object of the class loaded but i get object of Object class.
Now if i want to call the functions of the loaded class, i do it like:
methodName.invoke(obj);
it throws an exception:
java.lang.IllegalArgumentException: object is not an instance of declaring class
can anybody please help?
Update on the problem:
The problem is that i need the left hand side of the assignment to be of a different class type and that class type will be decided on run time
For the below statement:
Object instance = clazz.newInstance();
"instance" should be of the "clazz" type and not the "Object" class.
How can i achieve this?
It works fine when everything's set up correctly:
import java.lang.reflect.Method;
class Foo {
public Foo() {
}
public void sayHello() {
System.out.println("Hello");
}
}
public class Test {
public static void main (String[] args) throws Exception {
Class<?> clazz = Class.forName("Foo");
Method method = clazz.getMethod("sayHello");
Object instance = clazz.newInstance();
method.invoke(instance); // Prints Hello
}
}
My guess is that the method you've fetched (methodName) wasn't actually fetched from classToLoad.
You can also just cast the return type and invoke the method directly.
public class Foo{
void HelloReflection(){
System.out.println("Hello reflection");
}
public static void main(String[] args){
try{
Foo o = (Foo) Class.forName("Foo").newInstance();
o.HelloReflection();
}catch(Exception e){
e.printStackTrace();
}
}
}
java.lang.IllegalArgumentException: object is not an instance of declaring class
This can be thrown if the method has no arguments and not found in your object's class. Probably You are calling the invoke method on the wrong object or your fetched method is wrong for your object.
The problem is that i need the left hand side of the assignment to be of a different class type and that class type will be decided on run time. ... How can i achieve this?
Use some language other than Java. Java is statically typed, which basically means you're not allowed to do exactly what you just asked how to do. The other answers here correctly show how to invoke a method without knowing the type of an object at compile time, but you'll never be able to set the type of a variable at runtime.
I have methods like this:
public File method1(){
method2()
}
public method2(){
do something..
and get method1 return type(in this case File)
}
How do I get it? i tried like this..
Throwable t = new Throwable();
StackTraceElement[] elements = t.getStackTrace();
and get all the methods for the elements. And after that, getReturnType, but it doesn't work. I also tried
public File method1(){
method2(this.getClass());
}
public method2(Class<?> className){
//problem here
}
But here the problem is that i can't compare two elements, the one on the stack and the one from classname.getMethods().
Is there any way that I can send method return type to a method2? I need this because of making some history-like log. I know it can be done with aspectJ but I have to do it somehow like this.
EDIT:
The main problem I have is that I can get stack output, and see the method who called my method2 - that's one fragment I need! Also I need that method's return type, but the stack doesnt hold that information. Now, I can get all the methods from the class where the "method who called method2" is. The list of those methods, hold everything, return type, input parameters.. but that's a pretty big list, 63 methods. So I have to compare them somehow to find out which one is the one FROM STACK. I can't comapre them using name, because some differ with return type, hashcode is different - that's where I'm stuck.
Update
If you really need to do this from a stack trace (which I would strongly recommend avoiding), I don't think you can. The stack trace can tell you the class and method names, but it doesn't include the method's argument types, and so if the method is overloaded you can't tell which one called method2.
I recommend you revisit your design. If method2 needs to know the return type of the method that calls it, then the method in question should pass that information into method2. Attempting to gather that information from a runtime stack is not only inefficient, but it's a design red flag.
Example:
public File method1(File f) {
// ...
method2(File.class);
}
public String method1(String s) {
// ...
method2(String.class);
}
public Foo method1(Foo f) {
// ...
method2(Foo.class);
}
There we have three overloads of method1. This is not a problem for method2, because each of them tells method2 what its return type is — or more accurately, I hope, what it needs method2 to create for it or whatever.
Original answer
For the specific case you list (esp. toward the end of your question), you can do this:
public File method1(){
method2(File.class);
}
File.class is the Class instance for the File class.
For the general case of finding the type of the return value of a method in a class, you can use the reflection API. Get the Class instance for the class containing the method via Class.forName, look up the method on that Class instance using Class#getMethod, then use Method#getReturnType on that Method to find out the return type's class.
Why is it so difficult with reflection?
public File method1() {
method2()
}
public void method2() {
Class<?> returnType = this.getClass().getMethod("method1").getReturnType();
}
Of course, you'll have to handle the exceptions though.
If the class you are returning has an empty constructor, you could build a instance of the return type locally in method2() and use that, but that is dangerous and not generic.
You could do x.getClass().getName() and perform a switch operation.
What I would suggest, though, is that you consider rearchitecting this to use AspectJ and put a cut point in your parent call to collect the information you really want before you get too low in the stack. I'm guessing a little bit as to your intent, but any time you are parsing the stack output for type information I think the design deserves a second look.
Updated answer
Using combination of StackTrace and Reflection
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Vector;
public class CallingMethodReturnType
{
public static void main( String[] args )
{
CallingMethodReturnType app = new CallingMethodReturnType();
app.method1();
app.method3();
}
public File method1(){
method2();
return null;
}
public ArrayList method3(){
method4();
return null;
}
public Vector method4() {
method2();
return null;
}
public void method2(){
Method method;
try {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
StackTraceElement ste = stackTraceElements[2];
String callerMethodName = ste.getMethodName();
method = this.getClass().getMethod(callerMethodName, null);
Class returnType = method.getReturnType();
System.out.println(returnType);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
Also check question How do I find the caller of a method using stacktrace or reflection? if you are concerned with performance.
Original answer
You can use reflection API like this
public method2(){
//do something and get method1 return type(in this case File)
Method method = this.getClass().getMethod("method1", null);
Class returnType = method.getReturnType();
}
I wish to initialize an array of java methods in the child class, as a class field like so
void callme() {System.out.println("hi!");}
Method[] actions = new Method[] {&callme,&callme};
and call all methods in this array at parent class like so:
for (meth:actions) {meth.invoke();}
However currently I cannot find a way to implicitly initialize the actions array, not through the constructor. The following gives me an error due to unhandled exception:
Method[] actions = new Method[] {
this.getClass().getDeclaredMethod("count")
};
As said, I cannot catch the exception when initializing this array explicitly as a field, and not in the constructor.
I'm a newbie to java reflection, so this is probably an obvious question, still I found no answer to that at google, any help would be appreciated.
Thanks
P.S.
As Scott below guessed, I "want a superclass to call a specific set of methods defined in a subclass".
Are you sure reflection is the right thing to do? Normally an interface with several anonymous classes implementing it would be better style.
You can write an initializer block to be able to catch the exception during initialization.
Why don't you use getMethod()?
[Note: code below has not been compiled but should get the idea across]
I should echo -- what are you trying to accomplish?
If you want a superclass to call a specific set of methods defined in a subclass, you can do a few things.
With reflection, I'd recommend using annotations:
1) define an annotation HeySuperclassCallMe (make sure retention is RUNTIME)
2) annotate the methods to call with HeySuperclassCallMe
#HeySuperclassCallMe public void foo...
3) in your superclass do something like
for (Method m : getClass().getMethods())
if (m.getAnnotation(HeySuperclassCallMe.class) != null)
m.invoke(...)
That's a nice reflective means to do it.
For non-reflection (which should be a bit faster, but more code):
1) define an interface that represents the calls
public interface Call {
void go();
}
2) in your superclass, define a
private List<Call> calls
protected void addCall(Call call)
3) in the subclass, use addCall:
addCall(new Call() {public void go() {foo();}} );
4) in the superclass
for (Call call : calls)
call.go();
Check out the Apache Commons - Beanutils! It's like a wrapper around all the reflection which is very easy to use. It wraps method invocation, modify attributes, lookups...
If you want to bring in dynamic to Java, you should have a look a dynamic JVM languages which can be used by simple including a .jar library! On of them is Groovy which contains the java syntax and bring in a lot of dynamic functionality (scripting, rapid-prototyping, Meta-Object-Protocol, runtime-method repacement, dynamic proxies...).
This should work as long, as your method is really declared in in the this.getClass().
If it is inherited, you should use Class.getMethod() instead.
However, instead of using function pointers, in java one would define an interface with a method one want to call, and let that interface be implemented by the target object.
Also consider using ArrayList, or other collection classes instead of arrays.
I can tell by your ampersands that you are thinking in C. We don't really use pointers to functions in java.
Generally, you would not use java reflection for this. As one of the other posters said - you would create an interface, and have objects that implemented that interface - either by directly implementing it, or with an adapter or anonymous class:
interface Callable { void callme(); }
Callable[] foo = new Callable[] {
new Callable() { public void callme() {System.out.println("foo!");}},
new Callable() { public void callme() {System.out.println("bar!");}}
};
for(Callable c: foo) {
c.callme();
}
Create a static method in your class which will return an array of declared methods and do the correct handling of exceptions.
private static Method[] declaredMethods(Class<T> clazz, String methodName) {
Method[] result = new Method[1];
try{
result[0] = clazz.getDeclaredMethod(methodName);
} catch (NoSuchMethodException nsme) {
// respond to the error
} catch (SecurityException se) {
// Respond to the error
}
return result;
}
Method[] actions = declaredMethods("count");
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);
}
}
}