How can I invoke a method with parameters using reflection ?
I want to specify the values of those parameters.
Here's a simple example of invoking a method using reflection involving primitives.
import java.lang.reflect.*;
public class ReflectionExample {
public int test(int i) {
return i + 1;
}
public static void main(String args[]) throws Exception {
Method testMethod = ReflectionExample.class.getMethod("test", int.class);
int result = (Integer) testMethod.invoke(new ReflectionExample(), 100);
System.out.println(result); // 101
}
}
To be robust, you should catch and handle all checked reflection-related exceptions NoSuchMethodException, IllegalAccessException, InvocationTargetException.
To call a class method using reflection is very simple.
You need to create a class and generate method in it. like as follows.
package reflectionpackage;
public class My {
public My() {
}
public void myReflectionMethod() {
System.out.println("My Reflection Method called");
}
}
and call this method in another class using reflection.
package reflectionpackage;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectionClass {
public static void main(String[] args)
throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class c=Class.forName("reflectionpackage.My");
Method m=c.getDeclaredMethod("myReflectionMethod");
Object t = c.newInstance();
Object o= m.invoke(t);
}
}
Find more details here.
You can use getClass in any Object to discover its class. Then you can use getMethods to discover all the available methods. Once you have the correct method you can call invoke with any number of parameters
this is the easiest way I know of, it needs to be surrounded with try & catch:
Method m = .class.getDeclaredMethod("", arg_1.class, arg_2.class, ... arg_n.class);
result = () m.invoke(null,(Object) arg_1, (Object) arg_2 ... (Object) arg_n);
this is for invoking a static method, if you want to invoke a non static method, you need to replace the first argument of m.invoke() from null to the object the underlying method is invoked from.
don't forget to add an import to java.lang.reflect.*;
Related
I want to create dynamic object so that I call the respective method of the class. All classes and interface is in different file but under the same folder
Given:
interface Method
{
public void display();
}
class Car implements Method
{
public void display()
{
System.out.print("Car method");
}
}
class Honda implements Method
{
public void display()
{
System.out.print("Honda method");
}
}
public class Main {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
String className = "Car";
Class cls = Class.forName(className);
Method method = (Method) cls.getConstructor().newInstance();
method.display();
}
}
Now if pass Honda in the string then I want to string method to get called but if I pass Car in string then I want to get Car method as an output but after compilation this method is not getting called. There is no error but no expected output as well. How to get the desired output. Please help.
You can invoke the desired method.
Method method = cls.getMethod("display");
method.invoke(parameters);
If I am allowed to update above code, it would be something like below,
interface Car
{
public void display();
}
class Honda implements Car
{
public void display()
{
System.out.print("Car method");
}
}
public class Main {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
String className = "Car";
Class cls = Class.forName(className);
Honda honda = (Honda)cls.newInstance()
honda.display();
}
}
Hopefully this will clear the things about the Method class I mentioned in above answer.
The method class.newInstance() has been deprecated. So you should use
Class<?> clazz = Class.forName(className);
Constructor<?> ctor = clazz.getConstructor(String.class).newInstance();
Object object = ctor.newInstance(ctorArgument);
SN: In this case I assumed the constructor had only one String parameter value. the getConstructor method must be called passing all the class types (correctly ordered) that the desired constructor has.
While with newInstance you need to pass the actual constrctor's args' values
At this point you have to get the method with getMethod() which requires both the method name and all the arguments' types. To actually invoke the method, you pass the instance of the object of which to call the method (in this case our object and passing the actual parameters' values to call it with
clazz.getMethod("methodName", String.class, String.class).invoke(object, "parameter1", "parameter2");
EDIT: The OP updated the question implementing a common interface by both classes. In this case you can actually call the method that you KNOW will have every class implementing that interface. This way you don't have to use any reflections magic except for creating the new instance of the object itself
With the common interface it'd be
Method method = (Method) Class.forName(className).getConstructor().newInstance();
method.display();
The last line will call the display method of the object instance that is implementing the interface
I wanted to check if a method uses recursion. So I wrote this mock up:
public class Main {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method method = Child.class.getMethod("toBeTested", int.class);
Object result = method.invoke(Super.class, 5);
System.out.println((Integer) result);
}
}
public class Super extends Child{
public static int toBeTested(int a){
System.out.println("validating recursion");
return Child.toBeTested(a);
}
}
public class Child {
public static int toBeTested(int a){
if(a==0)return 0;
return toBeTested(a-1)+1;
}
}
So I tried executing the method in Child with the Context of Super.class hoping in the recursion it would call the Super::toBeTested and I could hence validate the method uses recursion.
Is this even possible the way I tried? If no why not? Any other ideas to check foreign code for recursion...
No, you can't do that because that's not how static methods work, they don't have a "context" that decides what they call at runtime, it's decided at compile time (unless you want to call the classloader the context).
If it was a non-static method then you could do this:
public static class Child extends Super {
public int toBeTested(int a){
System.out.println("validating recursion");
return super.toBeTested(a);
}
}
public static class Super {
public int toBeTested(int a){
if(a==0)return 0;
return toBeTested(a-1)+1;
}
}
public static void main(String args[]) throws Exception {
Method method = Super.class.getMethod("toBeTested", int.class);
Object result = method.invoke(new Child(), 5);
System.out.println((Integer) result);
}
and it would print validating recursion 6 times because the method to be called depends on the runtime type of the object.
To check if static methods call themselves you could read the bytecode of the method (if you have access to it).
In Java, is it possible to access class defined in method by some means (reflections or so)? And How?
For example, i want to create instance of InnerClass in example below:
class Example {
public void outerMethod() {
class InnerClass {
double d = 0;
}
}
public void testMethod() {
outerMethod::InnerClass instance = new outerMethod::InnerClass();
}
}
Thanks for answers.
Technically it is possible.
Practically this is a kind of a hack and you should avoid such practice in the production code.
Example:
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
class Example {
public void outerMethod() {
class InnerClass {
private double d = 7.62;
#Override
public String toString() {
return String.format("[%s] d = %f", this.getClass().getName(), d);
}
}
}
public void testMethod() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
final Class<?> clazz = Class.forName("Example$1InnerClass");
final Constructor<?> constructor = clazz.getDeclaredConstructor(Example.class);
constructor.setAccessible(true);
final Object instance = constructor.newInstance(this);
System.out.println(instance);
}
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Example instance = new Example();
instance.testMethod();
}
}
Here we first get Class<?> for our local class by their name.
The local class name generation rules is a compiler implementation detail and may vary. AFAIK javac and ECJ use different approaches.
Then we get constructor of our class of interest via reflection.
Since class does not define constructor explicitly compiler generate it automacically and this constructor is not public. So we use getDeclaredConstructor() method here.
Since this class is not static (local classes cannot be defined static) the first and the only parameter of constructor is outer class reference. Example in our case.
After that we creating instance of a class by calling constructor.newInstance(this)
this is passed as a parameter to the constructor. See note above about constructor parameters.
Finally, we print just created object implicitly invoking InnerClass::toString()
No, that is not possible. Names declared inside a method can only be referenced inside the method itself. Local classes (which your case is an example) are defined in section 14.3 of the Java 8 Language Specification.
https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-Block.
I am trying to cast a class that I dynamically obtain that has implemented an interface. I have tried the following below but it doesn't seem to work. How I achieve this.
public InterfaceX test(){
InterfaceX x = null;
Class<?> classX = Class.forName("com.TestClassX");
x = (InterfaceX) classX;
return x;
}
EDIT:
I dont want to create an instance, since I am just looking to simply call a static method defined by the interface.
If x is a Class object, you cannot do x.staticMethod(). However, this is possible using reflection.
public interface Interface {
static void method() {
System.out.println("Hello, World!");
}
}
Then, in the main class you can do this.
import java.lang.reflect.*;
public class Main {
public static void invokeMethod(String className) {
try {
Class<?> clazz = Class.forName(className);
Method method = clazz.getDeclaredMethod("method");
method.invoke(null); // null is used for static methods. For instance methods, pass the instance.
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
invokeMethod("Interface");
}
}
This works, but you should generally try to avoid using reflection (anything in java.lang.reflect). Most of the time there is a better solution to the problem you are trying to solve.
I want to call a method by using a string. I get that this is possible; from what I understand reflection is the way to go. However, I'm having a hard time getting it to work and this is what I want.
For instance:
String method ="punch";
int punch(){
return 1;
}
I want to call the method by the string name. Can someone show me an example?
public class foo {
String method ="punch";
int punch() {
return 1;
}
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class<?> myClass = Class.forName("foo");
Method myMethod = myClass.getMethod("punch");
Object retObject = myMethod.invoke(null);
}
}
What do I need to do so that I can get the number 1?
Object retObject = myMethod.invoke(null);
That would only work for a static method.
For an instance method, you need to pass in the instance that you want to invoke the method on.
Object retObject = myMethod.invoke(instanceOfFoo);
Also, the method may need to be public (or be made accessible separately).