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 true} if 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