1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mybatis.generator.api.dom.java;
17
18 import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;
19 import static org.mybatis.generator.internal.util.messages.Messages.getString;
20
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Objects;
24 import java.util.StringTokenizer;
25 import java.util.stream.Collectors;
26
27 public class FullyQualifiedJavaType implements Comparable<FullyQualifiedJavaType> {
28
29 private static final String JAVA_LANG = "java.lang";
30
31 private static FullyQualifiedJavaType intInstance = null;
32
33 private static FullyQualifiedJavaType stringInstance = null;
34
35 private static FullyQualifiedJavaType booleanPrimitiveInstance = null;
36
37 private static FullyQualifiedJavaType objectInstance = null;
38
39 private static FullyQualifiedJavaType dateInstance = null;
40
41 private static FullyQualifiedJavaType criteriaInstance = null;
42
43 private static FullyQualifiedJavaType generatedCriteriaInstance = null;
44
45
46 private String baseShortName;
47
48
49 private String baseQualifiedName;
50
51 private boolean explicitlyImported;
52
53 private String packageName;
54
55 private boolean primitive;
56
57 private boolean isArray;
58
59 private PrimitiveTypeWrapper primitiveTypeWrapper;
60
61 private final List<FullyQualifiedJavaType> typeArguments;
62
63
64 private boolean wildcardType;
65
66 private boolean boundedWildcard;
67
68 private boolean extendsBoundedWildcard;
69
70
71
72
73
74
75
76 public FullyQualifiedJavaType(String fullTypeSpecification) {
77 super();
78 typeArguments = new ArrayList<>();
79 parse(fullTypeSpecification);
80 }
81
82 public boolean isExplicitlyImported() {
83 return explicitlyImported;
84 }
85
86
87
88
89
90
91 public String getFullyQualifiedName() {
92 String s = getFullyQualifiedNameWithoutTypeParameters();
93
94 if (typeArguments.isEmpty()) {
95 return s;
96 } else {
97 return typeArguments.stream()
98 .map(FullyQualifiedJavaType::getFullyQualifiedName)
99 .collect(Collectors.joining(", ", s + "<", ">"));
100 }
101 }
102
103 public String getFullyQualifiedNameWithoutTypeParameters() {
104 return calculateBaseType(baseQualifiedName);
105 }
106
107
108
109
110
111
112 public String getImportName() {
113 return baseQualifiedName;
114 }
115
116
117
118
119
120
121
122 public List<String> getImportList() {
123 List<String> answer = new ArrayList<>();
124 if (isExplicitlyImported()) {
125 int index = baseShortName.indexOf('.');
126 if (index == -1) {
127 answer.add(calculateActualImport(baseQualifiedName));
128 } else {
129
130
131 String sb = packageName + '.' + calculateActualImport(baseShortName.substring(0, index));
132 answer.add(sb);
133 }
134 }
135
136 typeArguments.forEach(t -> answer.addAll(t.getImportList()));
137
138 return answer;
139 }
140
141 private String calculateActualImport(String name) {
142 String answer = name;
143 if (this.isArray()) {
144 int index = name.indexOf('[');
145 if (index != -1) {
146 answer = name.substring(0, index);
147 }
148 }
149 return answer;
150 }
151
152 public String getPackageName() {
153 return packageName;
154 }
155
156 public String getShortName() {
157 String s = getShortNameWithoutTypeArguments();
158
159 if (typeArguments.isEmpty()) {
160 return s;
161 } else {
162 return typeArguments.stream()
163 .map(FullyQualifiedJavaType::getShortName)
164 .collect(Collectors.joining(", ", s + "<", ">"));
165 }
166 }
167
168 public String getShortNameWithoutTypeArguments() {
169 return calculateBaseType(baseShortName);
170 }
171
172 private String calculateBaseType(String name) {
173 StringBuilder sb = new StringBuilder();
174 if (wildcardType) {
175 sb.append('?');
176 if (boundedWildcard) {
177 if (extendsBoundedWildcard) {
178 sb.append(" extends ");
179 } else {
180 sb.append(" super ");
181 }
182
183 sb.append(name);
184 }
185 } else {
186 sb.append(name);
187 }
188 return sb.toString();
189 }
190
191 @Override
192 public boolean equals(Object obj) {
193 if (this == obj) {
194 return true;
195 }
196
197 if (!(obj instanceof FullyQualifiedJavaType other)) {
198 return false;
199 }
200
201 return getFullyQualifiedName().equals(other.getFullyQualifiedName());
202 }
203
204 @Override
205 public int hashCode() {
206 return getFullyQualifiedName().hashCode();
207 }
208
209 @Override
210 public String toString() {
211 return getFullyQualifiedName();
212 }
213
214 public boolean isPrimitive() {
215 return primitive;
216 }
217
218 public PrimitiveTypeWrapper getPrimitiveTypeWrapper() {
219 return primitiveTypeWrapper;
220 }
221
222 public static FullyQualifiedJavaType getIntInstance() {
223 if (intInstance == null) {
224 intInstance = new FullyQualifiedJavaType("int");
225 }
226
227 return intInstance;
228 }
229
230 public static FullyQualifiedJavaType getNewListInstance() {
231
232 return new FullyQualifiedJavaType("java.util.List");
233 }
234
235 public static FullyQualifiedJavaType getNewHashMapInstance() {
236
237 return new FullyQualifiedJavaType("java.util.HashMap");
238 }
239
240 public static FullyQualifiedJavaType getNewArrayListInstance() {
241
242 return new FullyQualifiedJavaType("java.util.ArrayList");
243 }
244
245 public static FullyQualifiedJavaType getNewIteratorInstance() {
246
247 return new FullyQualifiedJavaType("java.util.Iterator");
248 }
249
250 public static FullyQualifiedJavaType getStringInstance() {
251 stringInstance = Objects.requireNonNullElseGet(stringInstance,
252 () -> new FullyQualifiedJavaType("java.lang.String"));
253 return stringInstance;
254 }
255
256 public static FullyQualifiedJavaType getBooleanPrimitiveInstance() {
257 booleanPrimitiveInstance = Objects.requireNonNullElseGet(booleanPrimitiveInstance,
258 () -> new FullyQualifiedJavaType("boolean"));
259 return booleanPrimitiveInstance;
260 }
261
262 public static FullyQualifiedJavaType getObjectInstance() {
263 objectInstance = Objects.requireNonNullElseGet(objectInstance,
264 () -> new FullyQualifiedJavaType("java.lang.Object"));
265 return objectInstance;
266 }
267
268 public static FullyQualifiedJavaType getDateInstance() {
269 dateInstance = Objects.requireNonNullElseGet(dateInstance,
270 () -> new FullyQualifiedJavaType("java.util.Date"));
271 return dateInstance;
272 }
273
274 public static FullyQualifiedJavaType getCriteriaInstance() {
275 criteriaInstance = Objects.requireNonNullElseGet(criteriaInstance,
276 () -> new FullyQualifiedJavaType("Criteria"));
277 return criteriaInstance;
278 }
279
280 public static FullyQualifiedJavaType getGeneratedCriteriaInstance() {
281 generatedCriteriaInstance = Objects.requireNonNullElseGet(generatedCriteriaInstance,
282 () -> new FullyQualifiedJavaType("GeneratedCriteria"));
283 return generatedCriteriaInstance;
284 }
285
286 @Override
287 public int compareTo(FullyQualifiedJavaType other) {
288 return getFullyQualifiedName().compareTo(other.getFullyQualifiedName());
289 }
290
291 public void addTypeArgument(FullyQualifiedJavaType type) {
292 typeArguments.add(type);
293 }
294
295 private void parse(String fullTypeSpecification) {
296 String spec = fullTypeSpecification.trim();
297
298 if (spec.startsWith("?")) {
299 wildcardType = true;
300 spec = spec.substring(1).trim();
301 if (spec.startsWith("extends ")) {
302 boundedWildcard = true;
303 extendsBoundedWildcard = true;
304 spec = spec.substring(8);
305 } else if (spec.startsWith("super ")) {
306 boundedWildcard = true;
307 extendsBoundedWildcard = false;
308 spec = spec.substring(6);
309 } else {
310 boundedWildcard = false;
311 }
312 parse(spec);
313 } else {
314 int index = fullTypeSpecification.indexOf('<');
315 if (index == -1) {
316 simpleParse(fullTypeSpecification);
317 } else {
318 simpleParse(fullTypeSpecification.substring(0, index));
319 int endIndex = fullTypeSpecification.lastIndexOf('>');
320 if (endIndex == -1) {
321 throw new RuntimeException(getString(
322 "RuntimeError.22", fullTypeSpecification));
323 }
324 genericParse(fullTypeSpecification.substring(index, endIndex + 1));
325 }
326
327
328
329
330
331 isArray = fullTypeSpecification.endsWith("]");
332 }
333 }
334
335 private void simpleParse(String typeSpecification) {
336 baseQualifiedName = typeSpecification.trim();
337 if (baseQualifiedName.contains(".")) {
338 packageName = getPackage(baseQualifiedName);
339 baseShortName = baseQualifiedName.substring(packageName.length() + 1);
340 int index = baseShortName.lastIndexOf('.');
341 if (index != -1) {
342 baseShortName = baseShortName.substring(index + 1);
343 }
344
345
346 explicitlyImported = !JAVA_LANG.equals(packageName);
347 } else {
348 baseShortName = baseQualifiedName;
349 explicitlyImported = false;
350 packageName = "";
351
352 switch (baseQualifiedName) {
353 case "byte":
354 primitive = true;
355 primitiveTypeWrapper = PrimitiveTypeWrapper.getByteInstance();
356 break;
357 case "short":
358 primitive = true;
359 primitiveTypeWrapper = PrimitiveTypeWrapper.getShortInstance();
360 break;
361 case "int":
362 primitive = true;
363 primitiveTypeWrapper = PrimitiveTypeWrapper.getIntegerInstance();
364 break;
365 case "long":
366 primitive = true;
367 primitiveTypeWrapper = PrimitiveTypeWrapper.getLongInstance();
368 break;
369 case "char":
370 primitive = true;
371 primitiveTypeWrapper = PrimitiveTypeWrapper.getCharacterInstance();
372 break;
373 case "float":
374 primitive = true;
375 primitiveTypeWrapper = PrimitiveTypeWrapper.getFloatInstance();
376 break;
377 case "double":
378 primitive = true;
379 primitiveTypeWrapper = PrimitiveTypeWrapper.getDoubleInstance();
380 break;
381 case "boolean":
382 primitive = true;
383 primitiveTypeWrapper = PrimitiveTypeWrapper.getBooleanInstance();
384 break;
385 default:
386 primitive = false;
387 primitiveTypeWrapper = null;
388 break;
389 }
390 }
391 }
392
393 private void genericParse(String genericSpecification) {
394 int lastIndex = genericSpecification.lastIndexOf('>');
395 if (lastIndex == -1) {
396
397 throw new RuntimeException(getString(
398 "RuntimeError.22", genericSpecification));
399 }
400 String argumentString = genericSpecification.substring(1, lastIndex);
401
402 StringTokenizer st = new StringTokenizer(argumentString, ",<>", true);
403 int openCount = 0;
404 StringBuilder sb = new StringBuilder();
405 while (st.hasMoreTokens()) {
406 String token = st.nextToken();
407 if ("<".equals(token)) {
408 sb.append(token);
409 openCount++;
410 } else if (">".equals(token)) {
411 sb.append(token);
412 openCount--;
413 } else if (",".equals(token)) {
414 if (openCount == 0) {
415 typeArguments
416 .add(new FullyQualifiedJavaType(sb.toString()));
417 sb.setLength(0);
418 } else {
419 sb.append(token);
420 }
421 } else {
422 sb.append(token);
423 }
424 }
425
426 if (openCount != 0) {
427 throw new RuntimeException(getString(
428 "RuntimeError.22", genericSpecification));
429 }
430
431 String finalType = sb.toString();
432 if (stringHasValue(finalType)) {
433 typeArguments.add(new FullyQualifiedJavaType(finalType));
434 }
435 }
436
437
438
439
440
441
442
443
444
445
446
447
448
449 private static String getPackage(String baseQualifiedName) {
450 int index = baseQualifiedName.lastIndexOf('.');
451 return baseQualifiedName.substring(0, index);
452 }
453
454 public boolean isArray() {
455 return isArray;
456 }
457
458 public List<FullyQualifiedJavaType> getTypeArguments() {
459 return typeArguments;
460 }
461 }