23

I'm looking for a convenient workaround for getting the Method object from a method. The idea:

Method fooMethod = getMethod( new MyObject().foo() ) // returns method "foo" in MyObject

The obvious way is to use the name of the method as a string:

Method fooMethod = MyObject.class.getMethod("foo")

but I want to avoid this because if I rename foo() that code will stop working or I have rename the string in all the places where it is used.

The use case is that I want to use something similar to ProperyChangeListeners however those rely on the method name as string. I'd like to use the actual method (safely) and not rely on strings.

What could I use to get the method in a rename safe way?

UPDATE: I'd like to find a pure java solution that does not rely on IDE features

5
  • 1
    Though as others mention IDE's may take some of the pain away, what you describe is not currently possible. I seem to remember a featurerequest/JSR proposing a syntax like 'MyObject#foo' or something, but can't find it anymore. Commented Mar 25, 2012 at 21:52
  • Although its not possible I'm looking for possible workarounds that could currently be used Commented Mar 25, 2012 at 22:17
  • 2
    @ArnoutEngelen Java 8's lambdas are slated to have similar functionality: cr.openjdk.java.net/~briangoetz/lambda/lambda-state-4.html (section 8). Note that this won't give you a Method, but rather a lambda which you can then invoke. Commented Mar 25, 2012 at 22:19
  • Some IDEs suggest changing strings which could refer to a class, method etc when you rename something. They can suggest changes in text files e.g. properties, and comment as well. This can be useful even if you just want to change what youc all something so that all the code is in sync. Commented Mar 26, 2012 at 7:50
  • 1
    Possible duplicate of How to get the MethodInfo of a Java 8 method reference? Commented Apr 24, 2018 at 10:03

8 Answers 8

12

Java 8 method references would be ideal for this - the tricky part is getting to the underlying method, because the method reference syntax itself results in an opaque lambda object.

Found this after a bit of searching:

http://benjiweber.co.uk/blog/2013/12/28/typesafe-database-interaction-with-java-8/

Neat trick - call the method on a proxy object that records the method name. Haven't tried it but looks promising.

Sign up to request clarification or add additional context in comments.

4 Comments

Try adding more info into the answer itself, links can go stale :)
Depending on what you actually want to do, a java.lang.reflect.Proxy might also do the trick. Without external dependencies.
proxies can only snoop on interface classes though, not implementation classes afaik
10

In your method call: Method me = (new MethodNameHelper(){}).getMethod();

/**
 * Proper use of this class is
 *     Method me = (new MethodNameHelper(){}).getMethod();
 * the anonymous class allows easy access to the method name of the enclosing scope.
 */
public class MethodNameHelper {
  public Method getMethod() {
    return this.getClass().getEnclosingMethod();
  }
}

6 Comments

Are you suggesting to subclass the original MyObject and override foo() method to use this helper?
There is no need to subclass MyObject. Have foo() call Method me = (new MethodNameHelper(){}).getMethod(); and save or use that result as you had wished. You hadn't mentioned how you wanted to use the Method object.
Fair enough. The thing is that foo() will already have some code in it that I'd rather not change or it might come from third party. Even so how would I return the Method me to the calling code (eg main).
This technique is of limited value because you don't want to necessarily invoke the Method just to get its reference. Ideally they should be unrelated actions. It's unfortunately a flaw in Java's design that a lot of useful info that is known to the compiler isn't exposed until run-time (via reflection).
MethodNameHelper should be abstract.
|
10

There is actually a library that can do this:

Jodd MethRef - Strongly-typed method name references

https://jodd.org/ref/methref.html

Methref<Str> m = Methref.on(Str.class);  // create Methref tool

// example #1
m.to().boo();
m.ref();                               // returns String: 'boo'

2 Comments

Very cool, but it would be slightly cooler if they returned the Method instead of just its name.
Is in Jodd Proxetta now: proxetta.jodd.org/refs/methref
7

We have published the small library reflection-util that can be used to capture a method.

Example:

class MyClass {

    public void myMethod() {
    }

}

Method method = ClassUtils.getVoidMethod(MyClass.class, MyClass::myMethod);
System.out.println(method.getName()); // prints "myMethod"

Implementation details: A Proxy subclass of MyClass is created with ByteBuddy and a call to the method is captured to retrieve its name. ClassUtils caches the information such that we do not need to create a new proxy on every invocation.

Comments

4

You might want to use annotations. You can create a custom annotation for each method that you want to retrieve and the using reflection pull that method from the object.

You can safely rename the method and your code will work.

If you want to be able to retrieve many methods then use only one annotation with a string value which will change per method and then your reflection code will look for those annotations with that string value. You can still rename your method as long as you leave the string value of the annotation the same.

Comments

1

The safest thing is to use an IDE with refactoring capability that's smart enough to recognize and replace that String method name. IntelliJ from JetBrains does it - I just proved it to myself.

4 Comments

By default Eclipse does not do the same thing for methods - only classes. I could use search but I won't always know that I need to look for String references
Like I said, IntelliJ knows how to do it. I'd recommend that you get a superior IDE. Eclipse ain't it.
IntellJ unfortunately also can only use heuristics. It can for example happen that a method of the same name but different class gets renamed in a totally unrelated string. This is especially gruesome when you try to rename a method getId or isActive, which may exist on a lot of totally unrelated classes.
I have no trouble anything with ImtelliJ.
-1

You can use IDE refactoring which take care about all string occurences as well.

You cannot reference a method using reflection otherwise than by its name.

Comments

-1

By using reflection you're giving up compile-time safety, just by its nature.

Instead consider whether reflection is really necessary here. You could represent your method with a Runnable, for example:

Runnable foo = new Runnable() {
    @Override
    public void run() {
        new MyObject().foo();
    }
}

...

foo.run();

Or if you need to represent a method with a return type, look at Callable - or even better, Guava's Function.

3 Comments

Yes, I could, but that also would mean wrapping each method that needs to be used. It wouldn't be that convenient
I'd like to see an explanation of what led you to this design decision. I'm not convinced yet that reflection is necessary for what you're doing. This kind of design based on runtime lookup will be hard to maintain and debug going forward.
Added the PropertyChangeListener use case to the original question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.