I am trying to figure out how to invoke a method of a custom class. Here is the process of what I am trying to do:
1) I initialize an array of methods from the list of methods of my custom class, and an empty List of Method which will be used to hold a filtered list of these methods.
Method method[] = MyClass.getDeclaredMethods();
List<Method> x = new ArrayList<Method>();
2) I then run my array of methods through a for loop and filter out whichever methods do not fill my required criteria.
for (Method m : methods){
if(...){
if(...){
x.add(m);
}
}
}
3) Finally, I need to invoke each of the methods in the finalized list. This is where I am stuck, I am not exactly sure how the invoke function works. Here is what I am trying:
for(int i=0; i < x.size(); i++){
boolean g = x.get(i).invoke();
if(...)
else(...)
}
The thing is, I know Exactly what it is I don't know, I am just having trouble finding the answers. These are the questions I need answered:
1) Which object will actually use the invoke function? Is it going to be, in my case, the particular method I want to invoke, or an instance of the class I am trying to invoke?
2) I know that the invoke function is going to require arguments, one of which is the parameter data for the method. What I am unclear about is what exactly the first argument needs to be. I am thinking that the first argument is the actual method itself, but then I run into a logical loop, because the way I have it coded has the method using the invoke function, so I am stumped.
3) In my case, the methods I wish to invoke don't actually take any parameters, so when I do happen to figure out how the invoke function works, will I need to set one of the arguments to null, or will I just omit that part of the argument list?
You're using .invoke incorrectly. See this short example:
public class Test {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
X obj = new X();
Method method = obj.getClass().getMethod("test", null);
method.invoke(obj, null);
}
}
class X {
public void test(){
System.out.println("method call");
}
}
Output:
method call
More information in the docs.
Invokes the underlying method represented by this Method object, on the specified object with the specified parameters.
You have never specified an object nor parameters. My sample uses no parameters so I can put null instead. But either way you have to provide an instance as the first parameter (unless it is static).
Related
Using ByteBuddy, can I implement one instance method by calling another and transforming the result?
For instance (toy example):
public abstract class Foo {
public String bar() {
return "bar";
}
public abstract int baz();
}
Given the above, can I implement baz such that it calls bar() and returns the length of the returned string? I.e., as if it were:
public int baz() {
return bar().length();
}
Naively, I tried the following:
Method bar = Foo.class.getDeclaredMethod("bar");
Method baz = Foo.class.getDeclaredMethod("baz");
Method length = String.class.getDeclaredMethod("length");
Foo foo = new ByteBuddy()
.subclass(Foo.class)
.method(ElementMatchers.is(baz))
.intercept(
MethodCall.invoke(bar) // call bar()...
.andThen(MethodCall.invoke(length)) // ... .length()?
).make()
.load(Foo.class.getClassLoader())
.getLoaded()
.newInstance();
System.out.println(foo.baz());
However, it looks like I was wrong in thinking andThen() is invoked on the return value of the first invocation; it looks like it's invoked on the generated instance.
Exception in thread "main" java.lang.IllegalStateException:
Cannot invoke public int java.lang.String.length() on class Foo$ByteBuddy$sVgjXXp9
at net.bytebuddy.implementation.MethodCall$MethodInvoker$ForContextualInvocation
.invoke(MethodCall.java:1667)
I also tried an interceptor:
class BazInterceptor {
public static int barLength(#This Foo foo) {
String bar = foo.bar();
return bar.length();
}
}
with:
Foo foo = new ByteBuddy()
.subclass(Foo.class)
.method(ElementMatchers.is(baz))
.intercept(MethodDelegation.to(new BazInterceptor()))
// ...etc.
This ran, but produced the nonsensical result 870698190, and setting breakpoints and/or adding print statements in barLength() suggested it's never getting called; so clearly I'm not understanding interceptors or #This properly, either.
How can I get ByteBuddy to invoke one method and then invoke another on its return value?
Per k5_'s answer: BazInterceptor works if either:
we delegate to new BazInterceptor(), as above, but make barLength() an instance method, or:
we leave barLength() a class method, but delegate to BazInterceptor.class instead of to an instance.
I suspect the 870698190 was delegating to hashCode() of the BazInterceptor instance, though I didn't actually check.
There is not currently a good way in Byte Buddy but this would be an easy feature to add. You can track the progress on GitHub. I will add it once I find some time.
If you want to implement such chained calls today, you can implement them in Java code and inline this code using the Advice component. Alternatively, you can write the byte code more explicitly by creating your own ByteCodeAppender based on MethodInvocation instances where you have to load the arguments manually however.
You use an instance as interceptor, that means instance methods are prefered (maybe static method are not accepted at all). There is an instance method that matches the signature of your int baz() method, it is int hashCode(). The number you are getting is the hashcode of the new BazInterceptor() instance.
Options i am aware of:
Remove static from barLength that way it will actually be used for interception.
Add the class as interceptor .intercept(MethodDelegation.to(BazInterceptor.class))
I would prefer the second option as you are not using any fields/state of the BazInterceptor instance.
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.
I am implementing an IdChecker program who check the uniqueness of "id's" for classes and methods of a project. The IdChecker run only at compilation of my project...before I push a release.
For the classes it is easy to get the id's because I just need to map all my classes then invoke MyClass.getField("CLASS_ID").getShort(MyClass.getField("CLASS_ID")); then I create a ClassWrapper who contain the className and the classIdentifier.
For the methods, it's a little bit more complicated, because I can't use reflection to access a variable who is local to a method...but...in my project, I use a debuglogger to log every "entering-the-method" and "leaving-the-method". To get the local variable I want to invoke a method then read in my logBuffer the last entry (who is the "leaving-the-method" log entry) from this log entry, I get the METHOD_ID.
My problem:
I can't invoke the method on the class it generate an IllegalArgumentException...
I don't need to pass parameters to the method, I just want to invoke them that I can generate a log entry.
private void getMethodsList() throws IllegalArgumentException,
IllegalAccessException, NoSuchFieldException, SecurityException {
final short METHOD_ID = 0x03;
/* Log-entering the method */
mLogger.logDebug((byte) 1, METHOD_ID);
/* Create the MethodWrapper list corresponding
to each element of the ClassWrapper list */
for(Class<?> clazz : mClasses)
{
/* Get the declared methods from each class */
for(Method method : clazz.getDeclaredMethods())
{
/* Get the name of the method */
String newName = method.getName();
short newIdentifier = 0;
try
{
method.invoke(clazz, new Object[]{null});
/* Get the identifier of the class */
newIdentifier = AbstractDebugLogger.mLastMethodID;
}
.
.
.
method.invoke(...) requires an array of arguments that could actually be used to call the method. In this case, you give it {null}, which works for any function that accepts a single Object, but no other functions. To call arbitrary functions, you need to match the length of the parameter list to the number of arguments the function needs:
method.invoke(..., new Object[method.getParameterTypes().length])
This still has a few problems. First, the first parameter of invoke is not the class as you entered it, but instead an instance of an object of that class (or null, for static methods). You would need to search through the class's constructors and construct an instance of that class before you could call instance methods of that class.
The second problem is that this does not work with functions that require primitives, which cannot be null. You could check the classes of the parameters and replace null with 0 or false as appropriate.
The third, most important problem, which is the reason that it is so difficult to do this, is that you do not actually want to invoke the method. You want to retrieve information about the method, which in this case happens to be stored inside the method. The proper solution is to just store the information attached to the method, with an annotation:
#Retention(RetentionPolicy.RUNTIME)
#interface ID {
int value();
}
...
#ID(1337)
void exampleMethod() { ... }
...
newIdentifier = method.getAnnotation(ID.class).value(); //returns 1337 for exampleMethod
I have a Java utility package, which can be used by multiple services(written in Java) for performing some utility tasks.
Lets say the Java utility package name is U and one of the Service be S. Now S calls a function F of U.
My question is, whether there is a way where function F of package U is able to determine which service S has called it ?
There can be multiple services S1, S2, ... , Sn calling F. I need to know upon a call, which Service Sx is calling that particular F.
You could use something like the following requiring you only to create a function findServiceContainingClass mapping class names to services (or null):
void callee() {
StackTraceElement[] st = new RuntimeException().getStackTrace();
for (int i = 1; i < st.length; i++) {
Service service = findServiceContainingClass(st[i].getClassName());
if (service != null) break;
}
// ... use service
}
However it is deemed bad practice to make code behave differently depending on the caller. I would use such code only as a last resort. (It would be okay to use it in a breakpoint condition during debugging. Maybe that is what you intend.)
Object Oriented programming in Java states that your service is scope for invocation, nothing else (forget static). So there is no normal way to find who is calling instance's method other than passing S instance as argument.
But that does not mean it is impossible.
If you only need to know what is the type of caller, you can use Thread.currentThread().getStackTrace():
StackTraceElement[] elements = Thread.currentThread().getStackTrace()
StackTraceElement caller = elements[elements.length - 2];
printLn(caller.getClassName());
As I said at the beginning it is totally counter objective Java code.
If you need to refer exact instance, you probably should add caller as call parameter. I assume that if you want to refer to caller, callee's code is written by you, so you are able to do it. As for me it would be best choice, because if you need caller in scope of callee, you should pass it directly. Other option is to set caller on ThreadLocal in U, but you don't have confidence that developer will do it each time.
If interface cannot be changed, and U is an interface, you could create U builder object:
public class UBuilder {
public U getS(final S caller) {
Proxy.newProxyInstance(getClass().getClassLoader(), U.class,
new InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
// store caller value on some ThreadLocal variable
try {
method.invoke(proxy, args);
} finally {
// remove caller from ThreadLocal variable
}
}
}
}
}
After that you have additional invocation context (ThreadLocal) referring S instance.
If U is not interface, Javassist, CgLib or something similar would help, but only if invoked method is not static or final.
If F is static or final I see only dramatically hackish answers. Maybe creating own interface imitating U, and forwarding method invocations in InvocationHandler could be some way. Of course S should refer to this interface, not U directly.
Hope it helps.
If there needs to be some service-specific code that is executed by that utility method, I would declare an interface in the utility class and have the services pass in an instance of it to the method.
Here is a contrived example:
public class Utility {
public interface UtilityInterface {
public void specificBehavior( Object arg );
}
public void utilityMethodF( UtilityInterface utilityInterface, Object... args ) {
// perform work with args or whatever
utilityInterface.specificBehavior( null );
// perform work with args or whatever
}
}
well I'm wondering if it's possible to have a method where another method is passed as a parameter, so the first method can call the method passed in param?
Like for instance:
public void goToVisitManagementForm() throws ParseException {
if (isAuthenticated() && userTypeIs("Patient")) {
// I could have this whole block just moved to another method?
Panel newPanel = new Panel("Choose the details for your visit");
Component visitManagementForm = new VisitManagementForm(userData,
this);
newPanel.addComponent(visitManagementForm);
mainWindow.setMainPanel(newPanel);
} else {
authenticate();
}
}
If the code block would be moved to another method and it would be passed as a parameter to this method. How can I achieve that and is this a good practice? Because in this case I have the ifs that I always need to paste in...
What about other aspects of this?
This is called a higher-order function and you cannot do this in Java 7 or below. You can simulate passing functions to other functions through the use of an anonymous class that instantiates some interface the function expects, and then calling the function on that object.
For example, to pass a no-arg function:
interface Function {
void apply();
}
void takesAFunction(Function function) {
function.apply();
}
Then the following code snippet would do what you want:
Function myFunction = new Function() {
#Override
public void apply() {
// your code here.
}
};
takesAFunction(myFunction);
As a side note, reflection is extreme overkill for this type of problem.
You can pass methods as parameters using Java Reflection API.
First, you get a method object from a class:
Class c = MyClass.class;
Method[] methods = c.getMethods();
Method m = // choose the method you want
Then your function can take a Method object as a parameter:
public void aFunction(MyClass o, Method m);
And then inside that function you can invoke the method:
m.invoke(o);
This is a very simple example, where the method doesn't take any parameters. It's pretty easy to expand on this example and add the parameters as well.
Yes, but it is a very advanced procedure. You need to use the Method object. Here is the javadoc on Method:
here is the javadoc:
- http://docs.oracle.com/javase/6/docs/api/java/lang/reflect/Method.html
If I am understanding your question correctly, you want to be able to pass a method as a parameter. There really is no 'smooth' way to do this in Java. In objective C, it is built right into the language, (#selector tag)