How to invoke a method with a superclass - java

I'm trying to invoke a method that takes a super class as a parameter with subclasses in the instance.
public String methodtobeinvoked(Collection<String> collection);
Now if invoke via
List<String> list = new ArrayList();
String methodName = "methodtobeinvoked";
...
method = someObject.getMethod(methodName,new Object[]{list});
It will fail with a no such method Exception
SomeObject.methodtobeinvoked(java.util.ArrayList);
Even though a method that can take the parameter exists.
Any thoughts on the best way to get around this?

You need to specify parameter types in getMethod() invocation:
method = someObject.getMethod("methodtobeinvoked", Collection.class);
Object array is unnecessary; java 1.5 supports varargs.
Update (based on comments)
So you need to do something like:
Method[] methods = myObject.getClass().getMethods();
for (Method method : methods) {
if (!method.getName().equals("methodtobeinvoked")) continue;
Class[] methodParameters = method.getParameterTypes();
if (methodParameters.length!=1) continue; // ignore methods with wrong number of arguments
if (methodParameters[0].isAssignableFrom(myArgument.class)) {
method.invoke(myObject, myArgument);
}
}
The above only checks public methods with a single argument; update as needed.

Related

Cast an object to its specific type at runtime Java [duplicate]

I'm experimenting with this code:
interface Callee {
public void foo(Object o);
public void foo(String s);
public void foo(Integer i);
}
class CalleeImpl implements Callee
public void foo(Object o) {
logger.debug("foo(Object o)");
}
public void foo(String s) {
logger.debug("foo(\"" + s + "\")");
}
public void foo(Integer i) {
logger.debug("foo(" + i + ")");
}
}
Callee callee = new CalleeImpl();
Object i = new Integer(12);
Object s = "foobar";
Object o = new Object();
callee.foo(i);
callee.foo(s);
callee.foo(o);
This prints foo(Object o) three times. I expect the method selection to take in consideration the real (not the declared) parameter type. Am I missing something? Is there a way to modify this code so that it'll print foo(12), foo("foobar") and foo(Object o)?
I expect the method selection to take
in consideration the real (not the
declared) parameter type. Am I missing
something?
Yes. Your expectation is wrong. In Java, dynamic method dispatch happens only for the object the method is called on, not for the parameter types of overloaded methods.
Citing the Java Language Specification:
When a method is invoked (§15.12), the
number of actual arguments (and any
explicit type arguments) and the
compile-time types of the arguments
are used, at compile time, to
determine the signature of the method
that will be invoked (§15.12.2). If
the method that is to be invoked is an
instance method, the actual method to
be invoked will be determined at run
time, using dynamic method lookup
(§15.12.4).
As mentioned before overloading resolution is performed at compile time.
Java Puzzlers has a nice example for that:
Puzzle 46: The Case of the Confusing Constructor
This puzzle presents you with two Confusing constructors. The main method invokes a constructor,
but which one? The program's output depends on the answer. What does the program print, or is it
even legal?
public class Confusing {
private Confusing(Object o) {
System.out.println("Object");
}
private Confusing(double[] dArray) {
System.out.println("double array");
}
public static void main(String[] args) {
new Confusing(null);
}
}
Solution 46: Case of the Confusing Constructor
...
Java's overload resolution process operates in two phases. The first phase selects all the methods or constructors that are accessible and applicable. The second phase selects the most specific of the methods or constructors selected in the first phase. One method or constructor is less specific than another if it can accept any parameters passed to the other [JLS 15.12.2.5].
In our program, both constructors are accessible and applicable. The constructor
Confusing(Object) accepts any parameter passed to Confusing(double[]), so
Confusing(Object) is less specific. (Every double array is an Object, but not every Object is a double array.) The most specific constructor is therefore Confusing(double[]), which explains the program's output.
This behavior makes sense if you pass a value of type double[]; it is counterintuitive if you pass null. The key to understanding this puzzle is that the test for which method or constructor is most specific does not use the actual parameters: the parameters appearing in the invocation.
They are used only to determine which overloadings are applicable. Once the compiler determines which overloadings are applicable and accessible, it selects the most specific overloading, using only the formal parameters: the parameters appearing in the declaration.
To invoke the Confusing(Object) constructor with a null parameter, write new
Confusing((Object)null). This ensures that only Confusing(Object) is applicable. More
generally, to force the compiler to select a specific overloading, cast actual parameters to the declared types of the formal parameters.
Ability to dispatch a call to a method based on types of arguments is called multiple dispatch. In Java this is done with Visitor pattern.
However, since you're dealing with Integers and Strings, you cannot easily incorporate this pattern (you just cannot modify these classes). Thus, a giant switch on object run-time will be your weapon of choice.
In Java the method to call (as in which method signature to use) is determined at compile time, so it goes with the compile time type.
The typical pattern for working around this is to check the object type in the method with the Object signature and delegate to the method with a cast.
public void foo(Object o) {
if (o instanceof String) foo((String) o);
if (o instanceof Integer) foo((Integer) o);
logger.debug("foo(Object o)");
}
If you have many types and this is unmanageable, then method overloading is probably not the right approach, rather the public method should just take Object and implement some kind of strategy pattern to delegate the appropriate handling per object type.
I had a similar issue with calling the right constructor of a class called "Parameter" that could take several basic Java types such as String, Integer, Boolean, Long, etc. Given an array of Objects, I want to convert them into an array of my Parameter objects by calling the most-specific constructor for each Object in the input array. I also wanted to define the constructor Parameter(Object o) that would throw an IllegalArgumentException. I of course found this method being invoked for every Object in my array.
The solution I used was to look up the constructor via reflection...
public Parameter[] convertObjectsToParameters(Object[] objArray) {
Parameter[] paramArray = new Parameter[objArray.length];
int i = 0;
for (Object obj : objArray) {
try {
Constructor<Parameter> cons = Parameter.class.getConstructor(obj.getClass());
paramArray[i++] = cons.newInstance(obj);
} catch (Exception e) {
throw new IllegalArgumentException("This method can't handle objects of type: " + obj.getClass(), e);
}
}
return paramArray;
}
No ugly instanceof, switch statements, or visitor pattern required! :)
Java looks at the reference type when trying to determine which method to call. If you want to force your code you choose the 'right' method, you can declare your fields as instances of the specific type:
Integeri = new Integer(12);
String s = "foobar";
Object o = new Object();
You could also cast your params as the type of the param:
callee.foo(i);
callee.foo((String)s);
callee.foo(((Integer)o);
If there is an exact match between the number and types of arguments specified in the method call and the method signature of an overloaded method then that is the method that will be invoked. You are using Object references, so java decides at compile time that for Object param, there is a method which accepts directly Object. So it called that method 3 times.

Passing constructor as a parameter to a method

I am new to java and started working on constructors. I am seeing few examples where constructor is passed as parameter to a Method. Please tell me what happens when a constructor is passed as a parameter to a method..or suggest me some links where can i get enough knowledge about using constructors
Depending on the purpose why do you need to pass the constructor you may consider passing the instance of Supplier instead (JavaDoc - https://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html).
For example you have a method which suppose to create an account and fill everything in it. You can make this method to accept Supplier as a parameter:
public Account createNewAccount(Supplier<Account> accountConstructor) {
var account = accountConstructor.get();
account.fillEverything();
return account;
}
And after that pass constructor to this method either using lambda:
createNewAccount(() -> new UserAccount());
Or using method reference:
createNewAccount(UserAccount::new);
Both variants are working.
Constructors can be passed as arugments to methods using a method reference, somewhat like a function pointer in C++.
See: http://www.baeldung.com/java-8-double-colon-operator
This can be a Function type with one argument or a BiFunction type with two arguments, either way its a lambda returning a class of the type it constructs.
Like Turing85 said though I don't think this is what you want. Passing constructors as parameters is a pretty niche use case. If you just want information on constructors,
https://docs.oracle.com/javase/tutorial/java/javaOO/constructors.html
Here is an example class that holds two constructors as instance variables and invokes one of them when the constructItem method is called. The first constructor is stored as a Supplier that returns an object of type S and the second takes a Function that takes type T and returns type S.
public class ConstructorWrapper<T, S> {
private final Supplier<S> construct;
private final Function<T, S> constructFromObject;
public ConstructorWrapper(Supplier<S> constructWithNothing, Function<T, S> constructWithObject) {
this.construct = constructWithNothing;
this.constructFromObject = constructWithObject;
}
public S constructItem(T k) {
if (k != null) return this.construct.get();
else return constructFromObject.apply(k);
}
}
We can use the class like this to wrap creation of ArrayLists from Sets. x is created by invoking the constructor with no parameters and y is created by invoking the constructor with one parameter.
ConstructorWrapper<Set, ArrayList> setToArrayList = new ConstructorWrapper<>(ArrayList::new, ArrayList::new);
ArrayList x = setToArrayList.constructItem(null);
ArrayList y = setToArrayList.constructItem(new HashSet<>());
Or like this to wrap creation of Sets from ArrayLists:
ConstructorWrapper<ArrayList, HashSet> arrayListsToSets = new ConstructorWrapper<>(HashSet::new, HashSet::new);
HashSet x = arrayListsToSets.constructItem(null);
HashSet y = arrayListsToSets.constructItem(new ArrayList<>());
I used raw ArrayLists and Sets because I didn't want to clutter the code with more generics

Invoking Method when Parmaeter is instance of another class - Java

Ill try to make it short.
I want to iterate through the methods of a class via "getMethods()". Now when the method has a Parameter which is an instance of the "Event" class, it should be invoked.
Example Method:
private void onEvent(ExampleEvent event) {...]
"ExampleEvent" is an instance of the "Event" class.
Help is appreciated!
You want to use getParameterTypes() instead of getParameters(). If you want to match a parameter type to a parameter name, simply index the two arrays the same.
Something Like this, its been awhile since i wrote in java but This something like this should work
Method[] methods = Class.getMethods();
List<Method> methodsWithEvent = new List<Method>();
for(Method method : methods){
Class[] params = method.getParameterTypes();
for(Class class : params)
if(typeof(class) == typeof(ExampleEvent))
methodsWithEvents.add(method);
}

What's the proper way to use reflection to instantiate objects of unknown classes at runtime?

I am working on a Configuration Loader class so that I can change the parameters of my program via an external text file (config.txt) rather than having to recompile my code with every change I make.
It has been suggested that I use Java's Reflection to do this, but I'm a little confused as to how I might actually implement this.
I have been able to successfully extract the class name and the arguments for its constructor from my text file, but how do I go from this to an instantiated object?
here's what I have of my method so far:
public void loadObject(String classString, HashMap hm)
{
String className = props.getProperty(classString);
Class c = Class.forName(className);
}
classString is a string containing the name of the class, and hm is a hashmap where the class' constructor parameters map to their intended values.
I.e., for class Foo (int xPos, float yPos), "xPos" would map to a string of the intended int, and "yPos" maps to a string of the intended float. I want to be able to return, new Foo(hm.get"xPos".toInt, hm.get"yPost".toFloat), but I'm unsure how to dynamically use a constructor like that (the issue is, there are multiple possible classes -- perhaps it's a bar instead of a foo, for instance).
I know that its possible to do an if/else based off the classString, and simply call the proper constructor after identifying it that way, but I am looking to create a more extensible code that doesn't have to be rewritten every time I add a new class to the program.
All of the possible objects inherit from a single parent object.
You would use Class.getConstructor(Class<?>... parameterTypes) to get a reference to the constructor followed by Constructor.newInstance(Object... initargs).
However I would suggest taking a look at a dependency injection framework such as Spring or Guice as it sounds like what you are creating is a basic version of what they do.
Upon request for expanding this answer:
Class c = Class.forName(name);
Constructor ctor = c.getConstructor(Integer.class, Integer.class);
Integer param1 = hm.get("xPos") ...;
Integer param2 = hm.get("yPos") ...;
Object instanceOfTheClass = ctor.newInstance(param1, param2);
Of course instead of param1 and param2 you would create an array of arguments based upon what was in the input file (the same goes for the arguments to getConstructor()), etc.
Here's an example of doing it from program arguments:
import java.lang.reflect.Constructor;
import java.util.*;
public class InstantiateWithReflectionIncludingArgs {
public static void main(String[] args) throws Exception {
String className = args[0];
List<Object> argList = new ArrayList<Object>();
if (args.length > 1) {
argList.addAll(Arrays.asList(args).subList(1, args.length));
}
Class c = Class.forName(className);
List<Class<?>> argTypes = new ArrayList<Class<?>>();
for (Object arg : argList) {
argTypes.add(arg.getClass());
}
Constructor constructor = c.getConstructor(
argTypes.toArray(new Class<?>[argTypes.size()]));
Object o = constructor.newInstance(
argList.toArray(new Object[argList.size()]));
System.out.println("Created a " + o.getClass() + ": " + o);
}
}
Naturally, the argList can only ever have Strings in this case because they're pulled from a String[], but you could add args of any type. Note that constructor args are positional, not named, so the names in the map won't do you much good. They need to be in the proper order.
Try running it and passing "java.util.Date" as an argument.
Class<?> clazz = MyClass.class;
Constructor<?> ctor = clazz.getConstructor( /* Array of Classes the constructor takes */);
ctor.newInstance( /* arguments the constructor takes */ );

java reflection issue

I have this code:
public static final <TypeVO extends BaseVo> List<SelectItem> populateSelectBoxForType(
final Class<TypeVO> voClass, final String fieldName) {
List<SelectItem> listSelectBox = null;
final List<TypeVO> vosList = GenericEjbProxyFactory
.getGenericTopValueObjectProxy(voClass)
.getAllValueObjects(null);
System.out.println("loaded vosList!!!!");
if (vosList != null) {
listSelectBox = new ArrayList<SelectItem>();
for (final TypeVO currVo : vosList) {
listSelectBox.add(new SelectItem(currVo.getInternalId(), currVo.getName()));
}
}
return listSelectBox;
}
As you see here, I'm using currVo.getName because always, currVo has a name property.
I want to be able to use also other fields from this currVo which has type as voClass, but not all currVo classes will contain this field so I have to use reflection to identify these getField method, something like:
for (final TypeVO currVo : vosList) {
for (final Method m : voClass.getMethods()) {
if (m.getName().contains(fieldName)) {
listSelectBox.add(new SelectItem(
currVo.getInternalId(), currVo.m));
}
}
}
What I do not know is HOW I can use that specific method's value when I find it, exactly like currVo.getName (because, of course, currVo.m is wrong)?
Eg: If fieldName is "Age" I want to put in the list: currVo.getAge()... I am simply blocked here...
m.invoke(currVo);
See also:
Method javadoc
Also note the correct way to look for a method as suggested by Nik and Bohemian.
Do I understand it correctly that you want to invoke the method m on your object currVo? Then it's simply
m.invoke(currVo);
Use reflection to get the getFieldName method and invoke it, as follows:
Method method = voClass.getMethod("get" + fieldName); // the getter with no params in the signature
Object value = method.invoke(currVo}); // invoke with no params
listSelectBox.add(new SelectItem(currVo.getInternalId(), value));
Note: This assumes that fieldName is leading uppercase, eg "Value", not "value", so prepending it with "get" gives the exact method name, eg "getValue"
You should use the invoke method from the Method class.
m.invoke(currVo, (Object[]) null);
(Assuming the method takes no parameter.)
This will work for JDK versions 1.4 and later, since they state:
If the number of formal parameters required by the underlying method is 0, the supplied args array may be of length 0 or null
The one-parameter version of that call will not work on older JVMs.
I am not sure if i got ur question right, but what i feel u are asking wud be answered by following code:
// Class is whatever is the type u r using
Method mthd = Class.getMethod("get" + fieldName); //in case method don't have any parameters.
listSelectBox.add(mthd.invoke(currVo));
otherwise ignore.

Categories