Method patterns
A simple and powerful way of identifying method definitions and invocations
Method patterns provide a way to accurately and quickly identify one or more method definitions or invocations. Unlike traditional text-based searches that can result in thousands of irrelevant matches, method patterns are type-aware and will, therefore, only find relevant results.
An OpenRewrite method pattern is comparable to an AspectJ "pointcut expression".
Anatomy of a method pattern
A method pattern can identify one or more method definitions or invocations based on:
A fully qualified class name for where the method is defined or invoked (aka a fully qualified receiver type)
A method name
The method's argument types
If you are using IntelliJ or Eclipse for development, you can right-click on a class name, select Copy / Paste Special
, and then click on Copy Reference
. This will copy the fully qualified class name that you can then use in your method pattern.
For instance, let's say we have a class like this:
The three pieces of information we need to know to identify the method would be:
org.foo.Bar
- the fully qualified class name where the method is definedbaz
- the method name itselfString, int
– the method's argument types
Combining the three would make this method pattern:
You might be wondering, "What if baz
returned an object instead of void
? Isn't that missing in the method pattern?
That information isn't actually needed as methods in Java (and similar languages) can be uniquely identified by the fully qualified receiver type, method name, and argument types alone.
Method patterns can also accept wildcard symbols if you want to search for or change many methods. There are two kinds of wildcard symbols:
*
- Matches any one thing. Applicable to receiver type, method name, and arguments...
- Matches zero or more. Applicable to receiver type and arguments.
In the following section, we will provide some examples of how to use these.
Examples
Check out the Moderne introduction to type-aware code searches for an example of how method patterns can be used by users running recipes.
The below table shows some more examples of method patterns and the methods they match:
Method Pattern | Matches |
---|---|
| Exactly the single argument overload of |
| Exactly the two argument overload of |
| Any overload of |
| Any method on |
| Exactly the String.format(String format, Object... args) method with varargs. |
| Exactly the String.format(String format, Object... args) method with varargs. |
| Any method on |
| Any method accepting any arguments on classes named "String" in any package. |
| Any method accepting any arguments on any class. |
| Any method named |
| Any method named |
| Any method named |
| Exactly the |
Method patterns match against a method's declaration. Methods that take in a variable number of arguments represent these variadic parameters as an array.
For example, the method pattern String.format(String, Object[])
would match all of these method invocations, regardless of the number of varargs passed:
Usage
Configuring recipes
Recipes that take in method patterns as arguments take them in as strings. In YAML that looks like this:
or they can take in wildcards like this:
Constructing a similarly configured instance of the same recipe in Java would look like this:
or
Authoring recipes with MethodMatcher
org.openrewrite.java.MethodMatcher
is the class that most recipes will use method patterns with. Instances are created by providing the method pattern to its constructor:
MethodMatcher.matches()
has overloads that accept method declarations, method invocations, and constructor invocations. matches()
returns true
if the argument matches the method pattern the matcher was initialized with. They are frequently used by visitors to avoid making changes to LST elements other than those indicated by the method pattern.
Last updated