I am trying to invoke a method using reflection
Method mi = TestInterface.class.getMethod("TestMethod", java.lang.String.class,java.lang.String.class,java.lang.String.class,java.lang.Object[].class);
this method has 3 mandatory string arguments, the last argument, which is the variable argument is optional.
However when I invoke this method as below.
mi.invoke(new TestImplementation(), new Object[]{"arg1", "arg2","arg3"});
then it gives me an error java.lang.IllegalArgumentException: wrong number of arguments
but the last arguement should be optional right?
or this doesn't work in case of invoking methods using reflection??
Code:
public interface TestInterface {
public void TestMethod(String str, String str1, String str2, Object... objects);
}
public class TestImplementation implements TestInterface {
public void TestMethod(String str1, String str2, String str3, Object... objects) {
// ....
}
}
public static void main(String[] args) throws Exception {
// works perfectly
TestInterface obj = new TestImplementation();
obj.TestMethod("str", "str1", "str2");
// doesn't work
Method mi = TestInterface.class.getMethod("TestMethod", java.lang.String.class, java.lang.String.class,
java.lang.String.class);
mi.invoke(new TestImplementation(), new Object[] { "arg1", "arg2", "arg3" });
}
Thanks in advance
In Java don't exists optional parameters. You can only override methods or use varargs.
In your case of varargs you are explicitly request Method object with paramters: String, String, String, Object[].
So you must invoke method with same parameters:
mi.invoke(new TestImplementation(), new Object[]{"arg1", "arg2","arg3", new Object[0]);
To understand your problem in general way see this topic.
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've been playing around with functional programing a little recently and I suspect it's got to me. But there's something I'd like to be able to do in Java and I'm not sure if It can be done.
I have an object 'ob' of type 'A'. I also have a library of methdods (several thousand, automatically generated ones-that take the same arguments) that I might want to a attach to ob. What I'd like to be able to write is
A ob = new A(Someint, someint, Method mymethod);
And then be able to write (within A) something along the lines of)
X = mymethod.call(arg1, arg2);
Is there something in Java that let's me do this? Or have I stayed too far from the light?
What you really need is Java 8 with lambda support. Anything else will be really ugly. (Even with this Java has functional support but nothing like a true functional language) I suggest you try
http://jdk8.java.net/lambda/
With this you can write lambdas line p -> p.getPrice() and function references like MyClass::myMethod
http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html
You can't do exactly that in Java. As a workaround, you can use an anonymous inner class.
Define an interface:
interface Func <A, B> {
A run (B arg);
}
Instantiate it on the fly to create a "function object":
C ob = frobn (someint,
new Func <int, long> () {
#Override
int run (long arg) {
// do something to return that int
}
});
You then call the passed Func inside frobn like this:
C frobn (int some, Func <int, long> fun) {
// do something
int foo = fun.run (bar);
// do something
}
Yes, that is ugly greenspunning.
Passing a Method reference to a method and then invoking the method with parameters.
There are various flavors on ways to do this. This instructional example uses
a static method named myMethod taking one Object as a parameter.
import java.lang.reflect.Method;
public class Tester54 {
static public class J42 {
static public Object myMethod(final Object o) {
return "Wow:" + o.toString();
}
}
private static void
doIt(final Class<?> c, final Method m, final Class<?>[] types, final Object[] args)
throws Exception {
final Object s = m.invoke(J42.class, new Object[] { "wow" });
System.out.println(s);
}
public static void main(final String[] a) throws Exception {
final Method m = J42.class.getMethod("myMethod", new Class<?>[] { Object.class });
final Class<?>[] types = new Class[] { Object.class };
final Object[] args = new Object[] { "wow" };
doIt(J42.class, m, types, args);
}
}
Im new to java and im just trying to use this method 'epli' from another class but when i try to do it it says The method epli(String[]) in the type nammi is not applicable for the arguments ()
im using eclipse here is all the code:
import java.util.Scanner;
public class nammi{
public void epli(String args[]){
System.out.println("Mér finnst nammi gott");
}
}
public class siggi {
public static void main(String args[]){
System.out.println("Eg heiti ekki siggi");
nammi nammi = new nammi();
nammi.epli();
}
}
You defined epli as:
public void epli(String args[])
So you need to provide an String array when you call it.
If you change the signature of epli to
public void epli()
you can call it the way you are doing it
Your method accepts a String[] data type but you are passing it nothing. You have to pass it a String[].
nammi.epli();
should become
nammi.epli(new String[5]);
or some other String array. You can also pass it a null if you want, but that's not what you should do in this case
nammi.epli(null);
Change the signature of the epli() method to use varargs syntax:
public void epli(String... args){
Within the epli() method, args will actually still has a type of String[].
Now your calling code will work, and you can pass parameters like this:
nammi.epli(); // OK - args is an empty array (not a null)
nammi.epli("foo"); // args is array size 1
nammi.epli("foo", "bar"); // args is array size 2 etc
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);
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?