1 package com.fasterxml.classmate;
2
3 import java.lang.reflect.TypeVariable;
4 import java.util.*;
5
6
10 public final class TypeBindings
11 {
12 private final static String[] NO_STRINGS = new String[0];
13
14 private final static ResolvedType[] NO_TYPES = new ResolvedType[0];
15
16 private final static TypeBindings EMPTY = new TypeBindings(NO_STRINGS, NO_TYPES, null);
17
18
21 private final String[] _names;
22
23
26 private final ResolvedType[] _types;
27
28
33 private final String[] _unboundVariables;
34
35 private final int _hashCode;
36
37
42
43 private TypeBindings(String[] names, ResolvedType[] types, String[] uvars)
44 {
45 _names = (names == null) ? NO_STRINGS : names;
46 _types = (types == null) ? NO_TYPES : types;
47 if (_names.length != _types.length) {
48 throw new IllegalArgumentException("Mismatching names ("+_names.length+"), types ("+_types.length+")");
49 }
50 int h = 1;
51 for (int i = 0, len = _types.length; i < len; ++i) {
52 h += _types[i].hashCode();
53 }
54 _unboundVariables = uvars;
55 _hashCode = h;
56 }
57
58 public static TypeBindings emptyBindings() {
59 return EMPTY;
60 }
61
62
66 public static TypeBindings create(Class<?> erasedType, List<ResolvedType> typeList)
67 {
68 ResolvedType[] types = (typeList == null || typeList.isEmpty()) ?
69 NO_TYPES : typeList.toArray(new ResolvedType[0]);
70 return create(erasedType, types);
71 }
72
73 public static TypeBindings create(Class<?> erasedType, ResolvedType[] types)
74 {
75 if (types == null) {
76 types = NO_TYPES;
77 }
78 TypeVariable<?>[] vars = erasedType.getTypeParameters();
79 String[] names;
80 if (vars == null || vars.length == 0) {
81 names = NO_STRINGS;
82 } else {
83 int len = vars.length;
84 names = new String[len];
85 for (int i = 0; i < len; ++i) {
86 names[i] = vars[i].getName();
87 }
88 }
89
90 if (names.length != types.length) {
91 throw new IllegalArgumentException("Can not create TypeBinding for class "+erasedType.getName()
92 +" with "+types.length+" type parameter"
93 +((types.length == 1) ? "" : "s")+": class expects "+names.length);
94 }
95 return new TypeBindings(names, types, null);
96 }
97
98
105 public TypeBindings withUnboundVariable(String name)
106 {
107 int len = (_unboundVariables == null) ? 0 : _unboundVariables.length;
108 String[] names = (len == 0)
109 ? new String[1] : Arrays.copyOf(_unboundVariables, len+1);
110 names[len] = name;
111 return new TypeBindings(_names, _types, names);
112 }
113
114
119
120
123 public ResolvedType findBoundType(String name)
124 {
125 for (int i = 0, len = _names.length; i < len; ++i) {
126 if (name.equals(_names[i])) {
127 return _types[i];
128 }
129 }
130 return null;
131 }
132
133 public boolean isEmpty() {
134 return (_types.length == 0);
135 }
136
137
140 public int size() {
141 return _types.length;
142 }
143
144 public String getBoundName(int index)
145 {
146 if (index < 0 || index >= _names.length) {
147 return null;
148 }
149 return _names[index];
150 }
151
152 public ResolvedType getBoundType(int index)
153 {
154 if (index < 0 || index >= _types.length) {
155 return null;
156 }
157 return _types[index];
158 }
159
160
163 public List<ResolvedType> getTypeParameters()
164 {
165 if (_types.length == 0) {
166 return Collections.emptyList();
167 }
168 return Arrays.asList(_types);
169 }
170
171
174 public boolean hasUnbound(String name) {
175 if (_unboundVariables != null) {
176 for (int i = _unboundVariables.length; --i >= 0; ) {
177 if (name.equals(_unboundVariables[i])) {
178 return true;
179 }
180 }
181 }
182 return false;
183 }
184
185
190
191 @Override public String toString()
192 {
193 if (_types.length == 0) {
194 return "";
195 }
196 StringBuilder sb = new StringBuilder();
197 sb.append('<');
198 for (int i = 0, len = _types.length; i < len; ++i) {
199 if (i > 0) {
200 sb.append(',');
201 }
202 sb = _types[i].appendBriefDescription(sb);
203 }
204 sb.append('>');
205 return sb.toString();
206 }
207
208 @Override public int hashCode() { return _hashCode; }
209
210 @Override public boolean equals(Object o)
211 {
212 if (o == this) return true;
213 if (o == null || o.getClass() != getClass()) return false;
214 TypeBindings other = (TypeBindings) o;
215 int len = _types.length;
216 if (len != other.size()) {
217 return false;
218 }
219 ResolvedType[] otherTypes = other._types;
220 for (int i = 0; i < len; ++i) {
221 if (!otherTypes[i].equals(_types[i])) {
222 return false;
223 }
224 }
225 return true;
226 }
227
228
233
234 protected ResolvedType[] typeParameterArray() {
235 return _types;
236 }
237 }
238