1 /*
2  * Copyright 2014 - 2020 Rafael Winterhalter
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package net.bytebuddy.matcher;
17
18 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
19
20 /**
21  * An element matcher is used as a predicate for identifying code elements such as types, methods, fields or
22  * annotations. They are similar to Java 8's {@code Predicate}s but compatible to Java 6 and Java 7 and represent
23  * a functional interface. They can be chained by using instances of
24  * {@link net.bytebuddy.matcher.ElementMatcher.Junction}.
25  *
26  * @param <T> The type of the object that is being matched.
27  */

28 public interface ElementMatcher<T> {
29
30     /**
31      * Matches a target against this element matcher.
32      *
33      * @param target The instance to be matched.
34      * @return {@code trueif the given element is matched by this matcher or {@code false} otherwise.
35      */

36     boolean matches(T target);
37
38     /**
39      * A junctions allows to chain different {@link net.bytebuddy.matcher.ElementMatcher}s in a readable manner.
40      *
41      * @param <S> The type of the object that is being matched.
42      */

43     interface Junction<S> extends ElementMatcher<S> {
44
45         /**
46          * Creates a conjunction where this matcher and the {@code other} matcher must both be matched in order
47          * to constitute a successful match. The other matcher is only invoked if this matcher constitutes a successful
48          * match.
49          *
50          * @param other The second matcher to consult.
51          * @param <U>   The type of the object that is being matched. Note that Java's type inference might not
52          *              be able to infer the common subtype of this instance and the {@code other} matcher such that
53          *              this type must need to be named explicitly.
54          * @return A conjunction of this matcher and the other matcher.
55          */

56         <U extends S> Junction<U> and(ElementMatcher<? super U> other);
57
58         /**
59          * Creates a disjunction where either this matcher or the {@code other} matcher must be matched in order
60          * to constitute a successful match. The other matcher is only invoked if this matcher constitutes an
61          * unsuccessful match.
62          *
63          * @param other The second matcher to consult.
64          * @param <U>   The type of the object that is being matched. Note that Java's type inference might not
65          *              be able to infer the common subtype of this instance and the {@code other} matcher such that
66          *              this type must need to be named explicitly.
67          * @return A disjunction of this matcher and the other matcher.
68          */

69         <U extends S> Junction<U> or(ElementMatcher<? super U> other);
70
71         /**
72          * A base implementation of {@link net.bytebuddy.matcher.ElementMatcher.Junction}.
73          *
74          * @param <V> The type of the object that is being matched.
75          */

76         abstract class AbstractBase<V> implements Junction<V> {
77
78             /**
79              * {@inheritDoc}
80              */

81             public <U extends V> Junction<U> and(ElementMatcher<? super U> other) {
82                 return new Conjunction<U>(this, other);
83             }
84
85             /**
86              * {@inheritDoc}
87              */

88             public <U extends V> Junction<U> or(ElementMatcher<? super U> other) {
89                 return new Disjunction<U>(this, other);
90             }
91         }
92
93         /**
94          * A conjunction matcher which only matches an element if both represented matchers constitute a match.
95          *
96          * @param <W> The type of the object that is being matched.
97          */

98         @HashCodeAndEqualsPlugin.Enhance
99         class Conjunction<W> extends AbstractBase<W> {
100
101             /**
102              * The element matchers that constitute this conjunction.
103              */

104             private final ElementMatcher<? super W> left, right;
105
106             /**
107              * Creates a new conjunction matcher.
108              *
109              * @param left  The first matcher to consult for a match.
110              * @param right The second matcher to consult for a match. This matcher is only consulted
111              *              if the {@code first} matcher constituted a match.
112              */

113             public Conjunction(ElementMatcher<? super W> left, ElementMatcher<? super W> right) {
114                 this.left = left;
115                 this.right = right;
116             }
117
118             /**
119              * {@inheritDoc}
120              */

121             public boolean matches(W target) {
122                 return left.matches(target) && right.matches(target);
123             }
124
125             @Override
126             public String toString() {
127                 return "(" + left + " and " + right + ')';
128             }
129         }
130
131         /**
132          * A disjunction matcher which only matches an element if both represented matchers constitute a match.
133          *
134          * @param <W> The type of the object that is being matched.
135          */

136         @HashCodeAndEqualsPlugin.Enhance
137         class Disjunction<W> extends AbstractBase<W> {
138
139             /**
140              * The element matchers that constitute this disjunction.
141              */

142             private final ElementMatcher<? super W> left, right;
143
144             /**
145              * Creates a new disjunction matcher.
146              *
147              * @param left  The first matcher to consult for a match.
148              * @param right The second matcher to consult for a match. This matcher is only consulted
149              *              if the {@code first} matcher did not already constitute a match.
150              */

151             public Disjunction(ElementMatcher<? super W> left, ElementMatcher<? super W> right) {
152                 this.left = left;
153                 this.right = right;
154             }
155
156             /**
157              * {@inheritDoc}
158              */

159             public boolean matches(W target) {
160                 return left.matches(target) || right.matches(target);
161             }
162
163             @Override
164             public String toString() {
165                 return "(" + left + " or " + right + ')';
166             }
167         }
168     }
169 }
170