diff --git a/class-match/src/main/java/datadog/instrument/classmatch/AccessMatcher.java b/class-match/src/main/java/datadog/instrument/classmatch/AccessMatcher.java new file mode 100644 index 0000000..0015df6 --- /dev/null +++ b/class-match/src/main/java/datadog/instrument/classmatch/AccessMatcher.java @@ -0,0 +1,89 @@ +/* + * Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2025-Present Datadog, Inc. + */ + +package datadog.instrument.classmatch; + +import java.lang.reflect.Modifier; +import java.util.function.IntPredicate; + +/** + * Predicate for matching access modifiers defined in class-files. + */ +@FunctionalInterface +public interface AccessMatcher extends IntPredicate { + + /** Matches public access. */ + AccessMatcher PUBLIC = Modifier::isPublic; + + /** Matches private access. */ + AccessMatcher PRIVATE = Modifier::isPrivate; + + /** Matches protected access. */ + AccessMatcher PROTECTED = Modifier::isProtected; + + /** Matches package-private access. */ + AccessMatcher PACKAGE_PRIVATE = + acc -> (acc & (Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE)) == 0; + + /** Matches static methods/fields. */ + AccessMatcher STATIC = Modifier::isStatic; + + /** Matches non-static methods/fields. */ + AccessMatcher INSTANCE = acc -> (acc & Modifier.STATIC) == 0; + + /** Matches final classes/methods/fields. */ + AccessMatcher FINAL = Modifier::isFinal; + + /** Matches non-final classes/methods/fields. */ + AccessMatcher NON_FINAL = acc -> (acc & Modifier.FINAL) == 0; + + /** Matches synchronized methods. */ + AccessMatcher SYNCHRONIZED = Modifier::isSynchronized; + + /** Matches varargs methods. */ + AccessMatcher VARARGS = acc -> (acc & 0x0080) != 0; + + /** Matches volatile fields. */ + AccessMatcher VOLATILE = Modifier::isVolatile; + + /** Matches transient fields. */ + AccessMatcher TRANSIENT = Modifier::isTransient; + + /** Matches interface classes. */ + AccessMatcher INTERFACE = Modifier::isInterface; + + /** Matches non-interface classes. */ + AccessMatcher CLASS = acc -> (acc & Modifier.INTERFACE) == 0; + + /** Matches abstract classes/methods. */ + AccessMatcher ABSTRACT = Modifier::isAbstract; + + /** Matches non-abstract classes/methods. */ + AccessMatcher CONCRETE = acc -> (acc & Modifier.ABSTRACT) == 0; + + /** + * Conjunction of this matcher AND another. + * + * @param other the other matcher + * @return conjunction of both matchers + */ + default AccessMatcher and(AccessMatcher other) { + // simple approach as we don't expect many access-matcher unions + return acc -> test(acc) && other.test(acc); + } + + /** + * Disjunction of this matcher OR another. + * + * @param other the other matcher + * @return disjunction of both matchers + */ + default AccessMatcher or(AccessMatcher other) { + // simple approach as we don't expect many access-matcher unions + return acc -> test(acc) || other.test(acc); + } +} diff --git a/class-match/src/main/java/datadog/instrument/classmatch/ClassMatcher.java b/class-match/src/main/java/datadog/instrument/classmatch/ClassMatcher.java index 837d66a..7aed30e 100644 --- a/class-match/src/main/java/datadog/instrument/classmatch/ClassMatcher.java +++ b/class-match/src/main/java/datadog/instrument/classmatch/ClassMatcher.java @@ -12,7 +12,6 @@ import static java.util.Arrays.asList; import java.util.Collection; -import java.util.function.IntPredicate; import java.util.function.Predicate; /** Fluent-API for building {@link ClassOutline} predicates. */ @@ -36,7 +35,7 @@ static ClassMatcher declares(FieldMatcher fieldMatcher) { * @param fieldMatcher the field matcher * @return matcher of classes with a matching field */ - static ClassMatcher declares(IntPredicate accessMatcher, FieldMatcher fieldMatcher) { + static ClassMatcher declares(AccessMatcher accessMatcher, FieldMatcher fieldMatcher) { FieldMatcher combinedMatcher = fieldMatcher.access(accessMatcher); return c -> anyMatch(c.fields, combinedMatcher); } @@ -58,7 +57,7 @@ static ClassMatcher declares(MethodMatcher methodMatcher) { * @param methodMatcher the method matcher * @return matcher of classes with a matching method */ - static ClassMatcher declares(IntPredicate accessMatcher, MethodMatcher methodMatcher) { + static ClassMatcher declares(AccessMatcher accessMatcher, MethodMatcher methodMatcher) { MethodMatcher combinedMatcher = methodMatcher.access(accessMatcher); return c -> anyMatch(c.methods, combinedMatcher); } diff --git a/class-match/src/main/java/datadog/instrument/classmatch/FieldMatcher.java b/class-match/src/main/java/datadog/instrument/classmatch/FieldMatcher.java index fe4c108..742b375 100644 --- a/class-match/src/main/java/datadog/instrument/classmatch/FieldMatcher.java +++ b/class-match/src/main/java/datadog/instrument/classmatch/FieldMatcher.java @@ -8,7 +8,6 @@ import static datadog.instrument.classmatch.InternalMatchers.descriptor; -import java.util.function.IntPredicate; import java.util.function.Predicate; /** Fluent-API for building {@link FieldOutline} predicates. */ @@ -41,7 +40,7 @@ static FieldMatcher field(Predicate nameMatcher) { * @param accessMatcher the access matcher * @return matcher of fields with matching access */ - default FieldMatcher access(IntPredicate accessMatcher) { + default FieldMatcher access(AccessMatcher accessMatcher) { return f -> test(f) && accessMatcher.test(f.access); } diff --git a/class-match/src/main/java/datadog/instrument/classmatch/MethodMatcher.java b/class-match/src/main/java/datadog/instrument/classmatch/MethodMatcher.java index 7e9a8eb..7235bd0 100644 --- a/class-match/src/main/java/datadog/instrument/classmatch/MethodMatcher.java +++ b/class-match/src/main/java/datadog/instrument/classmatch/MethodMatcher.java @@ -16,7 +16,6 @@ import static java.util.Arrays.asList; import java.util.Collection; -import java.util.function.IntPredicate; import java.util.function.Predicate; /** Fluent-API for building {@link MethodOutline} predicates. */ @@ -76,7 +75,7 @@ static MethodMatcher staticInitializer() { * @param accessMatcher the access matcher * @return matcher of methods with matching access */ - default MethodMatcher access(IntPredicate accessMatcher) { + default MethodMatcher access(AccessMatcher accessMatcher) { return and(m -> accessMatcher.test(m.access)); } diff --git a/class-match/src/main/java/datadog/instrument/classmatch/StandardMatchers.java b/class-match/src/main/java/datadog/instrument/classmatch/StandardMatchers.java index 1fefda2..958551e 100644 --- a/class-match/src/main/java/datadog/instrument/classmatch/StandardMatchers.java +++ b/class-match/src/main/java/datadog/instrument/classmatch/StandardMatchers.java @@ -8,58 +8,63 @@ import static java.util.Arrays.asList; -import java.lang.reflect.Modifier; import java.util.Collection; import java.util.HashSet; -import java.util.function.IntPredicate; import java.util.function.Predicate; /** Standard matchers, part of the public API. */ public final class StandardMatchers { - /** Matches public access. */ - public static final IntPredicate PUBLIC = Modifier::isPublic; - - /** Matches private access. */ - public static final IntPredicate PRIVATE = Modifier::isPrivate; - - /** Matches protected access. */ - public static final IntPredicate PROTECTED = Modifier::isProtected; - - /** Matches static access. */ - public static final IntPredicate STATIC = Modifier::isStatic; - - /** Matches final classes/methods/fields. */ - public static final IntPredicate FINAL = Modifier::isFinal; - - /** Matches synchronized methods. */ - public static final IntPredicate SYNCHRONIZED = Modifier::isSynchronized; - - /** Matches volatile fields. */ - public static final IntPredicate VOLATILE = Modifier::isVolatile; - - /** Matches transient fields. */ - public static final IntPredicate TRANSIENT = Modifier::isTransient; + private StandardMatchers() {} - /** Matches native methods. */ - public static final IntPredicate NATIVE = Modifier::isNative; + /** + * Negates the given type matcher. + * + * @param matcher the matcher to negate + * @return negation of the matcher + */ + public static TypeMatcher not(TypeMatcher matcher) { + return cs -> !matcher.test(cs); + } - /** Matches interface classes. */ - public static final IntPredicate INTERFACE = Modifier::isInterface; + /** + * Negates the given class matcher. + * + * @param matcher the matcher to negate + * @return negation of the matcher + */ + public static ClassMatcher not(ClassMatcher matcher) { + return c -> !matcher.test(c); + } - /** Matches abstract classes. */ - public static final IntPredicate ABSTRACT = Modifier::isAbstract; + /** + * Negates the given field matcher. + * + * @param matcher the matcher to negate + * @return negation of the matcher + */ + public static FieldMatcher not(FieldMatcher matcher) { + return f -> !matcher.test(f); + } - private StandardMatchers() {} + /** + * Negates the given method matcher. + * + * @param matcher the matcher to negate + * @return negation of the matcher + */ + public static MethodMatcher not(MethodMatcher matcher) { + return m -> !matcher.test(m); + } /** - * Syntactic sugar around {@link IntPredicate#negate()}. + * Negates the given access matcher. * - * @param predicate the predicate to negate - * @return negated predicate + * @param matcher the matcher to negate + * @return negation of the matcher */ - public static IntPredicate not(IntPredicate predicate) { - return predicate.negate(); + public static AccessMatcher not(AccessMatcher matcher) { + return acc -> !matcher.test(acc); } /** diff --git a/class-match/src/main/java/datadog/instrument/classmatch/TypeMatcher.java b/class-match/src/main/java/datadog/instrument/classmatch/TypeMatcher.java index af1ea37..54eedaa 100644 --- a/class-match/src/main/java/datadog/instrument/classmatch/TypeMatcher.java +++ b/class-match/src/main/java/datadog/instrument/classmatch/TypeMatcher.java @@ -13,6 +13,7 @@ import java.util.function.Predicate; /** Fluent-API for building type hierarchy predicates. */ +@FunctionalInterface public interface TypeMatcher extends Predicate { /**