Unit testing by passing runtime parameters to java reflect method - java

I am making a class object using the a java bean in my code. Then I am calling a particular method of that class obj
public static void runUnitTest(String className, String methodName, List<Object> inputParams, Object expectedReturnValue){
try {
// Make the class object to be tested on
Object classObj = Class.forName(className).newInstance();
Method calledMethod = classObj.getClass().getMethod(methodName,inputParams.get(0).getClass());
Object returnVal = calledMethod.invoke(classObj,inputParams.get(0));
}catch (InstantiationException | IllegalAccessException
| ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
I call it this way :
public static void main(String[] args) throws IOException {
List<Object> inputParams = new ArrayList<Object>();
inputParams.add(new BigDecimal(1234));
runUnitTest("NumberTest","getOutputNumber",inputParams,new BigDecimal(5678));
}
The code of NumberTest:
public class NumberTest{
public BigDecimal getOutputNumber(BigDecimal numberId) {
if(numberId.intValue() == 1234)
{
return new BigDecimal(5678);
}else
return new BigDecimal(0);
}
public BigDecimal getAdditionalOutputNumber(BigDecimal numberId, String additionalInfo) {
if(numberId.intValue() == 1234 && "Pass".equals(additionalInfo))
{
return new BigDecimal(5678);
}else
return new BigDecimal(0);
}
}
This works fine as I know that the method getOutputNumber has only one parameter. But when I have to call the same code for multiple methods where number of parameters differ (e.g. getAdditionalOutputNumber) I can't use the same code. I don't want to use a multiple if else or case block on the basis of size of inputParams.
Is there a generic way of calling the below :
Method calledMethod = classObj.getClass().getMethod(methodName,**?? What to pass here ??**);
Object returnVal = calledMethod.invoke(classObj,**?? What to pass here ??**);

You just have to build suitable arrays from the list of parameters to call the reflection API.
Class[] types = new Class[inputParams.size()];
int i = 0;
for(Object param:inputParams) {
types[i++] = param.getClass();
}
Method calledMethod = classObj.getClass().getMethod(methodName,types);
Object returnVal = calledMethod.invoke(classObj,inputParams.toArray());
There might be some issues with primitive types and null values.

Related

Use Class parameter for generic type (e.g ArrayList)

I am trying to create a generic method to handle different types of ArrayLists in Java. The types are quite different, but all contain one identical parameter, which I want to evaluate in this method.
But I cannot create proper ArrayList<type> with given class information.
What am I doing wrong?
private String test(ArrayList<?> list, Class<?> type) {
for(type i : list){ // for (type i : (ArrayList<type>) list){
// do something
}
return "xxx"
}
private void init() {
ArrayList<Type_1> a1 = new ArrayList<>();
ArrayList<Type_2> a2 = new ArrayList<>();
String s1 = test(a1, Type_1.class);
String s2 = test(a2, Type_2.class);
}
Update
Found a solution
private String test(ArrayList<?> list) {
for (Object i : list){
try {
Method m = i.getClass().getMethod("getName", null);
System.out.println(m.invoke(i));
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
//Handle Exception
}
}
}
I created a mixed answer relating to both solutions:
Implementing Interfaces
The first is done with a simple interface MyType that defines the contract method(s) for the classes Type_1 and Type_2. This is the clean and proper Java way. This way the compiler will already tell you if you can do certain operations or not. This also shows beginners problems with their concept of implementing ideas.
The downside is that all classes have to implement that interface (which may be defined anywhere along their inheritance hierarchy).
But Java is all about the advantage of type safety and compiler warnings. So this is clearly the preferred way.
Using Reflection
Using Reflection for this task is possible, yes. But not necessarily a good idea. With reflection, there are multiple problems:
You will get runtime errors or have to handle those exceptions
The project will start, but if your design, your concept, is flawed, this will be a lot harder to pinpoint
lots of libraries cannot handle reflections well (Aspect Oriented Programming, Application Containers, special Compilers like the GraalVM NativeImage, etc etc)
Using reflection will be slower and consume more memory
So if it's possible and easy to stay away from Reflection, you should steer clear. Especially if this has such a simple proper solution to it.
(I also cleaned up your code with the reflection, there were some minor inconsistencies in there that wouldn't let it compile)
Code:
package stackoverflow;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class SimpleInterfacing {
interface MyType {
String getName();
}
static class Type_1 implements MyType {
#Override public String getName() {
return "This is type 1";
}
}
static class Type_2 implements MyType {
#Override public String getName() {
return "This is type 2";
}
}
private String test(final ArrayList<? extends MyType> list) {
String returnValue = null;
for (final MyType t : list) {
// do something
System.out.println("Got name: " + t.getName());
returnValue = t.getName();
}
return returnValue; // returns last value, null is lists are empty
}
private void init() {
final ArrayList<Type_1> a1 = new ArrayList<>();
a1.add(new Type_1());
final ArrayList<Type_2> a2 = new ArrayList<>();
a2.add(new Type_2());
{
final String s1 = test(a1);
System.out.println("s1 is " + s1);
}
{
final String s2 = test(a2);
System.out.println("s2 is " + s2);
}
{
test_reflection(a1);
test_reflection(a2);
}
}
public static void main(final String[] args) {
new SimpleInterfacing().init();
}
private String test_reflection(final ArrayList<?> list) {
for (final Object i : list) {
try {
final Method m = i.getClass().getMethod("getName");
System.out.println("Invoked: " + m.invoke(i));
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
//Handle Exception
ex.printStackTrace();
}
}
return null;
}
}
You need to declare an explicit type parameter:
private <T> String test(ArrayList<T> list, Class<T> type) {
for (T i : list) {
// do something with 'i'
}
return "xxx"
}
If you don't need Class<T> argument, you can leave it out; e.g.
private <T> String test(ArrayList<T> list) {
for (T i : list) {
// do something
}
return "xxx"
}
You would normally only need to pass a Class<T> type object if you intended to create instances of that class ... or an array of that class.
The commented out version of your code would not compile because it is mixing compile-time and runtime types. In
for (type i : (ArrayList<type>) list) {
the compiler would need to know what type was represented by type at compile time. But it is a runtime variable. But that is invalid even before that because the Java syntax requires the identifier for a type at that point ... not the identifier for a variable.

How to get "double.class" by a "Double" Object

description:
I need use getMethod, it requires the parameterTypes.
The origin method requires double (a primitive type, not Double), and I can't change origin method.
I can't just input double.class in parameterTypes, because the s maybe diffierent types, such as Integer(not int).
The method parameter in Foo.java are always and only primitive types.
code:
test.java
public static void main( String args[] )
{
Object obj = new Foo();
Object s = 1.2;
String type = "Double";
try {
Method method = obj.getClass().getMethod("return" + type, s.getClass());// got NoSuchMethodException here, because it requires `double` not Double
System.out.println(method.invoke(obj,s));
} catch (NoSuchMethodException | IllegalAccessException |InvocationTargetException e) {
e.printStackTrace();
}
}
}
Foo.java //(I can't change/add code/delete in this part)
public class Foo {
public double returnDouble(double type){
return type;
}
public int returnInt(int type){
return type;
}
}
what I have tried:
Use Map
public static void main( String args[] )
{
Object obj = new Foo();
// Object s = 1;
// String type = "Int";
Object s = 1.2;
String type = "Double";
Map<String, Class> methodClassMap = new HashMap<String, Class>() {{
put("Double",double.class);
put("Integer",int.class);
}};
try {
Method method = obj.getClass().getMethod("return" + type, methodClassMap.get(s.getClass().getSimpleName()));
System.out.println(method.invoke(obj,s));
} catch (NoSuchMethodException | IllegalAccessException |InvocationTargetException e) {
e.printStackTrace();
}
}
}
It worked, but I have to list all possible type of value the s.
question:
Any better solution than using Map? Maybe use generic?
When you know beforehand that the target method always uses a primitive types, you can use the unwrap() method of MethodType of the java.lang.invoke package.
Object obj = new Foo();
Object s = 1.2;
String type = "Double";
try {
MethodType mt = MethodType.methodType(s.getClass(), s.getClass()).unwrap();
Method method = obj.getClass().getMethod("return" + type, mt.parameterArray());
System.out.println(method.invoke(obj, s));
} catch(ReflectiveOperationException e) {
e.printStackTrace();
}
Alternatively, when you’re already using the method type of the java.lang.invoke package, you can also use a method handle to perform the invocation.
Object obj = new Foo();
Object s = 1.2;
String type = "Double";
try {
MethodType mt = MethodType.methodType(s.getClass(), s.getClass()).unwrap();
MethodHandle mh = MethodHandles.lookup().bind(obj, "return" + type, mt);
System.out.println(mh.invoke(s));
} catch(Throwable e) {
e.printStackTrace();
}
But note that unlike Reflection, the return type has to be correctly specified for the lookup. I’m assuming the same return type as the parameter type, like in your example.

Is it possible to create the objects of class dynamically?

for example, i have 10 classes created with some methods in it. now, i want to create a method which takes one of these classname as input parameter in String format and instantiate that class.
public void instantiateclass(String Classname)
{
// this method should instantiate the given classname
}
is this possible in java reflection? or any other concepts in java?
Yes, you can do that. you can change your method to return an Object.
public Object instantiateClass(Class<?> clazz)
{
Object instance = null;
try {
instance = clazz.getDeclaredConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
return instance;
}
This can be easily done in c# by below code
private static object CreateInstanceByClassName(string className)
{
var assembly = Assembly.GetExecutingAssembly();
var type = assembly.GetTypes()
.First(t => t.Name == className);
return Activator.CreateInstance(type);
}
Above code assumes that the class is present in same assemble

Mockito: Attach Answer to every method of arbitrary Object instance

I have the following situation:
I want to attach an Answer to every method call of a specific class instance. So for example with the class
public class Example {
public int example1() { /* */ }
public int example2(Object a) { /* */ }
public int example3(Object a, Integer b) { /* */ }
public int example4(int a) { /* */ }
}
I want to do the following
public Example attachToExample(Example ex) {
Example spy = Mockito.spy(ex);
Answer<Object> answer = /* */;
doAnswer(answer).when(spy).example1();
doAnswer(answer).when(spy).example2(any());
doAnswer(answer).when(spy).example3(any(), any());
doAnswer(answer).when(spy).example4(anyInt());
return spy;
}
This works but what I would like to do is generalize this to not just Example instances but arbitrary Objects.
So what I would like to do is
public Object attachToExample(Object o) {
Object spy = Mockito.spy(o);
Answer<Object> answer = /* */;
for(Method m : o.getClass().getMethods()) {
/* skipping methods that cannot be mocked (equals/hashCode/final/..) */
doAnswer(answer).when(spy)./* Method m with according arguments */;
}
return spy;
}
What I would need to do for that is construct argument matchers any/anyInt/.. depending on the amount of parameters of each method and their types (primitive/non primitive). Ideally I would create a list of arguments like this:
Class<?>[] params = m.getParameterTypes();
ArrayList<Object> args = new ArrayList<>();
for (Class<?> param : params) {
if ("int".equals(param.toString())) {
args.add(ArgumentMatchers.anyInt());
} else { // Cases for other primitive types left out.
args.add(ArgumentMatchers.any()); // Found non primitive. We can use 'any()'
}
}
try {
doAnswer(answer).when(spy).getClass().getMethod(m.getName(), m.getParameterTypes())
.invoke(spy, args.toArray());
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
This does not work as using argument matchers outside of stubbing is not supported but I hope that this makes clear what I want to do.
Is there any way to make this work or is there a different way of archiving what I want to do?
Okay, I have found a way to do what I want:
While the array of arguments cannot be constructed before the invoke call we can do so with an external method call like so:
try {
doAnswer(answer).when(spy).getClass().getMethod(m.getName(), m.getParameterTypes())
.invoke(spy, constructArguments(m));
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
where constructArguments is the following:
private static Object[] getArgumentMatcher(Method m) {
Class<?>[] types = m.getParameterTypes();
Object[] res = new Object[types.length];
for(int i = 0; i < types.length; ++i) {
if (types[i].isPrimitive()) {
// For primitives we need to specify the type explicitly ¯\_(ツ)_/¯
res[i] = any(types[i]);
} else {
res[i] = any();
}
}
return res;
}

Dynamically calling a class method in java?

Is it possible to dynamically call a method on a class from java?
E.g, lets say I have the reference to a class, e.g either the string: 'com.foo.Bar', or com.foo.Bar.class, or anything else which is needed..). And I have an array / list of strings, e.g [First, Last, Email].
I want to simply loop through this array, and call the method 'validate' + element on the class that I have a reference to. E.g:
MyInterface item = //instantiate the com.foo.Bar class here somehow, I'm not sure how.
item.validateFirst();
item.validateLast();
item.validateEmail();
I want the above lines of code to happen dynamically, so I can change the reference to a different class, and the names in my string list can change, but it will still call the validate + name method on whichever class it has the reference to.
Is that possible?
The simplest approach would be to use reflection
Given...
package com.foo;
public class Bar {
public void validateFirst() {
System.out.println("validateFirst");
}
public void validateLast() {
System.out.println("validateLast");
}
public void validateEmail() {
System.out.println("validateEmail");
}
}
You could use something like...
String methodNames[] = new String[]{"First", "Last", "Email"};
String className = "com.foo.Bar";
try {
Class classRef = Class.forName(className);
Object instance = classRef.newInstance();
for (String methodName : methodNames) {
try {
Method method = classRef.getDeclaredMethod("validate" + methodName);
method.invoke(instance);
} catch (NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException ex) {
ex.printStackTrace();
}
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
ex.printStackTrace();
}
To look up the methods and execute them.
You will need to decide the best way to handle errors and what they mean to you, but it wouldn't be a difficult them to expand the idea to a reusable method...
Updated with idea of concept discussed in comments
Given....
public interface Validator {
public boolean isValid(Properties formProperties);
}
We can create one or more...
public class UserRegistrationValidator implements Validator {
public boolean isValid(Properties formProperties) {
boolean isValid = false;
// Required fields...
if (formProperties.containsKey("firstName") && formProperties.containsKey("lastName") && formProperties.containsKey("email")) {
// Further processing, valid each required field...
}
if (isValid) {
// Process optional parameters
}
return isValid;
}
}
Then from our input controller, we can look and valid the required forms
public class FormController ... {
private Map<String, Validator> validators;
public void validForm(String formName, Properties formProperties) {
boolean isValid = false;
Validator validator = validators.get(formName);
if (validator != null) {
isValid = validate.isValid(formProperties);
}
return isValid;
}
}
Of course you need to provide some way to register the Validators and there may be differences based on the backbone framework you are using and the parameters you can use (you don't have to use Properties, but it is basically just a Map<String, String>...)
You can write something like this... it takes name of a class as string as an argument, the method name and its arguments
private static String invoke(String aClass, String aMethod, Class<?>[] params,
Object[] args) throws Exception {
String resp = "";
Class<?> c = Class.forName(aClass);
Method m = c.getDeclaredMethod(aMethod, params);
Object i = c.newInstance();
resp = m.invoke(i, args).toString();
return resp;
}
You can also refer to the oracle tutorial on reflection ... which demonstrates how to call methods
http://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html
It's possible using reflection.
First, you create a new class from the FQN (fully qualified name, which is the class name including the package).
Then you iterate through your elements and invoke the "validate" methods on your item.
Class<?> clazz = Class.forName("com.foo.Bar");
Object item = clazz.newInstance();
for (String element : elements) {
Method method = clazz.getDeclaredMethod("validate" + element);
method.invoke(item);
}
You can use reflection, but my favorite method is to use beanutils, eg:
Bar b1 = //...
BeanUtils.getProperty(b1, "first");
BeanUtils.getProperty(b1, "last");
Note that your class has to conform to javabean convention. You can read more about beanutils on this blog post (disclaimer I'm the blog author)
If you know the name of the class beforehand, use Class.forName(yourClassname)
That way, you can invoke the class, and then, you can invoke its methods.
Yes, using reflection.
Using Class.getDeclaredMethod on your object
Object validator = <your object instance>;
final String[] values = {
"Item1","Item2","Item3"
}
for(final String s : values) {
Method m = validator.getDeclaredMethod("validate" + s,String.class);
try {
Object result = m.invoke(validator, s);
}
catch(ex) {}
}

Categories