All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fitbur.bytebuddy.matcher.ElementMatcher Maven / Gradle / Ivy

There is a newer version: 1.0.0
Show newest version
package com.fitbur.bytebuddy.matcher;

/**
 * An element matcher is used as a predicate for identifying code elements such as types, methods, fields or
 * annotations. They are similar to Java 8's {@code Predicate}s but compatible to Java 6 and Java 7 and represent
 * a functional interface. They can be chained by using instances of
 * {@link com.fitbur.bytebuddy.matcher.ElementMatcher.Junction}.
 *
 * @param  The type of the object that is being matched.
 */
public interface ElementMatcher {

    /**
     * Matches a target against this element matcher.
     *
     * @param target The instance to be matched.
     * @return {@code true} if the given element is matched by this matcher or {@code false} otherwise.
     */
    boolean matches(T target);

    /**
     * A junctions allows to chain different {@link com.fitbur.bytebuddy.matcher.ElementMatcher}s in a readable manner.
     *
     * @param  The type of the object that is being matched.
     */
    interface Junction extends ElementMatcher {

        /**
         * Creates a conjunction where this matcher and the {@code other} matcher must both be matched in order
         * to constitute a successful match. The other matcher is only invoked if this matcher constitutes a successful
         * match.
         *
         * @param other The second matcher to consult.
         * @param    The type of the object that is being matched. Note that Java's type inference might not
         *              be able to infer the common subtype of this instance and the {@code other} matcher such that
         *              this type must need to be named explicitly.
         * @return A conjunction of this matcher and the other matcher.
         */
         Junction and(ElementMatcher other);

        /**
         * Creates a disjunction where either this matcher or the {@code other} matcher must be matched in order
         * to constitute a successful match. The other matcher is only invoked if this matcher constitutes an
         * unsuccessful match.
         *
         * @param other The second matcher to consult.
         * @param    The type of the object that is being matched. Note that Java's type inference might not
         *              be able to infer the common subtype of this instance and the {@code other} matcher such that
         *              this type must need to be named explicitly.
         * @return A disjunction of this matcher and the other matcher.
         */
         Junction or(ElementMatcher other);

        /**
         * A base implementation of {@link com.fitbur.bytebuddy.matcher.ElementMatcher.Junction}.
         *
         * @param  The type of the object that is being matched.
         */
        abstract class AbstractBase implements Junction {

            @Override
            public  Junction and(ElementMatcher other) {
                return new Conjunction(this, other);
            }

            @Override
            public  Junction or(ElementMatcher other) {
                return new Disjunction(this, other);
            }
        }

        /**
         * A conjunction matcher which only matches an element if both represented matchers constitute a match.
         *
         * @param  The type of the object that is being matched.
         */
        class Conjunction extends AbstractBase {

            /**
             * The element matchers that constitute this conjunction.
             */
            private final ElementMatcher left, right;

            /**
             * Creates a new conjunction matcher.
             *
             * @param left  The first matcher to consult for a match.
             * @param right The second matcher to consult for a match. This matcher is only consulted
             *              if the {@code first} matcher constituted a match.
             */
            public Conjunction(ElementMatcher left, ElementMatcher right) {
                this.left = left;
                this.right = right;
            }

            @Override
            public boolean matches(W target) {
                return left.matches(target) && right.matches(target);
            }

            @Override
            public boolean equals(Object other) {
                return this == other || !(other == null || getClass() != other.getClass())
                        && left.equals(((Conjunction) other).left)
                        && right.equals(((Conjunction) other).right);
            }

            @Override
            public int hashCode() {
                return 31 * left.hashCode() + right.hashCode();
            }

            @Override
            public String toString() {
                return "(" + left + " and " + right + ')';
            }
        }

        /**
         * A disjunction matcher which only matches an element if both represented matchers constitute a match.
         *
         * @param  The type of the object that is being matched.
         */
        class Disjunction extends AbstractBase {

            /**
             * The element matchers that constitute this disjunction.
             */
            private final ElementMatcher left, right;

            /**
             * Creates a new disjunction matcher.
             *
             * @param left  The first matcher to consult for a match.
             * @param right The second matcher to consult for a match. This matcher is only consulted
             *              if the {@code first} matcher did not already constitute a match.
             */
            public Disjunction(ElementMatcher left, ElementMatcher right) {
                this.left = left;
                this.right = right;
            }

            @Override
            public boolean matches(W target) {
                return left.matches(target) || right.matches(target);
            }

            @Override
            public boolean equals(Object other) {
                return this == other || !(other == null || getClass() != other.getClass())
                        && left.equals(((Disjunction) other).left)
                        && right.equals(((Disjunction) other).right);
            }

            @Override
            public int hashCode() {
                return 27 * left.hashCode() + right.hashCode();
            }

            @Override
            public String toString() {
                return "(" + left + " or " + right + ')';
            }
        }
    }
}