1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.grouplens.grapht.context;
21
22 import org.apache.commons.lang3.builder.EqualsBuilder;
23 import org.apache.commons.lang3.builder.HashCodeBuilder;
24 import org.apache.commons.lang3.tuple.Pair;
25 import org.grouplens.grapht.reflect.InjectionPoint;
26 import org.grouplens.grapht.reflect.QualifierMatcher;
27 import org.grouplens.grapht.reflect.Qualifiers;
28 import org.grouplens.grapht.reflect.Satisfaction;
29 import org.grouplens.grapht.util.ClassProxy;
30 import org.grouplens.grapht.util.Types;
31
32 import javax.annotation.Nullable;
33 import javax.inject.Qualifier;
34 import java.io.InvalidObjectException;
35 import java.io.ObjectInputStream;
36 import java.io.ObjectStreamException;
37 import java.io.Serializable;
38
39
40
41
42
43
44
45
46 class TypeElementMatcher implements ContextElementMatcher, Serializable {
47 private static final long serialVersionUID = -1L;
48
49 @Nullable
50 private final transient Class<?> type;
51 private final transient QualifierMatcher qualifier;
52
53
54
55
56
57
58
59
60 public TypeElementMatcher(Class<?> type) {
61 this(type, Qualifiers.matchDefault());
62 }
63
64
65
66
67
68
69
70
71
72 public TypeElementMatcher(Class<?> type, QualifierMatcher qualifier) {
73 this.type = type;
74 this.qualifier = qualifier;
75 }
76
77
78
79
80 public Class<?> getMatchedType() {
81 return type;
82 }
83
84
85
86
87 public QualifierMatcher getMatchedQualifier() {
88 return qualifier;
89 }
90
91 @Override
92 public MatchElement apply(Pair<Satisfaction, InjectionPoint> n) {
93
94 Satisfaction sat = n.getLeft();
95 boolean typeMatches;
96 if (type == null) {
97 typeMatches = sat == null
98 || sat.getErasedType() == null
99 || sat.getType().equals(Void.TYPE);
100 } else {
101 typeMatches = sat != null && sat.getErasedType() != null &&
102 type.isAssignableFrom(sat.getErasedType());
103 }
104
105 if (typeMatches && qualifier.matches(n.getRight().getQualifier())) {
106 return new MatchElem(sat == null ? null : sat.getErasedType(),
107 type, qualifier);
108 } else {
109 return null;
110 }
111 }
112
113 @Override
114 public boolean equals(Object o) {
115 if (o == this) {
116 return true;
117 } else if (o instanceof TypeElementMatcher) {
118 TypeElementMatcher r = (TypeElementMatcher) o;
119 return new EqualsBuilder().append(type, r.type)
120 .append(qualifier, r.qualifier)
121 .isEquals();
122 } else {
123 return false;
124 }
125 }
126
127 @Override
128 public int hashCode() {
129 return new HashCodeBuilder().append(type)
130 .append(qualifier)
131 .toHashCode();
132 }
133
134 @Override
135 public String toString() {
136 String tname = type == null ? "null" : type.getSimpleName();
137 return "[" + qualifier + ":" + tname + "]";
138 }
139
140 private static class MatchElem implements MatchElement {
141 private final Class<?> matchedType;
142 private final Class<?> patternType;
143 private final QualifierMatcher qualMatcher;
144
145 private MatchElem(Class<?> mtype, Class<?> ptype, QualifierMatcher qmatch) {
146 matchedType = mtype;
147 patternType = ptype;
148 qualMatcher = qmatch;
149 }
150
151 @Override
152 public ContextElements.MatchPriority getPriority() {
153 return ContextElements.MatchPriority.TYPE;
154 }
155
156 @Override
157 public Integer getTypeDistance() {
158 return Types.getTypeDistance(matchedType, patternType);
159 }
160
161 @Override
162 public boolean equals(Object o) {
163 if (this == o) {
164 return true;
165 } else if (o instanceof MatchElem) {
166 MatchElem other = (MatchElem) o;
167 EqualsBuilder eqb = new EqualsBuilder();
168 return eqb.append(matchedType, other.matchedType)
169 .append(patternType, other.patternType)
170 .append(qualMatcher, other.qualMatcher)
171 .isEquals();
172 } else {
173 return false;
174 }
175 }
176
177 @Override
178 public int hashCode() {
179 HashCodeBuilder hcb = new HashCodeBuilder();
180 return hcb.append(matchedType)
181 .append(patternType)
182 .append(qualMatcher)
183 .toHashCode();
184 }
185
186 @Override
187 public String toString() {
188 return String.format("Match(%s,%s)", matchedType, patternType);
189 }
190 }
191
192 private Object writeReplace() {
193 return new SerialProxy(type, qualifier);
194 }
195
196 private void readObject(ObjectInputStream stream) throws ObjectStreamException {
197 throw new InvalidObjectException("must use serialization proxy");
198 }
199
200 private static class SerialProxy implements Serializable {
201 private static final long serialVersionUID = 2L;
202
203 private final ClassProxy type;
204 private final QualifierMatcher qualifier;
205
206 public SerialProxy(Class<?> t, QualifierMatcher qual) {
207 type = ClassProxy.of(t);
208 qualifier = qual;
209 }
210
211 @SuppressWarnings("unchecked")
212 private Object readResolve() throws ObjectStreamException {
213 try {
214 return new TypeElementMatcher(type.resolve(),
215 qualifier);
216 } catch (ClassNotFoundException e) {
217 InvalidObjectException ex = new InvalidObjectException("cannot resolve " + type);
218 ex.initCause(e);
219 throw ex;
220 }
221 }
222 }
223 }