i am trying to call a private method using java reflection i developed a small method to call the others methods iterating over all methods and comparing by name and by parameters type i have invoke 4 methods with success.
i have one question.
1). is this the best way to do it?. because i understand class.getMethod only match public methods. Java have something built-in?
here is my code.
public class Compute
{
private Method getMethod(Class clazz,String methodName,Class...parametersClass)
{
outer:
Method[] methods = clazz.getDeclaredMethods();
for(Method method:methods)
{
//comparing the method types... of the requested method and the real method.....
if(method.getName().equals(methodName) && parametersClass.length== method.getParameterTypes().length)//it a possible match
{
Class[]arrayForRealParameters = method.getParameterTypes();
//comparing the method types... of the requested method and the real method.....
for(int i=0;i<arrayForRealParameters.length;i++)if(!arrayForRealParameters[i].getSimpleName().equals(parametersClass[i].getSimpleName()))continue outer;
return method;
}
}
return null;
}
private Calendar getCalendar(){return java.util.Calendar.getInstance();}
private void methodByReflex(){System.out.println("Empty Parameters.");}
private void methodByReflex(Integer a,Integer b){System.out.println(a*b);}
private void methodByReflex(String a,String b){System.out.println(a.concat(b));}
public static void main(String[] args) throws Exception
{
Compute clazz = new Compute();
Class[]arrayOfEmptyClasses=new Class[]{};
Class[]arrayOfIntegerClasses=new Class[]{Integer.class,Integer.class};
Class[]arrayOfStringClasses=new Class[]{String.class,String.class};
Method calendarMethod=clazz.getMethod(clazz.getClass(),"getCalendar",arrayOfEmptyClasses);
Method emptyMethod=clazz.getMethod(clazz.getClass(),"methodByReflex",arrayOfEmptyClasses);
Method intMethod=clazz.getMethod(clazz.getClass(),"methodByReflex",arrayOfIntegerClasses);
Method stringMethod=clazz.getMethod(clazz.getClass(),"methodByReflex",arrayOfStringClasses);
System.out.println((calendarMethod==null)+" "+(emptyMethod==null)+" "+(intMethod==null)+" "+(stringMethod==null));//prints false false false false
Calendar cal = (Calendar)calendarMethod.invoke(clazz);
System.out.println(cal.getTime());//prints current time
stringMethod.invoke(clazz,"John ","Lennon");//Prints John Lennon
emptyMethod.invoke(clazz);//prints Empty Parameters.
intMethod.invoke(clazz,13,13);// prints 169
Integer a=10,b=10;
intMethod.invoke(clazz,a,b);//prints 100
}
}
any help is appreciate it.
thanks a lot.
You are getting a list of all the methods on a class with getDeclaredMethods. Try using the getDeclaredMethod (singular) method, which takes as a parameter the method name and a varargs argument for the classes of the parameter types. That should get you directly to the method so you don't have to iterate through all methods yourself.
Example:
clazz.getDeclaredMethod(methodName, parametersClass);
See how i invoke private method with parameters using java reflection API-
Here i have written a method named as executePrivateMethod like :
public Object executePrivateMethod(Class<?> clazz,String methodName,Class<?>[] parameterTypes,Object ... args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException, SecurityException, NoSuchMethodException{
//get declared Method for execution
Method pvtMethod = clazz.getDeclaredMethod(methodName,parameterTypes);
pvtMethod.setAccessible(true);
//invoke loadConfiguration() method and return result Object
return pvtMethod.invoke(clazz.newInstance(),args);
}
How to call:
//params
private Map<String, String> requestParams = new HashMap<String, String>();
requestParams.put("a","a");
requestParams.put("b","b");
requestParams.put("c","c");
requestParams.put("d","d");
//call
executePrivateMethod(JSGeneratorFacade.class,"testMethod",new Class<?>[]{Map.class},requestParams);
Related
I'm puzzled how Java polymorphism works.
In the case below, there are three polymorphism methods of showText, for distinguishing clearly, these methods names method-1, method-2, method-3. codes as below:
public class PolymorphismTest {
public static void main(String[] args) {
showText("def");
}
// method-1
private static void showText(Object abc) {
print("1.....");
showText(abc, "abc");
}
// method-2
private static void showText(Object abc, String item) {
// print(abc.getClass().getName());
print("2.....");
String text;
if (abc == null) {
text = null;
} else {
text = abc.toString();
}
showText(text, item);
}
// method-3
private static void showText(String abc, String item) {
print("3.....");
}
private static void print(String text) {
System.out.print(text);
}
}
method-1 has one parameter of type Object
method-2 has two parameters, the parameter type are Object and String
method-3 has two parameters, the same param count with method-2, while its first param type is String
The main() calls method-1 with a parameter of type String, in the body of method-1 it calls another method, which one is matched, method-2 or method-3?
I test it in java 8, the out put is
1.....2.....3.....
Overload is decided at compile-time, so when the first method gets the abc parameter it sees it as an Object (not a String) and calls method-2 which has the appropriate signature for it.
You are probably confused because this is different from the dynamic linking mechanism, which applies to class instances (objects) methods, and resolves the method at runtime based on the actual class of the instance on which the call is made (for example toString() in abc.toString()).
I need to send code to another method, as the number of methods in the class may change, I use reflection. But the problem is that I can not enumerate them in a loop benchmarkMethods.get(i).invoke(set, null);, because it is possible to me anonymous class can only pass final variable. What do I do in this case?
public void RunAllBenchmarks(final Object set, boolean randomOrder) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
final List<Method> benchmarkMethods = new ArrayList<Method >();
final Class benchClass = set.getClass();
Method[] methods = benchClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++){
Annotation[] annotations = methods[i].getAnnotations();
if (annotations.length != 0){
for (int j = 0; j < annotations.length; j++)
if (annotations[j].annotationType().toString().contentEquals("interface Benchmark"))
benchmarkMethods.add(methods[i]);
}
}
for (int i = 0; i < benchmarkMethods.size(); i++){
String name = null;
Method method = benchmarkMethods.listIterator().next();
MeasureAndRecord(name, new IFunc() {
#Override
public Object onEvent() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
return benchmarkMethods.get(i).invoke(set, null);
}
});
}
PrintWriter writer = new PrintWriter(System.out);
PrintResults(writer);
}
I thought I would add, there is a trick I use to pass non-final variables into an anonymous class. Taking a section of the code you wrote above, I've made some small changes to show how I do it.
I've assumed here measureAndRecord is a method (I've decapitalised the first character to signify that) and that IFunc is the class that you are creating an anonymous extension of. I've also assumed that Method method ... is supposed to be the method you want to pass to your anonymous class (because in your code it doesn't do anything).
The trick here is to add a new method called init which you can pass your variables to (final or non-final) and which returns this (which in this case is the anonymous class). What happens is the anonymous class is called, the init method is immediately called, and then the object (which is an IFunc as required) is returned and used.
You must call the init method upon construction (before assignment) and you cannot chain methods together in this way. The reason is once the object is returned from the first method call, it is an IFunc, not the anonymous subclass that you created, and so Java will no longer recognise anything but the overriden methods after that.
Anyway, have a play. I find it very handy, if a bit of a cheat. Even when Java 8 comes along and allows virtually final variables to be passed, this will still work with the variable variables.
...
for (int i = 0; i < benchmarkMethods.size(); i++) {
String name = null;
Method method = benchmarkMethods.get(i); // Assumption on my part
measureAndRecord(name, new IFunc() {
// Anonymous class variables matching what we want to pass
Method method;
int i;
// Cheating "Constructor"
public IFunc init (Method method, int i) {
this.method = method;
this.i = i;
return this; // Must return this for assignment
}
#Override
public Object onEvent() throws InvocationTargetException,
IllegalAccessException, NoSuchMethodException {
return method.invoke(set, null);
}
}.init(method, i)); // Note that init is called BEFORE assignment
}
}
...
An approach could be to avoid the anonymous inner class. i.e. have a class MethodIFunc implements IFunc that invokes the method on its onEvent() i.e.
for (...) {
Method method = ...
// this class calls method.invoke(..) inside its onEvent() method
MethodIFunc mi = new MethodIFunc(method, set);
MeasureAndRecord(name, mi);
}
Another approach (btw: you have a double iteration in the second for-loop I assume this is not the actual code) could be to use the for-each statement that allows the variable to be declared final:
for (final Method method : benchmarkMethods) {
...
MeasureAndRecord(name, new IFunc() {
#Override
public Object onEvent() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
return method.invoke(set, (Object[]) null);
}
});
}
You can use a mutable int wrapper, e.g.
final AtomicInteger ai = new AtomicInteger();
for (int i = 0; i < benchmarkMethods.size(); i++){
String name = null;
Method method = benchmarkMethods.listIterator().next();
ai.set(i);
MeasureAndRecord(name, new IFunc() {
#Override
public Object onEvent() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
return benchmarkMethods.get(ai.get()).invoke(set, null);
}
});
}
I have a void method "functionVoid" that informs a parameter.
public class MyMotherClass {
#Inject
MyClass2 myClass2
public String motherFunction(){
....
String test = "";
myClass2.functionVoid(test);
if (test.equals("")) {
IllegalArgumentException ile = new IllegalArgumentException(
"Argument is not valid");
logger.throwing(ile);
throw ile;
}
....
}
}
public class MyClass2 {
public void functionVoid(String output_value)
{ ....
output_value = "test";
....
}
}
How do I mock this method in the JUnit method my method "motherFunction"?
In my example, the "test" variable is still empty.
#RunWith(MockitoJUnitRunner.class)
public class MyMotherClassTest {
#Mock
private MyClass2 myClass2 ;
#InjectMock
private final MyMotherClass myMotherClass = new MyMotherClass ();
#Test
public void test(){
myMotherClass.motherFunction();
}
}
If you want to mock the return result of motherFunction then you need not worry about the internal implementation of the method (which ends up calling functionVoid). What you do need to do is provide Mockito with an instruction as to what to do when the method, motherFunction is invoked, this can be achieved via the when clause with syntax;
when(mockedObject.motherFunction()).thenReturn("Any old string");
If that misses the point of what you are attempting to achieve then look at how to mock void methods in the documentation and determine whether the use of doAnswer is applicable here, something like;
doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
String output_value = invocation.getArguments()[0];
output_value = "Not blank";
return null;
}
}).when(myClass2).functionVoid(anyString());
If you can change functionVoid() to accept a mutable object as the parameter, then you should be able to achieve what you want.
For example, if you change functionVoid() as follows:
public void functionVoid(StringBuilder output_value)
{ ....
output_value.append("test");
....
}
and invoke it in your motherFunction as follows:
public String motherFunction(){
....
StringBuilder test = new StringBuilder();
myClass2.functionVoid(test);
if (test.toString().equals("")) {
Now modifying OceanLife's answer above, you should be able to do the following:
doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
StringBuilder output_value = invocation.getArguments()[0];
output_value.append("Not blank");
return null;
}
}).when(myClass2).functionVoid(any(StringBuilder.class));
Of course, if you can change functionVoid(), you could also just make it return a String instead of void.
In my example, the "test" variable is still empty.
This is not a Mockito problem.
Take a look at this question and especially this answer.
The gist of it is that Java is pass by value (this is explained far better at the links above). Nothing in Mockito or Java will ever be able to make the test var anything other than an empty String. It's an empty String before the method call, and will be an empty String after the call.
You can change an object's state within a method (e.g. adding objects to a collection within a method) and see those changes when you exit the method, but you cannot change what object a var references within a method and expect those changes to "stick" once you exit the method. Strings however, are effectively immutable (no state to change), so you can't even do this.
Thus no modifications to test can be made within that method call.
If you want to check method someMethod(String arg) of object Obj then:
String argument = "";
Mockito.verify(Obj, Mockito.times(1)).someMethod(argument);
Obj has to be Mock or Spy.
This works when you want to check if proper argument was passed to void method.
If your method modifies somehow argument then you should use assertion:
someMethod(StringWrapper wrapper) that changes string.
// given
String argument = "a";
String expected = "a_changed";
String wrapped = new StringWrapper(a);
// when
someMethod(wrapped);
// then
Assert.assertEquals(wrapped.getString(), expected)
I am not sure if this what you were looking for?
I want to write a program which decides which methods to call on an object at runtime.
For example
<method>getXyz<operation>
<arg type="int"> 1 <arg>
<arg type="float"> 1/0 <arg>
Now I have something like above in XML files and I want to decide which method to call at runtime. There can be multiple methods.
I don't want to do something like the following in my code:
if (methodNam.equals("getXyz"))
//call obj.getXyz()
How can I do it using Java reflection?
Also I want to construct the parameter list at runtime. For example, one method can take
2 parameters and another can take n arguments.
You should use Object.getClass() method to get the Class object first.
Then you should use Class.getMethod() and Class.getDeclaredMethod() to get the Method, and finally use Method.invoke() to invoke this method.
Example:
public class Tryout {
public void foo(Integer x) {
System.out.println("foo " + x);
}
public static void main(String[] args) throws Exception {
Tryout myObject = new Tryout();
Class<?> cl = myObject.getClass();
Method m = cl.getMethod("foo", Integer.class);
m.invoke(myObject, 5);
}
}
Also i want to construct the parameter list at runtime.For Example one
method can take 2 parameters and other can take n args
This is not an issue, just create arrays of Class<?> for the types of the arguments, and an array of Objects of the values of the arguments, and pass them to getMethod() and invoke(). It works because these methods accept Class<?>... as argument, and an array fits it.
You can use the following code to a class method using reflection
package reflectionpackage;
public class My {
public My() {
}
public void myReflectionMethod(){
System.out.println("My Reflection Method called");
}
}
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);
}
}
this will work and for further reference please follow the link
http://compilr.org/java/call-class-method-using-reflection/
Have a good look at java.beans.Statement and java.beans.Expression. See here for further details.
I have a question about reflection
I am trying to have some kind of eval() method. So i can call for example:
eval("test('woohoo')");
Now I understand the there is no eval method in java but there is reflection. I made the following code:
String s = "test";
Class cl = Class.forName("Main");
Method method = cl.getMethod(s, String.class);
method.invoke(null, "woohoo");
This works perfectly (of course there is a try, catch block around this code). It runs the test method. However I want to call multiple methods who all have different parameters.
I don't know what parameters these are (so not only String.class). But how is this possible? how
can I get the parameter types of a method ?
I know of the following method:
Class[] parameterTypes = method.getParameterTypes();
But that will return the parameterTypes of the method I just selected! with the following statement:
Method method = cl.getMethod(s, String.class);
Any help would be appreciated !
You will need to call Class.getMethods() and iterate through them looking for the correct function.
For (Method method : clazz.getMethods()) {
if (method.getName().equals("...")) {
...
}
}
The reason for this is that there can be multiple methods with the same name and different parameter types (ie the method name is overloaded).
getMethods() returns all the public methods in the class, including those from superclasses. An alternative is Class.getDeclaredMethods(), which returns all methods in that class only.
You can loop over all methods of a class using:
cls.getMethods(); // gets all public methods (from the whole class hierarchy)
or
cls.getDeclaredMethods(); // get all methods declared by this class
.
for (Method method : cls.getMethods()) {
// make your checks and calls here
}
You can use getMethods() which returns an array of all methods of a class.
Inside the loop you can inspect the parameters of each method.
for(Method m : cl.getMethods()) {
Class<?>[] params = m.getParameterTypes();
...
}
Otherwise you can use getDelcaredMethods() which will allow you to "see" private methods (but not inherited methods). Note that if you want to invoke a private methods you must first apply setAccessible(boolean flag) on it:
for(Method m : cl.getDelcaredMethods()) {
m.setAccessible(true);
Class<?>[] params = m.getParameterTypes();
...
}
Ok thanxs to all the people who answered my question here the final solution:
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args){
String func = "test";
Object arguments[] = {"this is ", "really cool"};
try{
Class cl = Class.forName("Main");
for (Method method : cl.getMethods()){
if(method.getName().equals(func)){
method.invoke(null, arguments);
}
}
} catch (Exception ioe){
System.out.println(ioe);
}
}
public static void test(String s, String b){
System.out.println(s+b);
}
}