@@ -140,14 +140,14 @@ public ElementMatcher.Junction<ClassLoader> classLoaderMatcher() {
140140
141141#### Rules for ` classLoaderMatcher() `
142142
143- - ** Every ` InstrumentationModule ` should override ` classLoaderMatcher() ` ** with a
144- ` hasClassesNamed(...) ` check for a class from the module's target library. This allows
145- the agent to skip the entire module early — before evaluating type matchers or muzzle —
146- when the target library is absent .
147- ** Exceptions ** — do not flag: modules under ` instrumentation/internal/ ` (JDK/agent internals),
148- modules instrumenting JDK classes on all supported Java versions (executors,
149- http-url-connection, java-util-logging, rmi, jdbc), config-driven modules with no fixed
150- target library ( ` methods ` , ` external-annotations ` ), and test-only modules .
143+ - ** Do NOT add ` classLoaderMatcher() ` for optimization. ** The "skip when library is absent"
144+ optimization belongs on ` TypeInstrumentation.classLoaderOptimization() ` , not here.
145+ ` classLoaderMatcher() ` is only for ** version-boundary detection ** — cases where muzzle
146+ alone cannot distinguish the target version range. Most modules do not need it .
147+ - ** Do NOT flag modules that lack a ` classLoaderMatcher() ` override. ** The default ( ` any() ` )
148+ is correct when muzzle can detect version boundaries on its own (the common case). Only
149+ flag a * missing * override when the module targets a specific version range and the
150+ versioning signal (added/removed landmark class) is not part of the classes muzzle inspects .
151151- ** Version comments on landmark classes.** For multi-class checks, ` .and(not(...)) `
152152 chains, or cases where the landmark version differs from the module's base version,
153153 each ` hasClassesNamed() ` call must have a ` // ` comment stating the library version
@@ -185,7 +185,7 @@ public class MyClassInstrumentation implements TypeInstrumentation {
185185 @Override
186186 public void transform (TypeTransformer transformer ) {
187187 transformer. applyAdviceToMethod(
188- isMethod() . and( named(" execute" ) ). and(takesArguments(1 )),
188+ named(" execute" ). and(takesArguments(1 )),
189189 getClass(). getName() + " $ExecuteAdvice" );
190190 }
191191
@@ -196,6 +196,32 @@ public class MyClassInstrumentation implements TypeInstrumentation {
196196}
197197```
198198
199+ ### ` classLoaderOptimization() ` — Skip When Library Absent
200+
201+ Override ` classLoaderOptimization() ` when the ` typeMatcher() ` uses expensive matchers
202+ (e.g., ` implementsInterface(...) ` , ` extendsClass(...) ` , ` isAnnotatedWith(...) ` ). This is
203+ a fast pre-filter that runs before type matching: if a class from the target library is
204+ absent, the expensive type matcher is skipped entirely.
205+
206+ ``` java
207+ @Override
208+ public ElementMatcher<ClassLoader > classLoaderOptimization() {
209+ return hasClassesNamed(" com.example.library.TargetClass" );
210+ }
211+ ```
212+
213+ ** This is the correct place for "skip when library is absent" optimization** — not
214+ ` InstrumentationModule.classLoaderMatcher() ` . The module-level ` classLoaderMatcher() ` is
215+ ANDed with ` classLoaderOptimization() ` at runtime, so the type-level check alone is
216+ sufficient for optimization.
217+
218+ ** When to override:**
219+
220+ - The ` typeMatcher() ` uses hierarchy matchers (` implementsInterface ` , ` extendsClass ` ) or
221+ annotation matchers — these require bytecode inspection of super classes/interfaces.
222+ - The ` typeMatcher() ` uses ` named(...) ` or ` namedOneOf(...) ` — no override needed because
223+ name-only matchers are already fast (they check only the class name, no bytecode).
224+
199225### Rules
200226
201227- Do not flag or change the visibility or ` final ` modifier on ` TypeInstrumentation ` ,
@@ -206,6 +232,9 @@ public class MyClassInstrumentation implements TypeInstrumentation {
206232 ` extendsClass(...) ` and ` implementsInterface(...) ` are appropriate when the instrumentation
207233 targets subclasses or implementors of a type.
208234- ` transform() ` wires method matchers to advice classes via ` applyAdviceToMethod() ` .
235+ - Do not add ` isMethod() ` in method matchers inside ` transform() ` . ` isMethod() ` only
236+ serves to exclude constructors, but ` named(...) ` already excludes them because
237+ constructors are named ` <init> ` . Remove ` isMethod() ` when not needed.
209238- Reference the advice class using ` getClass().getName() + "$InnerClassName" ` — not
210239 ` InnerClassName.class.getName() ` , ` OuterClass.class.getName() ` , or a string literal.
211240 Any ` .class.getName() ` reference — whether to the inner advice class or the outer
0 commit comments