Getting annotation value of calling method - java

I want to get a value in annotation from method that is calling another method and that needs to be used with annotation used in called method.
Example
#MyAnnotation(id="method-invoker")
public void invoker(){
executor();
}
#ChildMethod
public void executor(){
}
In above example I want to get value set in id field in #MyAnnotation when handling #ChildMethod annotation.
How can I do this?

First you have to get the stack trace, then extract caller's name from it, then get the Method and get its annotation:
String id = getClass().getMethod(new Throwable().getStackTrace()[1].getMethodName()).getAnnotation(MyAnnotation.class).id();
(obviously it is a bad style to perform so many calls sequentially in one line, but it is ok for example).
But this method is limited. It does not support methods overloading. For example if you have 2 methods called invoker() that have different signature in one class you cannot distinguish between them using pure reflection API.
Fortunately I implemented library named CallStack that can do this: https://github.com/alexradzin/callstack
Using CallStack you can say:
CallStack.getCallStack().getFunction().getAnnotation(MyAnnotation.class).id()

Related

Java annotation example in official docs

While reading the Oracle documentation on annotations (quite new to this concept), I came across the following snippet in the beginning (link at the bottom). I am not clear on what the example is illustrating. Is the public #interface definition an enhanced version of a normal interface definition? id(), engineer() etc are methods that return default values if not specified in the interface implementation? But then the instantiation is confusing, is it providing an implementation of an interface where id() returns 2868724 etc? Also not clear what the function travelThroughTime() is for. Any clarifications appreciated:
/**
* Describes the Request-For-Enhancement(RFE) that led
* to the presence of the annotated API element.
*/
public #interface RequestForEnhancement {
int id();
String synopsis();
String engineer() default "[unassigned]";
String date(); default "[unimplemented]";
}
#RequestForEnhancement(
id = 2868724,
synopsis = "Enable time-travel",
engineer = "Mr. Peabody",
date = "4/1/3007"
)
public static void travelThroughTime(Date destination) { ... }
http://docs.oracle.com/javase/1.5.0/docs/guide/language/annotations.html
To break down your questions:
Is #interface just an enhancement of interface?:
No, #interface is declaring something quite different from a standard interface- you are essentially declaring an annotation type. Making this declaration enables the declared thing to be used as an annotation in other code. So the declaration:
public #interface RequestForEnhancement
enables the annotation #RequestForEnhancement to be used in later code.
An annotation describes metadata for a method or a class. The #RequestForEnhancement annotation, for example, might be placed in front of a method in another class to indicate that some developer wants that method to be changed in some way.
Declaring an interface, by contrast, is declaring the signature of a group of functions. Classes which later implement an interface must then provide implementations of those functions.
What are the "methods" (synopsis(), engineer(), etc.) in the annotation body for? These are not really methods like you would be used to seeing in a class or interface definition. Instead, these represent fields that the annotation you've just declared has. A #RequestForEnhancement annotation on a method should indicate what the requested change to the method is, and possibly who is expected to implement the enhancement to the method. Thus the fields synopsis and engineer are fields that can be included in the annotation.
What does this section mean?:
#RequestForEnhancement(
id = 2868724,
synopsis = "Enable time-travel",
engineer = "Mr. Peabody",
date = "4/1/3007"
)
public static void travelThroughTime(Date destination) { ... }
This is an example of using the annotation that we've declared in the block starting with #RequestForEnhancement. Usages like this will likely occur all over your codebase, in many different classes, once the annotation has been defined. In this particular example, there is a method travelThroughTime(Date destination) in some class which apparently doesn't work very well. Some developer coming across the method thought it should be improved by making it do what it appears to claim to do (travel through time). That developer decided to reflect his request by putting an #RequestForEnhancement annotation on the method with some information about when the request was made, who was expected to make the enhancement, etc.
Sure, but how do you use the contents of an annotation for anything useful? (A question I'll ask for you :-) )
So let's say I want to write a tool which looks through all of my code for methods annotated with #RequestForEnhancement and send an e-mail to the engineers listed in the request, along with information about the annotation and the request for enhancement. How would I get started?
The basic mechanism to find out what methods have an annotation and the way to get values from the annotation is through Java reflection. A tutorial which includes an example of annotations and reflection is here (it's actually a good tutorial on annotations in general).
So sure, you can use reflection to get info out of these annotations, but when would you run a tool to use the info from the annotations? (another one I'll ask for you) Java provides the ability for you to define annotation processors which use annotation information when your code is compiled. Here's what looks like a reasonable tutorial. You can also use the information in your annotations at runtime. If you've ever used JavaFX, for example, you may have noticed that annotations can affect runtime behavior (adding #FXML to a field helps JavaFX fill that field with a value defined in your fxml).

To get the hashCode() of the object that calls a specific method in Java

What I'm trying to is to get 'hashCode()' value of the object that calls a specific method in Java. For example,
public class Caller {
public void aMethod() {
Callee calleeObj = new Callee();
calleeObj.aSpecificMethod();
//do something
}
}
What I want to know is Caller's hashCode() value which calls calleeObj.aSpecificMethod() during the runtime. It is for drawing an Object diagram like below.
As a constraint, I only can modify '.class' files using bytecode instrumentation techniques.
To do that, I've tried Javassist library to instrument inside Callee.aSpecificMethod() but this way cannot get the caller's object. The reason seems obvious because instrumented code on 'Callee.aSpecificMethod()' only can access codes on Callee class, not Caller class.
Is there any way to capture the hashCode() value of caller's object using Javassist? I'm considering ASM 5.0 also, but using ASM 5.0 is the last option because I've built many code based on Javassist until now.
As said by others, there is no way of the invoked method getting hands on the caller object, but so far, nobody pointed you to the reason why this will never be possible:
The big misconception about your request is that you assume that there has to be a “caller object”. But there is no such thing. Your method might get invoked by static methods, e.g. right from the main method of an application, but also from class initializers or from constructors, even during the super constructor invocation, in other words, at places, where an object exists in the context of the invocation but hasn’t fully constructed yet, hence at a place where hashCode() can’t be invoked.
If you haven’t considered these gaps in your idea, you shouldn’t start using Instrumentation to alter the caller’s byte codes. It’s very unlikely that you will produce correct code. Even at places where an instance exist at the call cites, that instance doesn’t need to be available, nor does hash code calculation. What if you method get invoked from another object’s hashCode method?
Besides practical obstacles, the big question is, why do you think you need the “callers” hash code? What ever you intend to do with it, it can’t be right. Think of the following code:
public class Caller {
public void aMethod() {
Callee calleeObj = new Callee();
new Thread(calleeObj::aSpecificMethod).start();
}
}
Whose hash code are you interested in? Of the instance of the anonymous class generated at runtime? Of the Thread instance invoking the run method of that anonymous class? Or of the Caller instance which won’t be on the call stack at all, when your method get invoked?
You have to pass either the calling object or its hash code as a parameter to the method.

is an annotation aware of which method it is staying and this method's current parameter list and values?

It is in java, and I have a method:
public String test(String p1, String p2){...}
I want to print a message like "method test was called with parameter p1=xx and p2=xx" by an annotation so that it seems like this annotation is a monitor to tell the every call details.
How can I do that by annotation, or, the same goal under the condition that no touch of the method body ?
Current I know I can write an annotation for a parameter to let me get its value. But I am not sure if the annotation for parameter is aware of its current environments, the method name or the parameter name. I want it to know.

Is it possible to convert method reference to MethodHandle?

Is it possible to convert a method reference (e.g. SomeClass::someMethod) to a MethodHandle instance? I want the benefits of compile-time checking (ensuring that the class and method exists) as well as the ability to introspect the method using the MethodHandle API.
Use-case: I've got code that needs to execute if and only if the request was not triggered by a specific method (to avoid endless recursion). I want a compile-time check to ensure the class/method exists but a runtime check to compare the caller to the method.
So to recap: Is it possible to convert a method reference to a MethodHandle?
Well, if you can afford the additional overhead and security implications, you can use a Serializable functional interface and decode the serialized form of the method reference instance to find the target like demonstrated in this answer or brought up again with this question and its answers.
However, you should really rethink your software design. “Avoiding endless recursion” shouldn’t be fixed by decoding some kind of parameter object, especially not if your assumption is, that this actual argument value represents the caller of your method. How would you ever enforce this strange relationship?
Even a simple code change like referencing a method which delegates to the other method would break your check. Here is a simple example showing the subtle problems with your approach:
public class SimpleTest {
public static void main(String... arg) {
run(SimpleTest::process);
}
static void run(BiConsumer<Object,Object> c) {
c.accept("foo", "bar");
}
static void process(Object... arg) {
Thread.dumpStack();
}
}
When running this program it will print something like:
java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1329)
at SimpleTest.process(SimpleTest.java:16)
at SimpleTest.lambda$MR$main$process$a9318f35$1(SimpleTest.java:10)
at SimpleTest$$Lambda$1/26852690.accept(Unknown Source)
at SimpleTest.run(SimpleTest.java:13)
at SimpleTest.main(SimpleTest.java:10)
showing that the method reference within the generated instance is not the expected SimpleTest::process but instead SimpleTest::lambda$MR$main$process$a9318f35$1 which will eventually invoke process. The reason is that some operations (here varargs processing) are not performed by the generated interface instance but a synthetic method instead, just like you had written run((a,b)-> SimpleTest.process(a,b)). The only difference is the name of the synthetic method.
You shouldn’t design software relying on such fragile introspection. If you want to avoid recursion, a simple ThreadLocal flag telling whether you are already inside your specific method would do the job. But it might be worth asking yourself why your API is provoking endless recursion in the first place; there seems to be something fundamentally wrong…

How can a Java method retrieve the method object pertaining to that particular method? (Java)

I am writing a Java method with the following signature.
void Logger(Method method, Object[] args);
If a method (e.g. ABC() ) calls this method Logger, it should retrieve the Method object that encapsulates data about itself (ABC()) and pass it as an argument.
How can a method retrieve the Method object that is storing all the information about that method?
A simple way is that I use
Method[] methods = ExampleClass.Class.getMethods();
and search the whole array for the Method with the correct name. (Which is quite inefficient). Also, if two or more methods have the same names, then I will have to retrieve their parameter types too (to distinguish them) and have different code for each method. This would be inefficient as well as painful.
Is there a better way?
Thanks for the help.
Don't do it. Rather obtain the method name from the stack.
public void log(Object object) {
String methodName = Thread.currentThread().getStackTrace()[2].getMethodName();
// ...
}
This is however pretty expensive and that's why most self-respected logging frameworks offer an option to turn it on/off (which I would recommend to use instead of homegrowing one).
Even better, don't implement this method at all. Use logback, or some other modern logging framework.
If you are writing a wrapper over existing logger frameworks then the already provide a way to print the method name in the log message - if that's what you are trying to implement.
You can read from the log4j documentation, for example, that this extraction (as the other answer suggests) is done from the stack trace and is expensive : http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html

Categories

Resources