javainstrumentationbyte-buddyjavaagents

How to use matchers for the argument of canThrow() with ByteBuddy?


I'm writing some code where I would like to instrument every method in a class that throws a specific exception, so I would like to have something like this:

builder.method(ElementMatchers.canThrow(nameStartsWith("RestClientException")));

However, these types do not work since canThrow expects either a Class or a TypeDescription.

I do not believe using RestClientException.class would work here, as I want to create a Java Agent, and so I would have to include spring-web in my client just to use the class here, which furthermore i believe would not work correctly if this is not the exact same version as the application being instrumented.

This leaves TypeDescription as the option, but I do not know if there is a way to turn an ElementMatcher into a TypeDescription. ByteBuddy has a good tutorial but a very unwieldy and difficult to navigate javadoc, so I am asking this question here.

I could use a different way of matching all these functions, but this seems like a nice shortcut and good to know if it is or is not possible in general.


Solution

  • The simplest solution would be to implement a custom element matcher:

    ElementMatcher.Junction<MethodDescription> matcher = new ElementMatcher.Junction.AbstractBase<MethodDescription>() {
        @Override
        public boolean matches(MethodDescription target) {
            for (TypeDescription.Generic exceptionType : target.getExceptionTypes()) {
                if (exceptionType.asErasure().getName().startsWith("org.springframework.web.client.RestClientException")) {
                    return true;
                }
            }
            return false;
        }
    };
    

    The ElementMatchers API only contains common cases, and I'll consider including your scenario. But generally speaking, a custom matcher might offer the easiest approach.

    Note that you need to match the package name, not just the simple name.