I'm stuck in a situation where I only got Fields (java.lang.reflect) of a given class.
To help you better imagine, let's say we have code:
List<Apple> sortApplesByFieldName(List<Apple> apples, String fieldName) {
Field field = Apple.class.getDeclaredField(fieldName);
// some stream logic for sorting using this var
return apples;
}
Note, the class Apple is a regular POJO with private fields and public getters/setters.
Something like this. It will throw a ClassCastException if the field can't be compared.
Bit ugly, but isn't reflection always.
<T extends Comparable<T>> List<Apple> sortApplesByFieldName(List<Apple> apples, String fieldName)
throws NoSuchFieldException {
Field field = Apple.class.getDeclaredField(fieldName);
return apples.stream()
.sorted(Comparator.comparing(apple -> {
try {
return (T) field.get(apple);
}
catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}))
.collect(Collectors.toList());
}
#Test
public void verifyAttribute_getEnforceUserGroup_True()
{
boolean flag= false;
new MockUp<DataCache>()
{
#Mock
public HashMap getSitesCache()
{
return map;
}
};
new Expectations()
{
{
cach.getSitesCache().get(anyInt);
returns(site);
site.getEnforceUserGroups();
returns(1);
}
};
try
{
flag =enforceObj.verifyAttribute();
assertEquals(true, flag);
}
catch (Exception e)
{
e.printStackTrace();
}
}
I am unable to mock this get(int key) method of HashMap class. Cach and site are the mocked objects of their respective classes.
If I comment the cach.getSitesCache.get(anyInt) and add map.get(key) it gives the same error. My question is:
how to mock the get(int) method of HashMap class?
Here getSitesCache() method returns the HashMap. Now by passing the key as an argument of get method I got an object. Now that object is converted into Site object.
How to mock it?
Mocking HashMap is not allowed; instead, the test should return a real map from getSitesCache().
I am trying to invoke a static method with a Object[] parameter type. When I debug, the correct method is identified and the parameter type I put in seems to me to be of the correct type.
public String convertToJSFunction(Method method, Object[] params) {
String function = method.getName();
for (Method m : JavaToJS.class.getDeclaredMethods()) {
if (m.getName().equals(function))
try {
return (String) m.invoke(null,params);
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
} catch (InvocationTargetException e) {
e.printStackTrace();
return null;
} catch (IllegalArgumentException e) {
e.printStackTrace();
return null;
}
}
return null;
}
JavaToJS has only static methods. After debugging, the m I am trying to invoke is this method:
public static String setRegionNumber(Object[] params)
This throws an IllegalArgumentException: argument type mismatch. How is this possible?
i guess you are calling
Method setRegionNumber=...; // "setRegionNumber" Method
Object[] params=...; // your Object-Array Parameter
convertToJSFunction(setRegionNumber, params);
but what you need to do is
Method setRegionNumber=...; // "setRegionNumber" Method
Object[] params=...; // your Object-Array Parameter
convertToJSFunction(setRegionNumber, new Object[] { params });
this is because Method.invoke expects the parameter list of the called method as an object Array. So if you pass your object array directly then it interprets that as the parameter list. so if you have an Object[] Parameter you need to wrap it in an Object-Array just like any other parameter.
Say I have the following code...
#FunctionalInterface
static interface MessageFunction<T> {
void send(T obj);
}
static #interface Message {
Class<?> value();
}
static class Foo {
#Message(String.class)
MessageFunction<String> bass = (string) -> {
// Do Stuff
};
}
static class MessageManager {
Map<Class<?>, MessageFunction<?>> messages = new HashMap<>();
public void register(Object obj) {
for (Field field : obj.getClass().getDeclaredFields()) {
Message message = field.getAnnotation(Message.class);
if (message != null) {
MessageFunction<?> function;
try {
function = (MessageFunction<?>) field.get(obj);
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
return;
}
Method sendMethod;
try {
// Will this work?
sendMethod = function.getClass().getDeclaredMethod("send", Object.class);
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
return;
}
// How do I do something like this?
/*if (sendMethod.testParamaters(message.value())) {
this.messages.put(message.value(), function);
}*/
}
}
}
}
public static void main(String[] args) {
MessageManager manager = new MessageManager();
manager.register(new Foo());
}
I am reflecting a field that references an #FunctionalInterface of a generic type. Because the method parameter is also generic I have no way of knowing what parameters it accepts, Thus I must pass it along through other means (the annotation).
The issue is that there is the annotation value and the generic type do not have to match and there seems to be no way to check. I wan't it to fail in registration if the type listed in the annotation would not be accepted into the send method.
How would I go about thing this without actually calling the method. Is there a way? Better yet although I know its most likely impossible, is there a way to know what the parameter type is without the annotation?
The following is just a suggestion, I have used it in my project. But it is not a perfect solution for the question. May be you can download the source of GenericHibernateDao framework and see the sourcecode of method "getTypeArguments". I think it is so cool!.
// get a class object for your entity
Class clazz = ...
Type type = clazz.getGenericSuperclass();
if (type instanceof ParameterizedType) {
Type trueType = ((ParameterizedType)type).getActualTypeArguments()[0];
Class modelClass = (Class) trueType;
// Now you can creat an Instance in you generic parameterType
Object entity = modelClass.forInstance();
}
I do something similar in some of my code Here is a snippet.
Method[] meths = actionClass.getMethods();
for (Method meth : meths) {
Class<?>[] pTypes = meth.getParameterTypes();
/*
* Filter out all methods that do not meet correct
* signature. The correct signature for an action method
* is: String actionName(HttpServletRequest request)
*/
//...check for the correct number of params and the correct param type
if (pTypes.length != 1 || !HttpServletRequest.class.toString().equals(pTypes[0].toString())) {
continue;
} else {
//...check for return type
if (!String.class.toString().equals(meth.getReturnType().toString())) {
continue;
}
}
//If you make it here than that means the method
//meets the requirements to be a full fledged action.
//...
}
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) {}
}