I'm trying to call a method within a class, assuming I only know its name (aka, a char vector with its name)
I tried calling str2func(['obj.' functionName]) - where functionName is the name of that method, without any luck - I can't seem to grab the handle of the method.
You can reference it like a field
obj.(functionName)
or using feval
feval(functionName, obj, ...)
I recommend the first option.
Related
I am trying to log field writes with bytebuddy. After reading some earlier posts, I started using MemberSubstitution and got something going using the following code:
private static Method FIELD_INTERCEPTOR = // reflective reference to interceptFieldWrite
AsmVisitorWrapper VISITOR = MemberSubstitution.relaxed()
.field(ElementMatchers.any())
.onWrite()
.replaceWith(FIELD_INTERCEPTOR)
.on(ElementMatchers.isMethod());
..
public static void interceptFieldWrite(Object object,Object value) {
System.out.println("intercepted field write in object " + object + " , attempt to set value to " + value);
}
..
The part I am struggling with is how to pass a reference to the field for which the access is intercepted to interceptFieldWrite (as string or instance of Field). If possible I would of course like to avoid reflection completely. I don't actually want to completely substitute field access, but just want to add a method with some checks just before it takes place. Is there a feature in bytebuddy to do this, or do I have to use something more low-level than ASM to achieve this ?
Byte Buddy offers this but you will have to compose your own StackManipulations to do so. The mechanism in MemberSubstitution is called replaceWithChain. Here you specify Steps where each step can do what you intend:
invoke a method via MethodInvocation.
write a field via FieldAccessor.
You will have to load the arguments to the method call and the field access prior to using the above stack manipulations via the MethodVariableAccess where the targeted element's offsets are represented by offsets.
In your case, this would require to read the target instance via
MethodVaribaleAccess.of(parameters.get(0)).loadFrom(offsets.get(0));
MethodVaribaleAccess.of(parameters.get(1)).loadFrom(offsets.get(1));
and the to execute the method or field write in question. The targeted field will be passed as target, you can cast it to FieldDescription if you only ever intercept fields.
Make sure you only intercept non-static fields where the this instance will not be passed.
I've found the InvokeDynamic class and have made it work with a static method handle acquired via MethodHandles.Lookup.findStatic().
Now I am trying to do the same thing, but with a virtual method handle acquired via MethodHandles.Lookup.findVirtual().
I can cause my bootstrap method to run, and I make sure in my bootstrap method that I'm returning a ConstantCallSite(mh), where mh is the result of calling MethodHandles.Lookup.findVirtual(). (This part all works fine, i.e. I understand how "indy" works.)
However, when I use the resulting Implementation as the argument to an intercept() call, I cannot pass the actual object on which the method represented by the method handle is to be invoked. This is due to the withArgument() method being used for two contradictory purposes.
Here is my recipe:
Implementation impl =
InvokeDynamic.bootstrap(myBootstrapDescription, someOtherConstantArgumentsHere)
.invoke(theMethodName, theMethodReturnType)
// 0 is the object on which I want to invoke my virtual-method-represented-by-a-method-handle;
// 1 is the sole argument that the method actually takes.
.withArgument(0, 1);
There are some problems here.
Specifically, it seems that withArgument() is used by ByteBuddy for two things, not just one:
Specifying the parameter types that will be used to build a MethodType that will be supplied to the bootstrap method. Let's say my virtual method takes one argument.
Specifying how the instrumented method's arguments are passed to the actual method handle execution.
If I have supplied only one argument, the receiver type is left unbound and execution of the resulting MethodHandle cannot happen, because I haven't passed an argument that will be used for the receiver type "slot". If I accordingly supply two arguments to (1) above (as I do in my recipe), then the method handle is not found by my bootstrap method, because the supplied MethodType indicates that the method I am searching for requires two arguments, and my actual method that I'm finding only takes one.
Finally, I can work around this (and validate my hypothesis) by doing some fairly ugly stuff in my bootstrap method:
First, I deliberately continue to pass two arguments, not one, even though my method only takes two arguments: withArgument(0, 1)
In my bootstrap method, I now know that the MethodType it will receive will be "incorrect" (it will have two parameter types, not one, where the first parameter type will represent the receiver type). I drop the first parameter using MethodType#dropParameterTypes(int, int).
I call findVirtual() with the new MethodType. It returns a MethodType with two parameter types: the receiver type that it adds automatically, and the existing non-dropped parameter type.
(More simply I can just pass a MethodType as a constant to my bootstrap method via, for example, JavaConstant.MethodType.of(myMethodDescription) or built however I like, and ignore the one that ByteBuddy synthesizes. It would still be nice if there were instead a way to control the MethodType that ByteBuddy supplies (is obligated to supply) to the bootstrap method.)
When I do things like this in my bootstrap method, my recipe works. I'd prefer not to tailor my bootstrap method to ByteBudddy, but will here if I have to.
Is it a bug that ByteBuddy does not seem to allow InvokeDynamic to specify the ingredients for a MethodType directly, without also specifying the receiver?
What you described, is entirely independent of Byte-Buddy. It’s just the way how invokedynamic works.
JVMS, §5.4.3.6
5.4.3.6. Dynamically-Computed Constant and Call Site Resolution
To resolve an unresolved symbolic reference R to a dynamically-computed constant or call site, there are three tasks. First, R is examined to determine which code will serve as its bootstrap method, and which arguments will be passed to that code. Second, the arguments are packaged into an array and the bootstrap method is invoked. Third, the result of the bootstrap method is validated, and used as the result of resolution.
…
The second task, to invoke the bootstrap method handle, involves the following steps:
An array is allocated with component type Object and length n+3, where n is the number of static arguments given by R (n ≥ 0).
The zeroth component of the array is set to a reference to an instance of java.lang.invoke.MethodHandles.Lookup for the class in which R occurs, produced as if by invocation of the lookup method of java.lang.invoke.MethodHandles.
The first component of the array is set to a reference to an instance of String that denotes N, the unqualified name given by R.
The second component of the array is set to the reference to an instance of Class or java.lang.invoke.MethodType that was obtained earlier for the field descriptor or method descriptor given by R.
Subsequent components of the array are set to the references that were obtained earlier from resolving R's static arguments, if any. The references appear in the array in the same order as the corresponding static arguments are given by R.
A Java Virtual Machine implementation may be able to skip allocation of the array and, without any change in observable behavior, pass the arguments directly to the bootstrap method.
So the first three arguments to the bootstrap method are provided by the JVM according to the rules cited above. Only the other arguments are under the full control of the programmer.
The method type provided as 3rd argument always matches the type of the invokedynamic instruction describing the element types to pop from the stack and the type to push afterwards, if not void. Since this happens automatically, there’s not even a possibility to create contradicting, invalid bytecode in that regard; there is just a single method type stored in the class file.
If you want to bind the invokedynamic instruction to an invokevirtual operation using a receiver from the operand stack, you have exactly the choices already mentioned in your question. You may derive the method from other bootstrap arguments or drop the first parameter type of the instruction’s type. You can also use that first parameter type to determine the target of the method lookup. There’s nothing ugly in this approach; it’s the purpose of bootstrap methods to perform adaptations.
Inside an Objective-C method, it is possible to get the selector of the method with the keyword _cmd. Does such a thing exist for the names of arguments?
For example, if I have a method declared as such:
- (void)methodWithAnArgument:(id)foo {
...
}
Is there some sort of construct that would allow me to get access to some sort of string-like representation of the variable name? That is, not the value of foo, but something that actually reflects the variable name "foo" in a local variable inside the method.
This information doesn't appear to be stored in NSInvocation or any of its related classes (NSMethodSignature, etc), so I'm not optimistic this can be done using Apple's frameworks or the runtime. I suspect it might be possible with some sort of compile-time macro, but I'm unfamiliar with C macros so I wouldn't know where to begin.
Edit to contain more information about what I'm actually trying to do.
I'm building a tool to help make working with third-party URL schemes easier. There are two sides to how I want my API to look:
As a consumer of a URL scheme, I can call a method like [twitterHandler showUserWithScreenName:#"someTwitterHandle"];
As a creator of an app with a URL scheme, I can define my URLs in a plist dictionary, whose key-value pairs look something like #"showUserWithScreenName": #"twitter://user?screenName={screenName}".
What I'm working on now is finding the best way to glue these together. The current fully-functioning implementation of showUserWithScreenName: looks something like this:
- (void)showUserWithScreenName:(NSString *)screenName {
[self performCommand:NSStringFromSelector(_cmd) withArguments:#{#"screenName": screenName}];
}
Where performCommand:withArguments: is a method that (besides some other logic) looks up the command key in the plist (in this case "showUserWithScreenName:") and evaluates the value as a template using the passed dictionary as the values to bind.
The problem I'm trying to solve: there are dozens of methods like this that look exactly the same, but just swap out the dictionary definition to contain the correct template params. In every case, the desired dictionary key is the name of the parameter. I'm trying to find a way to minimize my boilerplate.
In practice, I assume I'm going to accept that there will be some boilerplate needed, but I can probably make it ever-so-slightly cleaner thanks to NSDictionaryOfVariableBindings (thanks #CodaFi — I wasn't familiar with that macro!). For the sake of argument, I'm curious if it would be possible to completely metaprogram this using something like forwardInvocation:, which as far as I can tell would require some way to access parameter names.
You can use componentsSeparatedByString: with a : after you get the string from NSStringFromSelector(_cmd) and use your #selector's argument names to put the arguments in the correct order.
You can also take a look at this post, which is describing the method naming conventions in Objective C
I am trying to define a protocol method without adding parameters but couldn't find the correct syntax.
Here is the definition (it has a syntax error)
- (void)cameraOverlayView:(CameraOverlayView *)cameraOverlay didTakePhoto;
I don't want to pass any values with the second parameter. My aim is only to signal that something happened to the delegate instance.
How should I write the definition?
Your the second part of the method is not formatted correctly:
- (void)cameraOverlayView:(CameraOverlayView *)cameraOverlay didTakePhoto;
Because of the space, it's expecting a parameter. Instead, work the didTakePhoto part into the method name, like:
- (void)cameraOverlayViewDidTakePhoto:(CameraOverlayView *)cameraOverlay;
- (void)cameraOverlayViewDidTakePhoto:(CameraOverlayView *)cameraOverlay;
basically in objective c you can't have method name parts dangling after parameters...
so:
illegal:
-(void)methodWith:(int)theInt forMyMom;
normal:
-(void)methodForMyMomWithInt:(int)theInt;
legal but strange
-(void)method:(int)theInt :(int)theOtherInt;
with the selector: #selector(method::)
This is an issue of Objective-C convention. You could rewrite it as:
- (void)cameraOverlayView:(CameraOverlayView *)cameraOverlayViewDidTakePhoto;
I have a cell array of Matlab objects, something like:
objs = {Object1(), Object2(), Object3()};
These objects are all of different types. Some of them will have a method, let's call it myMethod(). I want to do something like:
for o = objs
if hasMethod(o, 'myMethod()')
o.myMethod();
end
end
and my difficulty is that I don't know how to do hasMethod - exist doesn't seem helpful here.
I could use a try - catch, but I'd rather do something neater. Is there a way to do this? Should I just change my design instead?
Another option is to use the meta class.
obmeta = metaclass(ob);
methodNames = cellfun(#(x){x.Name},obmeta.Methods);
You can also get additional information from obmeta.Methods like
Amount of input/output parameters.
Access type
In which class the method is defined.
Also, metaclass can be constructed from the name of the class, without an instance, which can be an advantage in some situations.
Ah, found it. Not very exciting - you can get a list of methods with the methods command. So to check if an object has a method,
if any(strcmp(methods(o), 'myMethod'))
o.myMethod();
end
Very close! If you had written the function name a bit differently you would've stumbled upon the following built-in:
if ismethod(o, 'myMethod')
o.myMethod();
end
Documentation: ismethod.
Why would you want to do that? You'd better have a good reason :p
Better make them inherit a general function from a superclass. Then you can just call that function for all of them, instead of looking up which class it is/checking if a function exists and then calling a function depending on the result (which is imo not very OO)
One simple option is to use the function EXIST (along with the function CLASS) to check if the method exists for the given class:
if exist(['#' class(o) '/myMethod'])
o.myMethod();
end
Another option is to use the function WHICH to perform the check like this:
if ~isempty(which([class(o) '/myMethod']))
o.myMethod();
end