Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Add support for intercepting methods #656

Open
wants to merge 10 commits into
base: master
Choose a base branch
from

Conversation

EotT123
Copy link
Contributor

@EotT123 EotT123 commented Jan 12, 2025

This PR introduces the concept of intercepting (existing) methods, allowing you to modify their logic or introduce custom behavior before or after the original method executes.
The method's signature remains unchanged, meaning the return type, parameters, and any declared exceptions must be
preserved.
To intercept a method, simply annotate the (extension) method with @Intercept.

Consider the following example:

package extensions.java.lang.String;

@Extension
public class MyStringExtension {
    @Intercept
    public static String trim(@This String thiz) {
        return thiz == null ? null : thiz.trim();
    }
}
String text = null;
text.trim(); // returns null
text = "  myTestString  ";
text.trim(); // returns 'myTestString'

@rsmckinney
Copy link
Member

Interesting PR. I haven't looked at the code yet, but there is a limitation that you may or may not have considered already. Since this has to be implemented by rewriting the call site, it can only cover usages in the source files of the consuming project/module. Calls from external code will not be intercepted, particularly concerning for API code, callbacks, and the like.

I don't think this is a showstopper, but it should be clearly documented, maybe it is already?

Couple other random thoughts.

  1. Super calls. What happens with super.foo() when foo is intercepted? You would have to use reflection for this, I would think.
  2. Method references. What happens with MyClass::foo?

@EotT123
Copy link
Contributor Author

EotT123 commented Jan 19, 2025

Thank you for the valid remarks.

Intercepted methods behave similarly to regular extensions, sharing the same behavior and limitations. There are only a few differences in how intercepted methods are handled:

  • During Code Generation:
    • Unlike regular extensions, where a warning occurs if a duplicate is found, the interception process warns if no matching method is found.
    • Rather than adding a new method, the existing method is annotated with either ExtensionMethod or ForwardingExtensionMethod.
  • During Invocation Replacement:
    • Verification whether an intercepted method invocation should be replaced. A method should not be intercepted if it is invoked from within the body of the method being intercepted (i.e., the invocation is part of the method's own execution).

In response to your questions:

  • Calls from external code are indeed not intercepted, I'll clarify this in the documentation.
  • Super calls are not (yet) supported. I'll have a look at that.
  • Method references are not supported. Since the same code is used as the regular extensions, the same error is thrown:-Extension method '<method_name>' must be invoked as a lambda expression here.
    I’m currently working on adding support for it (including for regular extensions), but I’ll create a separate PR for that.
    Implemented in Add support for method references invoking extension methods #665.

@EotT123 EotT123 changed the title Add support for intercepting methods WIP: Add support for intercepting methods Jan 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants