Using reflection in Java, I've written some code to iterate through an arraylist of the names of classes I want enabled, instantiate them and in turn invoke a method with the common name 'parse(String)' within each.
for (String parser : enabledParses)
{
Class<?> parserClass = Class.forname(String.format"%s.%s", parserDirectoryPath, parser));
Method parseMethod = parserClass.getMethod("parse", String.class);
Object parserObj = null;
switch (parser)
{
case "parser1" :
parserObj = parserClass.getConstructor(ConfigWrapper.class, Alerter.class).newInstance(config, alerter);
break;
...
...
...
}
parseMethod.invoke(pluginObj, stringToParse);
When testing, how can I check to see that the parse() method has been called for each of the enabled parsers?
Thanks!
If you want to verify, that some method was called, you can use Mockito and then Mockito.verify (....).
But in this case your test is to big, because your implementation is too big, try to make better decomposition. Split it to more method, which are simple.
For example:
List<MyInterface> loadAndCreateInstances(File ...)
and
void callParse(List<MyInterface> instances) {}
Then use Mockito and create List of mocked/spyed objects (Collections.singletonList(myMock)). Verification:
Mockito.verify(myMock,times(1)).parse(any())
Let me know, if I said all :-)
Related
I have been trying to develop an application. A bean script will be written as per requirement which in turn will call methods (defined in the application) in various order as per requirement. The application code (apart for bean script) would not be changed.
Also, the application uses external jars which provide large number of methods - of which some are implemented in the application. However, I would like to have the possibility to use the other methods (ones that are not yet implemented) without making changes to application should the requirement arise. For this, I would like to use the Java reflection API. The user should be able to call any method present in the external jars by passing the method name and corresponding parameters (using the the external jar documentation).
I'm a java newbie so I have some code that tries to achieve it (may not be syntactically correct):
public void callExternalJarMethod(String methodName, Class[] methodParameterTypes, Object[] methodParameters)
throws NoSuchMethodException {
String className = "SampleClassName";
Class classObject = Class.forName(className);
Method methodObject;
if (methodParameterTypes.length == 0) {
methodObject = classObject.getMethod(methodName, null);
} else {
methodObject = classObject.getMethod(methodName, methodParameterTypes);
}
// Not handling calling of static methods in which case "null" would be passed instead of methodObject to the invoke method
Object returnValue = methodObject.invoke(methodObject, methodParameters);
}
I'm trying to find a way I can get the Class[] methodParameterTypes, and Object[] methodParameters populated with the relevant values. I would have the parameter types and parameter values as string. Also, any pointers towards useful utils would be appreciated.
Thanks in advance.
You are not passing an instance of SampleClassName to the Method.invoke() call here...
Object returnValue = methodObject.invoke(methodObject, methodParameters);
If the method you are going to invoke is static, you can do this...
Object returnValue = methodObject.invoke(null, methodParameters);
Otherwise (non-static), you need to create an instance of SampleClassName to execute the method on.
If the class does not need any constructor arguments, you could use...
Object returnValue = methodObject.invoke(classObject.newInstance(), methodParameters);
(Obviously there will be a load of Exceptions that you need to handle by doing "newInstance" and "invoke"...)
I have a bunch of objects in a List<MyClass> myObjects, which should be used as parameters of a method call on a mocked object. I'd like to verify that the corresponding method is called exactly once for each instance in myObjects like
Iterator<MyClass> it = myObjects.iterator();
while(it.hasNext()) {
MyClass myCurrentObj = it.next();
Mockito.verify(myMock).add(myCurrentObj); //fail here:
}
With this code, I get informed that my call was not done, but other interactions on the mock happened. This is not the case if I use Matchers.any(MyClass.class). Might be because the method calls on the mock don't have the same order than the corresponding parameters.
How can I verify that the method was called once for each entry in myObjects?
One way would be to use an ArgumentCaptor to collect all the values with which your mock was invoked:
final int nrElements = myObjects.size();
final ArgumentCaptor<MyClass> captor = ArgumentCaptor.forClass(MyClass.class);
verify(theMock, times(nrElements)).add(captor.capture());
// This is using assertJ
assertThat(captor.getAllValues()).isEqualTo(myObjects);
A side effect is that this will also check invocation order since the captor will add captured values in order.
I would like to access the usual reflection properties of a specific method without relying on Strings.
Is there any way to get from the method-Identifier to its reflection properties, like parameter types?
void run() {
java.lang.reflect.Method m = myMethod.getMethod(); // how?
Class<?>[] argClasses = m.getParameterTypes();
}
int myMethod(String arg) {
// ...
}
The piece myMethod.getMethod() is not valid. It is my way of saying "get from the method-identifier to the java.lang.reflect.Method object".
The string-way I do not want to use would be similar to m = getClass().getDeclaredMethod("myMethod", ...)
I use myMethod like a regular identifier and not as a String, i.e. "myMethod". I think this would be beneficial for refactoring, where someone renames myMethod to hisMethod -- the relation via the String-name would break, where the relation via the identifier would be refactored as well.
In java methods aren't first class citizens, so there is no solutions in Java for this problem.
Yet I had a similar problem and forged a small tool named picklock for this purpose.
I'm having some trouble using reflection in Java. I'm attempting to save a method of a data structure but getting an error. The error is
java.lang.NoSuchMethodException: cs671.eval.SerialList.add(java.lang.Integer, java.lang.String)
The method, in this case, that I'm trying to get is the add method for a SerialList that takes a Comparable and an Object as its parameters.
structType = "cs671.eval.SerialList", keyType = "java.lang.Integer", and valType = "java.lang.String" are strings that were read in from a file.
Class dataClass = null, comparableClass = null, objectClass = null;
try{ // create data structure
dataClass = Class.forName(structType);
comparableClass = Class.forName(keyType);
objectClass = Class.forName(valType);
}
catch(ClassNotFoundException e){}
java.lang.Object structObj = null;
try{ // Create a data structure object
structObj = dataClass.newInstance();
}
catch(Exception e){}
Method m = null;
try{ // Attempt to get add method for the data structure
m = dataClass.getMethod("add", comparableClass, objectClass); // This is where it fails
}
catch(Exception e){}
Basically I'm trying to get the right method on the right datastructure with the correct classes that are going to get passed into that method but I don't know how to tell the getMethod method that those classes (comparableClass and objectClass) are the correct ones.
Thanks in advance!
Added: Here's the SerialList's add method signature
public void add(java.lang.Comparable, java.lang.Object)
You are saying -
The method, in this case, that I'm trying to get is the add method for a SerialList that takes a Comparable and an Object as its parameters.
But passing the classes - java.lang.Integer, java.lang.String.
Just a note - Only public methods are visible to getMethod() for non-publics you would have to use getDeclaredMethod() instead.
From http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#getMethod%28java.lang.String,%20java.lang.Class...%29:
To find a matching method in a class C: If C declares exactly one public method with the specified name and exactly the same formal parameter types, that is the method reflected. If more than one such method is found in C, and one of these methods has a return type that is more specific than any of the others, that method is reflected; otherwise one of the methods is chosen arbitrarily.
=> You need to pass java.lang.Comparable.class & java.lang.Object.class
Apologies for providing wrong answer earlier. Based on your comments it appears that you're trying to get a Method by avoiding to provide specific parameter types needed in the signature of that method.
If my understanding is correct then you should rather use Class#getMethods() and examine the returned Method[] for your method. Consider a skeleton code like this:
Method[] methods = dataClass.getMethods();
boolean matched = false;
// find a matching method by name
for (Method method: methods) {
Class<?>[] parameterTypes = method.getParameterTypes();
if ( "add".equals(method.getName()) && parameterTypes.length == 2 ) {
// method is your target method
// however you'll need more strict checks if there can be another add method
// in your class with 2 different parameter types
}
}
As other answers have stated, to use getMethod() you need to know and use the actual declared formal parameters of the method you are attempting to retrieve.
However, if for some reason you do not know the formal parameters at compile time, then you can iterate over all of the methods from the class until you find a method that fits your parameters (or find the most specific method that fits your parameters).
There is functionality written to do this already in apache commons bean utils, specifically in org.apache.commons.beanutils.MethodUtils.invokeMethod(...) and MethodUtils.getMatchingAccessibleMethod(...).
Source code for the above methods can be easily viewed online here.
There are two classes A and B in the same package.
how to get name of the functions of class A called by class B.
Restriction is that the code of A and B cannot be modified.
You cannot use Java reflection to do static code analysis tasks like this. The reflection APIs don't provide the information that is needed.
Off the top of my head, I can think of two approaches that will work:
If you only have the ".class" files, then you can use a bytecode library such as BCEL to load the classes and traverse them to identify all of the method calls.
If you have source code, you could also use some existing Java parser library to create ASTs for your code and analyse them.
(The first approach is probably simpler if all you want is a list of class and method names.)
Reflection can be very useful, but very complicated if you don't understand it.
If you have the name of the class, and want to print the methods:
Class c = Class.forName(the_class_name);
for(Method m : c.getMethods()) {
System.out.println(m.toString());
}
If you want the name of a class given any Object:
String className = the_object.getClass().getName();
A combination of the two could look like this:
for(Method m : the_object.getClass().getMethods())
System.out.println(m.toString());
I think what you are asking for is the names of all the methods from A that B calls.
That can't really be done with reflection, mostly because Java doesn't provide any method for doing this.
The API, as always, provides more information. If you look through there, you might come up with a simple work around.
"Class of all the functions called by class A or class B" is confusing. But, If You want to get the class and function name of caller to a method detectsName described in your class A , then following code will be useful to you.
public class A {
public void detectsName() {
Throwable t = new Throwable();
StackTraceElement traceLine = t.getStackTrace()[1];
// t.printStackTrace();
String className = traceLine.getClassName();
String methodName = traceLine.getMethodName();
int lineNumber = traceLine.getLineNumber();
System.out.println(className);
System.out.println(methodName);
System.out.println(lineNumber);
}
}
If you call this method from any other class say - B, it will be detected.
public class B {
public static void main(String[] args) {
A a = new A();
a.detectsName();
}
}
Dependency Finder can do queries for this. Its approach is to generate meta data in XML and then use regexp based comparison. You may be specifically looking for feature called 'closure' with inbound reference..