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

org.testifyproject.bytebuddy.matcher.LatentMatcher Maven / Gradle / Ivy

There is a newer version: 1.0.6
Show newest version
package org.testifyproject.bytebuddy.matcher;

import org.testifyproject.bytebuddy.description.field.FieldDescription;
import org.testifyproject.bytebuddy.description.method.MethodDescription;
import org.testifyproject.bytebuddy.description.type.TypeDescription;

import java.util.Arrays;
import java.util.List;

import static org.testifyproject.bytebuddy.matcher.ElementMatchers.none;

/**
 * A latent matcher that resolves an {@link ElementMatcher} after supplying the instrumented type.
 *
 * @param  The type of the matched element.
 */
public interface LatentMatcher {

    /**
     * Resolves the element matcher this instance represents for the instrumented type.
     *
     * @param instrumentedType The instrumented type.
     * @return An {@link ElementMatcher} that represents this matcher's resolved form.
     */
    ElementMatcher resolve(TypeDescription instrumentedType);

    /**
     * A latent matcher representing an already resolved {@link ElementMatcher}.
     *
     * @param  The type of the matched element.
     */
    class Resolved implements LatentMatcher {

        /**
         * The resolved matcher.
         */
        private final ElementMatcher matcher;

        /**
         * Creates a new resolved latent matcher.
         *
         * @param matcher The resolved matcher.
         */
        public Resolved(ElementMatcher matcher) {
            this.matcher = matcher;
        }

        @Override
        public ElementMatcher resolve(TypeDescription instrumentedType) {
            return matcher;
        }

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

        @Override
        public int hashCode() {
            return matcher.hashCode();
        }

        @Override
        public String toString() {
            return "LatentMatcher.Resolved{" +
                    "matcher=" + matcher +
                    '}';
        }
    }

    /**
     * A latent matcher where the field token is being attached to the instrumented type before matching.
     */
    class ForFieldToken implements LatentMatcher {

        /**
         * A token representing the field being matched.
         */
        private final FieldDescription.Token token;

        /**
         * Creates a new latent matcher for a field token.
         *
         * @param token A token representing the field being matched.
         */
        public ForFieldToken(FieldDescription.Token token) {
            this.token = token;
        }

        @Override
        public ElementMatcher resolve(TypeDescription instrumentedType) {
            return new ResolvedMatcher(token.asSignatureToken(instrumentedType));
        }

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

        @Override
        public int hashCode() {
            return token.hashCode();
        }

        @Override
        public String toString() {
            return "LatentMatcher.ForFieldToken{" +
                    "token=" + token +
                    '}';
        }

        /**
         * A resolved matcher of a latent field matcher for a field token.
         */
        protected static class ResolvedMatcher implements ElementMatcher {

            /**
             * The signature token representing the matched field.
             */
            private final FieldDescription.SignatureToken signatureToken;

            /**
             * Creates a new resolved matcher.
             *
             * @param signatureToken The signature token representing the matched field.
             */
            protected ResolvedMatcher(FieldDescription.SignatureToken signatureToken) {
                this.signatureToken = signatureToken;
            }

            @Override
            public boolean matches(FieldDescription target) {
                return target.asSignatureToken().equals(signatureToken);
            }

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

            @Override
            public int hashCode() {
                return signatureToken.hashCode();
            }

            @Override
            public String toString() {
                return "LatentMatcher.ForFieldToken.ResolvedMatcher{" +
                        "signatureToken=" + signatureToken +
                        '}';
            }
        }
    }

    /**
     * A latent matcher where the method token is being attached to the instrumented type before matching.
     */
    class ForMethodToken implements LatentMatcher {

        /**
         * A token representing the method being matched.
         */
        private final MethodDescription.Token token;

        /**
         * Creates a new latent matcher for a method token.
         *
         * @param token A token representing the method being matched.
         */
        public ForMethodToken(MethodDescription.Token token) {
            this.token = token;
        }

        @Override
        public ElementMatcher resolve(TypeDescription instrumentedType) {
            return new ResolvedMatcher(token.asSignatureToken(instrumentedType));
        }

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

        @Override
        public int hashCode() {
            return token.hashCode();
        }

        @Override
        public String toString() {
            return "LatentMatcher.ForMethodToken{" +
                    "token=" + token +
                    '}';
        }

        /**
         * A resolved matcher of a latent method matcher for a method token.
         */
        protected static class ResolvedMatcher implements ElementMatcher {

            /**
             * The signature token representing the matched field.
             */
            private final MethodDescription.SignatureToken signatureToken;

            /**
             * Creates a new resolved matcher.
             *
             * @param signatureToken The signature token representing the matched field.
             */
            protected ResolvedMatcher(MethodDescription.SignatureToken signatureToken) {
                this.signatureToken = signatureToken;
            }

            @Override
            public boolean matches(MethodDescription target) {
                return target.asSignatureToken().equals(signatureToken);
            }

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

            @Override
            public int hashCode() {
                return signatureToken.hashCode();
            }

            @Override
            public String toString() {
                return "LatentMatcher.ForMethodToken.ResolvedMatcher{" +
                        "signatureToken=" + signatureToken +
                        '}';
            }
        }
    }

    /**
     * A compound implementation of a latent matcher. A compound matcher matches a method if at least one of the resolved matchers
     * matches the target element.
     *
     * @param  The type of the matched element.
     */
    class Compound implements LatentMatcher {

        /**
         * The matchers this compound matcher represents.
         */
        private final List> matchers;

        /**
         * Creates a new compound latent matcher.
         *
         * @param matcher The matchers this compound matcher represents.
         */
        //@SafeVarargs
        public Compound(LatentMatcher... matcher) {
            this(Arrays.asList(matcher));
        }

        /**
         * Creates a new compound latent matcher.
         *
         * @param matchers The matchers this compound matcher represents.
         */
        public Compound(List> matchers) {
            this.matchers = matchers;
        }

        @Override
        public ElementMatcher resolve(TypeDescription instrumentedType) {
            ElementMatcher.Junction matcher = none();
            for (LatentMatcher latentMatcher : matchers) {
                matcher = matcher.or(latentMatcher.resolve(instrumentedType));
            }
            return matcher;
        }

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

        @Override
        public int hashCode() {
            return matchers.hashCode();
        }

        @Override
        public String toString() {
            return "LatentMatcher.Compound{" +
                    "matchers=" + matchers +
                    '}';
        }
    }
}