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).
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 want to create some utility method and I want it to be able to work on different objects as long as they can provide an Integer property that is read/write.
I know the "Standard" way would be to:
declare some interface IProvidesAccessToInteger that has setInteger and getInteger.
declare MyUtility.doSomethingWonderful(IProvidesAccessToInteger obj)
make calls to obj.setInteger and obj.getInteger.
But this has a very strong downside that it requires the cooperation of all those classes that I want MyUtility to work with and not only that but even if some class wants to cooperate MyUtility would still only be able to .doSomethingWonderful() to just a single predetermined field of that classes.
I am looking for some syntax that would allow for something like MyUtility.doSomethingWonderful(T obj, Method<Integer> getter, Method<Integer,Integer> setter) maybe using generics somehow to specify the requirement that objhas two methods that get set and set an Integer and have some way to call them on the instance of obj.
It might also be interesting to do something similar with static methods that do not need an object.
UPDATE:
As I was pointed to reflection, I want to clarify that I know close things can be done using reflection.
However since I don't need to resolve the actual interface in runtime I had the hope that JAVA has some way to specify sort of an "Interface fulfilment map" such that If my requirement would be an object that has two methods int ?() and void ?(int) I could specify something like .doSomethingWonderful(?<int getter(),void setter(int)> obj) and call it once with some object1 that has int getInt() and void setInt(int) and once with some other object2 that has int getIntValue() and void setIntValue(int) by specifying in the calls that object fulfills the requirements for getInteger by getInt and fulfills the requirements for setInteger by setInt and so on. maybe with a call syntax like `.doSomethingWonderful((?)object1)
At least in theory I think it should be possible to do all at compile time and not require any runtime reflection.
maybe the right name for this would by an anonymous interface.
that said, I accept that a runtime solution via reflection might also be a solution.
The thing closest to your description will come with Java 8. You still need interfaces but the caller does not need to care about them and even better, there are plenty of default interfaces for typical tasks. For example, you can define a method like this:
static void increment(IntSupplier in, IntConsumer out)
{
out.accept(in.getAsInt()+1);
}
and use it like that to access different properties of an object:
class ClassWithInProperties {
int a, b;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public int getB() {
return b;
}
public void setB(int b) {
this.b = b;
}
#Override
public String toString() {
return "a="+a+", b="+b;
}
}
ClassWithInProperties obj=new ClassWithInProperties();
increment(obj::getA, obj::setA);
increment(obj::getA, obj::setA);
increment(obj::getB, obj::setB);
System.out.println(obj);
or with static methods:
public class Test {
static int DATA = 42;
static int getData() {
return DATA;
}
static void setData(int i) {
DATA=i;
}
}
increment(Test::getData, Test::setData);
System.out.println(DATA);
Your getter and setter are pretty Paradigm of reflection. But that would be import much risk and lose performance. Interface Oriented Programming are pretty common "standard" to handle this scenario.
You cannot do this with generics.
You can do this with reflection. Using a utility such as BeanUtils would of course be easier, but you can write it by hand too.
public void doSomethingWonderful(final Object in, final String fieldName)
throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
final String upperCased = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
final Method getter = in.getClass().getMethod("get" + upperCased);
final Method setter = in.getClass().getMethod("set" + upperCased, Integer.TYPE);
//to invoke getter
final int val = (int) getter.invoke(in);
//to invoke setter
setter.invoke(in, val);
}
I have assumed that you are using an int rather than an Integer, you will need to change the code slightly in the latter case.
You can see that it throws a massive number of exceptions, I would recommend wrapping them all in a custom exception type to simplify client code.
EDIT
Op wants the break down the method into three overloaded methods:
public void doSomethingWonderful(final Object in, final String fieldName)
throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
final String upperCased = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
doSomethingWonderful(in, "get" + upperCased, "set" + upperCased);
}
public void doSomethingWonderful(final Object in, final String getterName, final String setterName)
throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
final Method getter = in.getClass().getMethod(getterName);
final Method setter = in.getClass().getMethod(setterName);
doSomethingWonderful(in, getter, setter);
}
public void doSomethingWonderful(final Object in, final Method getter, final Method setter)
throws NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//to invoke getter
final int val = (int) getter.invoke(in);
//to invoke setter
setter.invoke(in, val);
}
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.*;