1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.juneau;
18
19 import static org.apache.juneau.ClassMeta.Category.*;
20 import static org.apache.juneau.commons.reflect.ReflectionUtils.*;
21 import static org.apache.juneau.commons.utils.CollectionUtils.*;
22 import static org.apache.juneau.commons.utils.ThrowableUtils.*;
23 import static org.apache.juneau.commons.utils.Utils.*;
24
25 import java.io.*;
26 import java.lang.annotation.*;
27 import java.lang.reflect.*;
28 import java.lang.reflect.Proxy;
29 import java.net.*;
30 import java.time.temporal.*;
31 import java.util.*;
32 import java.util.List;
33 import java.util.concurrent.*;
34 import java.util.function.*;
35
36 import org.apache.juneau.annotation.*;
37 import org.apache.juneau.commons.collections.*;
38 import org.apache.juneau.commons.function.*;
39 import org.apache.juneau.commons.reflect.*;
40 import org.apache.juneau.commons.utils.*;
41 import org.apache.juneau.cp.*;
42 import org.apache.juneau.json.*;
43 import org.apache.juneau.reflect.*;
44 import org.apache.juneau.swap.*;
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 @Bean(properties = "innerClass,elementType,keyType,valueType,notABeanReason,initException,beanMeta")
68 public class ClassMeta<T> extends ClassInfoTyped<T> {
69
70 private static class Categories {
71 int bits;
72
73 public boolean same(Categories cat) {
74 return cat.bits == bits;
75 }
76
77 boolean is(Category c) {
78 return (bits & c.mask) != 0;
79 }
80
81 boolean isUnknown() {
82 return bits == 0;
83 }
84
85 Categories set(Category c) {
86 bits |= c.mask;
87 return this;
88 }
89 }
90
91 enum Category {
92 MAP(0),
93 COLLECTION(1),
94 NUMBER(2),
95 DECIMAL(3),
96 DATE(4),
97 ARRAY(5),
98 ENUM(6),
99 CHARSEQ(8),
100 STR(9),
101 URI(10),
102 BEANMAP(11),
103 READER(12),
104 INPUTSTREAM(13),
105 ARGS(14),
106 CALENDAR(15),
107 TEMPORAL(16),
108 LIST(17),
109 SET(18),
110 DELEGATE(19),
111 BEAN(20);
112
113 private final int mask;
114
115 Category(int bitPosition) {
116 this.mask = 1 << bitPosition;
117 }
118 }
119
120
121
122
123
124
125
126
127
128
129
130 private static boolean isCacheable(Class<?> c) {
131 var n = cn(c);
132 var x = n.charAt(n.length() - 1);
133 if (x >= '0' && x <= '9') {
134 if (n.indexOf("$$") != -1 || n.startsWith("sun") || n.startsWith("com.sun") || n.indexOf("$Proxy") != -1)
135 return false;
136 }
137 return true;
138 }
139
140 private final List<ClassMeta<?>> args;
141 private final BeanContext beanContext;
142 private final Supplier<BuilderSwap<T,?>> builderSwap;
143 private final Categories cat;
144 private final Cache<Class<?>,ObjectSwap<?,?>> childSwapMap;
145 private final Supplier<List<ObjectSwap<?,?>>> childSwaps;
146 private final Cache<Class<?>,ObjectSwap<?,?>> childUnswapMap;
147 private final Supplier<String> beanDictionaryName;
148 private final Supplier<ClassMeta<?>> elementType;
149 private final OptionalSupplier<String> example;
150 private final OptionalSupplier<FieldInfo> exampleField;
151 private final OptionalSupplier<MethodInfo> exampleMethod;
152 private final Supplier<BidiMap<Object,String>> enumValues;
153 private final Map<Class<?>,Mutater<?,T>> fromMutaters = new ConcurrentHashMap<>();
154 private final OptionalSupplier<MethodInfo> fromStringMethod;
155 private final OptionalSupplier<ClassInfoTyped<? extends T>> implClass;
156 private final Supplier<KeyValueTypes> keyValueTypes;
157 private final OptionalSupplier<MarshalledFilter> marshalledFilter;
158 private final Supplier<Property<T,Object>> nameProperty;
159 private final OptionalSupplier<ConstructorInfo> noArgConstructor;
160 private final Supplier<Property<T,Object>> parentProperty;
161 private final Cache<String,Optional<?>> properties;
162 private final Mutater<String,T> stringMutater;
163 private final OptionalSupplier<ConstructorInfo> stringConstructor;
164 private final Supplier<List<ObjectSwap<T,?>>> swaps;
165 private final Map<Class<?>,Mutater<T,?>> toMutaters = new ConcurrentHashMap<>();
166 private final OptionalSupplier<BeanMeta.BeanMetaValue<T>> beanMeta;
167
168 private record KeyValueTypes(ClassMeta<?> keyType, ClassMeta<?> valueType) {
169 Optional<ClassMeta<?>> optKeyType() { return opt(keyType()); }
170 Optional<ClassMeta<?>> optValueType() { return opt(valueType()); }
171 }
172
173
174
175
176
177
178
179
180
181
182 ClassMeta(Class<T> innerClass, BeanContext beanContext) {
183 super(innerClass);
184 this.beanContext = beanContext;
185 this.cat = new Categories();
186
187
188 if (nn(beanContext) && nn(beanContext.getCmCache()) && isCacheable(innerClass))
189 beanContext.getCmCache().put(innerClass, this);
190
191 var ap = beanContext.getAnnotationProvider();
192
193 if (isChildOf(Delegate.class)) {
194 cat.set(DELEGATE);
195 }
196 if (isEnum()) {
197 cat.set(ENUM);
198 } else if (isChildOf(CharSequence.class)) {
199 cat.set(CHARSEQ);
200 if (is(String.class)) {
201 cat.set(STR);
202 }
203 } else if (isChildOf(Number.class) || isAny(byte.class, short.class, int.class, long.class, float.class, double.class)) {
204 cat.set(NUMBER);
205 if (isChildOfAny(Float.class, Double.class) || isAny(float.class, double.class)) {
206 cat.set(DECIMAL);
207 }
208 } else if (isChildOf(Collection.class)) {
209 cat.set(COLLECTION);
210 if (isChildOf(Set.class)) {
211 cat.set(SET);
212 } else if (isChildOf(List.class)) {
213 cat.set(LIST);
214 }
215 } else if (isChildOf(Map.class)) {
216 cat.set(MAP);
217 if (isChildOf(BeanMap.class)) {
218 cat.set(BEANMAP);
219 }
220 } else if (isChildOfAny(Date.class, Calendar.class)) {
221 if (isChildOf(Date.class)) {
222 cat.set(DATE);
223 } else if (isChildOf(Calendar.class)) {
224 cat.set(CALENDAR);
225 }
226 } else if (isChildOf(Temporal.class)) {
227 cat.set(TEMPORAL);
228 } else if (inner().isArray()) {
229 cat.set(ARRAY);
230 } else if (isChildOfAny(URL.class, URI.class) || ap.has(Uri.class, this)) {
231 cat.set(URI);
232 } else if (isChildOf(Reader.class)) {
233 cat.set(READER);
234 } else if (isChildOf(InputStream.class)) {
235 cat.set(INPUTSTREAM);
236 }
237
238 beanMeta = mem(()->findBeanMeta());
239 builderSwap = mem(()->findBuilderSwap());
240 childSwapMap = Cache.<Class<?>,ObjectSwap<?,?>>create().supplier(x -> findSwap(x)).build();
241 childSwaps = mem(()->findChildSwaps());
242 childUnswapMap = Cache.<Class<?>,ObjectSwap<?,?>>create().supplier(x -> findUnswap(x)).build();
243 beanDictionaryName = mem(()->findBeanDictionaryName());
244 elementType = mem(()->findElementType());
245 enumValues = mem(()->findEnumValues());
246 example = mem(()->findExample());
247 exampleField = mem(()->findExampleField());
248 exampleMethod = mem(()->findExampleMethod());
249 fromStringMethod = mem(()->findFromStringMethod());
250 implClass = mem(()->findImplClass());
251 keyValueTypes = mem(()->findKeyValueTypes());
252 marshalledFilter = mem(()->findMarshalledFilter());
253 nameProperty = mem(()->findNameProperty());
254 noArgConstructor = mem(()->findNoArgConstructor());
255 parentProperty = mem(()->findParentProperty());
256 properties = Cache.<String,Optional<?>>create().build();
257 stringConstructor = mem(()->findStringConstructor());
258 swaps = mem(()->findSwaps());
259
260 this.args = null;
261 this.stringMutater = Mutaters.get(String.class, inner());
262 }
263
264 protected ObjectSwap<?,?> findSwap(Class<?> c) {
265 return childSwaps.get().stream().filter(x -> x.getNormalClass().isParentOf(c)).findFirst().orElse(null);
266 }
267
268 protected ObjectSwap<?,?> findUnswap(Class<?> c) {
269 return childSwaps.get().stream().filter(x -> x.getSwapClass().isParentOf(c)).findFirst().orElse(null);
270 }
271
272
273
274
275
276 @SuppressWarnings("unchecked")
277 ClassMeta(List<ClassMeta<?>> args) {
278 super((Class<T>)Object[].class);
279 this.args = args;
280 this.childSwaps = mem(()->findChildSwaps());
281 this.childSwapMap = null;
282 this.childUnswapMap = null;
283 this.cat = new Categories().set(ARGS);
284 this.beanContext = null;
285 this.elementType = mem(()->findElementType());
286 this.keyValueTypes = mem(()->findKeyValueTypes());
287 this.beanMeta = mem(()->findBeanMeta());
288 this.swaps = mem(()->findSwaps());
289 this.stringMutater = null;
290 this.fromStringMethod = mem(()->findFromStringMethod());
291 this.exampleMethod = mem(()->findExampleMethod());
292 this.parentProperty = mem(()->findParentProperty());
293 this.nameProperty = mem(()->findNameProperty());
294 this.exampleField = mem(()->findExampleField());
295 this.noArgConstructor = mem(()->findNoArgConstructor());
296 this.properties = Cache.<String,Optional<?>>create().build();
297 this.stringConstructor = mem(()->findStringConstructor());
298 this.marshalledFilter = mem(()->findMarshalledFilter());
299 this.builderSwap = mem(()->findBuilderSwap());
300 this.example = mem(()->findExample());
301 this.implClass = mem(()->findImplClass());
302 this.enumValues = mem(()->findEnumValues());
303 this.beanDictionaryName = mem(()->findBeanDictionaryName());
304 }
305
306
307
308
309
310
311
312 ClassMeta(ClassMeta<T> mainType, ClassMeta<?> keyType, ClassMeta<?> valueType, ClassMeta<?> elementType) {
313 super(mainType.inner());
314 this.childSwaps = mainType.childSwaps;
315 this.childSwapMap = mainType.childSwapMap;
316 this.childUnswapMap = mainType.childUnswapMap;
317 this.cat = mainType.cat;
318 this.fromStringMethod = mainType.fromStringMethod;
319 this.beanContext = mainType.beanContext;
320 this.elementType = elementType != null ? mem(()->elementType) : mainType.elementType;
321 this.keyValueTypes = (keyType != null || valueType != null) ? mem(()->new KeyValueTypes(keyType, valueType)) : mainType.keyValueTypes;
322 this.beanMeta = mainType.beanMeta;
323 this.swaps = mainType.swaps;
324 this.exampleMethod = mainType.exampleMethod;
325 this.args = null;
326 this.stringMutater = mainType.stringMutater;
327 this.parentProperty = mainType.parentProperty;
328 this.nameProperty = mainType.nameProperty;
329 this.exampleField = mainType.exampleField;
330 this.noArgConstructor = mainType.noArgConstructor;
331 this.properties = mainType.properties;
332 this.stringConstructor = mainType.stringConstructor;
333 this.marshalledFilter = mainType.marshalledFilter;
334 this.builderSwap = mainType.builderSwap;
335 this.example = mainType.example;
336 this.implClass = mainType.implClass;
337 this.enumValues = mainType.enumValues;
338 this.beanDictionaryName = mainType.beanDictionaryName;
339 }
340
341
342
343
344
345
346
347
348
349
350
351 public boolean canCreateNewBean(Object outer) {
352 var bm = getBeanMeta();
353 if (bm == null || ! bm.hasConstructor())
354 return false;
355 if (isMemberClass() && isNotStatic())
356 return nn(outer) && bm.getConstructor().hasParameterTypes(outer.getClass());
357 return true;
358 }
359
360
361
362
363
364
365 public boolean canCreateNewInstance() {
366 if (isMemberClass() && isNotStatic())
367 return false;
368 var bm = getBeanMeta();
369 if (noArgConstructor.isPresent() || (bm != null && bm.getBeanProxyInvocationHandler() != null) || (isArray() && elementType.get().canCreateNewInstance()))
370 return true;
371 return false;
372 }
373
374
375
376
377
378
379
380
381
382
383
384 public boolean canCreateNewInstance(Object outer) {
385 if (isMemberClass() && isNotStatic())
386 return nn(outer) && noArgConstructor.map(x -> x.hasParameterTypes(outer.getClass())).orElse(false);
387 return canCreateNewInstance();
388 }
389
390
391
392
393
394
395
396
397
398 public boolean canCreateNewInstanceFromString(Object outer) {
399 if (fromStringMethod.isPresent())
400 return true;
401 if (stringConstructor.isPresent()) {
402 if (isMemberClass() && isNotStatic())
403 return nn(outer) && stringConstructor.map(x -> x.hasParameterTypes(outer.getClass(), String.class)).orElse(false);
404 return true;
405 }
406 return false;
407 }
408
409 @Override
410 public boolean equals(Object o) {
411 return (o instanceof ClassMeta<?>) && super.equals(o);
412 }
413
414
415
416
417
418
419
420
421
422
423 public <A extends Annotation> ClassMeta<T> forEachAnnotation(Class<A> type, Predicate<A> filter, Consumer<A> action) {
424 if (beanContext != null) {
425 beanContext.getAnnotationProvider().find(type, this).stream().map(AnnotationInfo::inner).filter(x -> filter == null || filter.test(x)).forEach(x -> action.accept(x));
426 }
427 return this;
428 }
429
430
431
432
433
434
435
436
437 public ClassMeta<?> getArg(int index) {
438 if (nn(args) && index >= 0 && index < args.size())
439 return args.get(index);
440 throw bex("Invalid argument index specified: {0}. Only {1} arguments are defined.", index, args == null ? 0 : args.size());
441 }
442
443
444
445
446
447
448 public List<ClassMeta<?>> getArgs() { return args; }
449
450
451
452
453
454
455 public BeanContext getBeanContext() { return beanContext; }
456
457
458
459
460
461
462
463
464 public BeanMeta<T> getBeanMeta() {
465 return beanMeta.get().beanMeta();
466 }
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481 public BeanRegistry getBeanRegistry() {
482 return beanMeta.get().optBeanMeta().map(x -> x.getBeanRegistry()).orElse(null);
483 }
484
485
486
487
488
489
490
491 public BuilderSwap<T,?> getBuilderSwap(BeanSession session) {
492 return builderSwap.get();
493 }
494
495
496
497
498
499
500
501
502
503
504
505 public String getBeanDictionaryName() {
506 return beanDictionaryName.get();
507 }
508
509
510
511
512
513
514
515 public ClassMeta<?> getElementType() { return elementType.get(); }
516
517
518
519
520
521
522
523
524
525
526 @SuppressWarnings({ "unchecked" })
527 public T getExample(BeanSession session, JsonParserSession jpSession) {
528 try {
529 if (example.isPresent())
530 return jpSession.parse(example.get(), this);
531 if (exampleMethod.isPresent())
532 return (T)exampleMethod.get().invokeLenient(null, session);
533 if (exampleField.isPresent())
534 return (T)exampleField.get().get(null);
535
536 if (isCollection()) {
537 var etExample = getElementType().getExample(session, jpSession);
538 if (nn(etExample)) {
539 if (canCreateNewInstance()) {
540 var c = (Collection<Object>)newInstance();
541 c.add(etExample);
542 return (T)c;
543 }
544 return (T)Collections.singleton(etExample);
545 }
546 } else if (super.isArray()) {
547 var etExample = getElementType().getExample(session, jpSession);
548 if (nn(etExample)) {
549 var o = Array.newInstance(getElementType().inner(), 1);
550 Array.set(o, 0, etExample);
551 return (T)o;
552 }
553 } else if (isMap()) {
554 var vtExample = getValueType().getExample(session, jpSession);
555 var ktExample = getKeyType().getExample(session, jpSession);
556 if (nn(ktExample) && nn(vtExample)) {
557 if (canCreateNewInstance()) {
558 var m = (Map<Object,Object>)newInstance();
559 m.put(ktExample, vtExample);
560 return (T)m;
561 }
562 return (T)Collections.singletonMap(ktExample, vtExample);
563 }
564 }
565
566 return null;
567 } catch (Exception e) {
568 throw new ClassMetaRuntimeException(e);
569 }
570 }
571
572
573
574
575
576
577
578
579 @SuppressWarnings({ "rawtypes", "unchecked" })
580 public <I> Mutater<I,T> getFromMutater(Class<I> c) {
581 Mutater t = fromMutaters.get(c);
582 if (t == Mutaters.NULL)
583 return null;
584 if (t == null) {
585 t = Mutaters.get(c, inner());
586 if (t == null)
587 t = Mutaters.NULL;
588 fromMutaters.put(c, t);
589 }
590 return t == Mutaters.NULL ? null : t;
591 }
592
593
594
595
596
597
598
599 public ConstructorInfo getImplClassConstructor(Visibility conVis) {
600 return implClass.map(x -> x.getNoArgConstructor(conVis).orElse(null)).orElse(null);
601 }
602
603
604
605
606
607
608 public Mutater<InputStream,T> getInputStreamMutater() { return getFromMutater(InputStream.class); }
609
610
611
612
613
614
615 public ClassMeta<?> getKeyType() {
616 return keyValueTypes.get().keyType();
617 }
618
619
620
621
622
623
624
625
626 public Property<T,Object> getNameProperty() { return nameProperty.get(); }
627
628
629
630
631
632
633 public synchronized String getNotABeanReason() {
634 return beanMeta.get().notABeanReason();
635 }
636
637
638
639
640
641
642
643
644
645 public Optional<?> getOptionalDefault() {
646 if (isOptional())
647 return opt(getElementType().getOptionalDefault());
648 return null;
649 }
650
651
652
653
654
655
656
657
658 public Property<T,Object> getParentProperty() { return parentProperty.get(); }
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698 @SuppressWarnings("unchecked")
699 public <T2> Optional<T2> getProperty(String name, Function<ClassMeta<?>,T2> function) {
700 return (Optional<T2>)properties.get(name, () -> opt(function.apply(this)));
701 }
702
703
704
705
706
707
708 public InvocationHandler getProxyInvocationHandler() {
709 return beanMeta.get().optBeanMeta().map(x -> x.getBeanProxyInvocationHandler()).orElse(null);
710 }
711
712
713
714
715
716
717 public Mutater<Reader,T> getReaderMutater() { return getFromMutater(Reader.class); }
718
719
720
721
722
723
724
725
726
727 public ClassMeta<?> getSerializedClassMeta(BeanSession session) {
728 var ps = getSwap(session);
729 return (ps == null ? this : ps.getSwapClassMeta(session));
730 }
731
732
733
734
735
736
737 public Mutater<String,T> getStringMutater() { return stringMutater; }
738
739
740
741
742
743
744
745
746
747
748
749
750 public ObjectSwap<T,?> getSwap(BeanSession session) {
751 var swapsList = swaps.get();
752 if (! swapsList.isEmpty()) {
753 var matchQuant = 0;
754 ObjectSwap<T,?> matchSwap = null;
755
756 for (var swap : swapsList) {
757 var q = swap.match(session);
758 if (q > matchQuant) {
759 matchQuant = q;
760 matchSwap = swap;
761 }
762 }
763
764 if (matchSwap != null)
765 return matchSwap;
766 }
767 return null;
768 }
769
770
771
772
773
774
775
776
777 @SuppressWarnings({ "rawtypes", "unchecked" })
778 public <O> Mutater<T,O> getToMutater(Class<O> c) {
779 Mutater t = toMutaters.get(c);
780 if (t == Mutaters.NULL)
781 return null;
782 if (t == null) {
783 t = Mutaters.get(inner(), c);
784 if (t == null)
785 t = Mutaters.NULL;
786 toMutaters.put(c, t);
787 }
788 return t == Mutaters.NULL ? null : t;
789 }
790
791
792
793
794
795
796 public ClassMeta<?> getValueType() {
797 return keyValueTypes.get().valueType();
798 }
799
800
801
802
803
804
805 public boolean hasInputStreamMutater() {
806 return hasMutaterFrom(InputStream.class);
807 }
808
809
810
811
812
813
814
815 public boolean hasMutaterFrom(Class<?> c) {
816 return nn(getFromMutater(c));
817 }
818
819
820
821
822
823
824
825 public boolean hasMutaterFrom(ClassMeta<?> c) {
826 return nn(getFromMutater(c.inner()));
827 }
828
829
830
831
832
833
834
835 public boolean hasMutaterTo(Class<?> c) {
836 return nn(getToMutater(c));
837 }
838
839
840
841
842
843
844
845 public boolean hasMutaterTo(ClassMeta<?> c) {
846 return nn(getToMutater(c.inner()));
847 }
848
849
850
851
852
853
854 public boolean hasReaderMutater() {
855 return hasMutaterFrom(Reader.class);
856 }
857
858
859
860
861
862
863 public boolean hasStringMutater() {
864 return nn(stringMutater);
865 }
866
867
868
869
870
871
872 public boolean isArgs() { return cat.is(ARGS); }
873
874
875
876
877
878
879 public boolean isBean() { return nn(getBeanMeta()); }
880
881
882
883
884
885
886 public boolean isBeanMap() { return cat.is(BEANMAP); }
887
888
889
890
891
892
893 public boolean isBoolean() { return isAny(boolean.class, Boolean.class); }
894
895
896
897
898
899
900 public boolean isByteArray() { return is(byte[].class); }
901
902
903
904
905
906
907 public boolean isCalendar() { return cat.is(CALENDAR); }
908
909
910
911
912
913
914 public boolean isChar() { return isAny(char.class, Character.class); }
915
916
917
918
919
920
921 public boolean isCharSequence() { return cat.is(CHARSEQ); }
922
923
924
925
926
927
928 public boolean isCollection() { return cat != null && cat.is(COLLECTION); }
929
930
931
932
933
934
935 public boolean isCollectionOrArrayOrOptional() { return cat.is(ARRAY) || is(Optional.class) || cat.is(COLLECTION); }
936
937
938
939
940
941
942 public boolean isDate() { return cat.is(DATE); }
943
944
945
946
947
948
949 public boolean isDateOrCalendar() { return cat.is(DATE) || cat.is(CALENDAR); }
950
951
952
953
954
955
956 public boolean isDateOrCalendarOrTemporal() { return cat.is(DATE) || cat.is(CALENDAR) || cat.is(TEMPORAL); }
957
958
959
960
961
962
963 public boolean isDecimal() { return cat.is(DECIMAL); }
964
965
966
967
968
969
970
971 public boolean isDelegate() { return cat.is(DELEGATE); }
972
973
974
975
976
977
978 public boolean isDouble() { return isAny(Double.class, double.class); }
979
980
981
982
983
984
985 public boolean isFloat() { return isAny(Float.class, float.class); }
986
987
988
989
990
991
992 public boolean isInputStream() { return cat.is(INPUTSTREAM); }
993
994
995
996
997
998
999 public boolean isInteger() { return isAny(Integer.class, int.class); }
1000
1001
1002
1003
1004
1005
1006 public boolean isList() { return cat.is(LIST); }
1007
1008
1009
1010
1011
1012
1013 public boolean isLong() { return isAny(Long.class, long.class); }
1014
1015
1016
1017
1018
1019
1020 public boolean isMap() {
1021
1022 return cat != null && cat.is(MAP);
1023 }
1024
1025
1026
1027
1028
1029
1030 public boolean isMapOrBean() { return cat.is(MAP) || nn(getBeanMeta()); }
1031
1032
1033
1034
1035
1036
1037 public boolean isMethod() { return is(Method.class); }
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048 public boolean isNullable() {
1049 if (isPrimitive())
1050 return is(char.class);
1051 return true;
1052 }
1053
1054
1055
1056
1057
1058
1059 public boolean isNumber() { return cat.is(NUMBER); }
1060
1061
1062
1063
1064
1065
1066 public boolean isObject() { return is(Object.class); }
1067
1068
1069
1070
1071
1072
1073 public boolean isOptional() { return is(Optional.class); }
1074
1075
1076
1077
1078
1079
1080 public boolean isReader() { return cat.is(READER); }
1081
1082
1083
1084
1085
1086
1087 public boolean isSet() { return cat.is(SET); }
1088
1089
1090
1091
1092
1093
1094 public boolean isShort() { return isAny(Short.class, short.class); }
1095
1096
1097
1098
1099
1100
1101 public boolean isString() { return is(String.class); }
1102
1103
1104
1105
1106
1107
1108 public boolean isTemporal() { return cat.is(TEMPORAL); }
1109
1110
1111
1112
1113
1114
1115 public boolean isUri() { return cat != null && cat.is(URI); }
1116
1117
1118
1119
1120
1121
1122
1123 @SuppressWarnings({ "unchecked", "rawtypes" })
1124 public T mutateFrom(Object o) {
1125 Mutater t = getFromMutater(o.getClass());
1126 return (T)(t == null ? null : t.mutate(o));
1127 }
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137 @SuppressWarnings({ "unchecked" })
1138 public <O> O mutateTo(Object o, Class<O> c) {
1139 Mutater<Object,O> t = (Mutater<Object,O>)getToMutater(c);
1140 return t == null ? null : t.mutate(o);
1141 }
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151 public <O> O mutateTo(Object o, ClassMeta<O> c) {
1152 return mutateTo(o, c.inner());
1153 }
1154
1155
1156
1157
1158
1159
1160
1161 @Override
1162 @SuppressWarnings("unchecked")
1163 public T newInstance() throws ExecutableException {
1164 if (super.isArray())
1165 return (T)Array.newInstance(inner().getComponentType(), 0);
1166 if (noArgConstructor.isPresent())
1167 return noArgConstructor.get().newInstance();
1168 var h = getProxyInvocationHandler();
1169 if (nn(h))
1170 return (T)Proxy.newProxyInstance(this.getClass().getClassLoader(), a(inner(), java.io.Serializable.class), h);
1171 return null;
1172 }
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183 public T newInstance(Object outer) throws ExecutableException {
1184 if (isMemberClass() && isNotStatic() && noArgConstructor.isPresent())
1185 return noArgConstructor.get().<T>newInstance(outer);
1186 return newInstance();
1187 }
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206 @SuppressWarnings({ "unchecked" })
1207 public T newInstanceFromString(Object outer, String arg) throws ExecutableException {
1208
1209 if (isEnum()) {
1210 var t = (T)enumValues.get().getKey(arg);
1211 if (t == null && ! beanContext.isIgnoreUnknownEnumValues())
1212 throw new ExecutableException("Could not resolve enum value ''{0}'' on class ''{1}''", arg, cn(inner()));
1213 return t;
1214 }
1215
1216 if (fromStringMethod.isPresent())
1217 return (T)fromStringMethod.get().invoke(null, arg);
1218
1219 if (stringConstructor.isPresent()) {
1220 if (isMemberClass() && isNotStatic())
1221 return stringConstructor.get().<T>newInstance(outer, arg);
1222 return stringConstructor.get().<T>newInstance(arg);
1223 }
1224 throw new ExecutableException("No string constructor or valueOf(String) method found for class '" + cn(inner()) + "'");
1225 }
1226
1227
1228
1229
1230
1231
1232
1233
1234 public boolean same(ClassMeta<?> cm) {
1235 if (equals(cm))
1236 return true;
1237 return (isPrimitive() && cat.same(cm.cat));
1238 }
1239
1240 @Override
1241 public String toString() {
1242 return toString(false);
1243 }
1244
1245
1246
1247
1248
1249
1250
1251 public String toString(boolean simple) {
1252 return toString(new StringBuilder(), simple).toString();
1253 }
1254
1255
1256
1257
1258
1259
1260
1261 public String toString(Object t) {
1262 if (t == null)
1263 return null;
1264 if (isEnum() && beanContext.isUseEnumNames())
1265 return ((Enum<?>)t).name();
1266 return t.toString();
1267 }
1268
1269 @SuppressWarnings("unchecked")
1270 private ObjectSwap<T,?> createSwap(Swap s) {
1271 var c = s.value();
1272 if (ClassUtils.isVoid(c))
1273 c = s.impl();
1274 var ci = info(c);
1275
1276 if (ci.isChildOf(ObjectSwap.class)) {
1277 var ps = BeanCreator.of(ObjectSwap.class).type(ci).run();
1278 if (s.mediaTypes().length > 0)
1279 ps.forMediaTypes(MediaType.ofAll(s.mediaTypes()));
1280 if (! s.template().isEmpty())
1281 ps.withTemplate(s.template());
1282 return ps;
1283 }
1284
1285 if (ci.isChildOf(Surrogate.class)) {
1286 List<SurrogateSwap<?,?>> l = SurrogateSwap.findObjectSwaps(c, beanContext);
1287 if (! l.isEmpty())
1288 return (ObjectSwap<T,?>)l.iterator().next();
1289 }
1290
1291 throw new ClassMetaRuntimeException(c, "Invalid swap class ''{0}'' specified. Must extend from ObjectSwap or Surrogate.", c);
1292 }
1293
1294 private String findBeanDictionaryName() {
1295 if (beanContext == null)
1296 return null;
1297
1298 var d = beanMeta.get().optBeanMeta().map(x -> x.getDictionaryName()).orElse(null);
1299 if (nn(d))
1300 return d;
1301
1302
1303
1304 return beanContext.getAnnotationProvider().find(Bean.class, this)
1305 .stream()
1306 .map(AnnotationInfo::inner)
1307 .filter(x -> ! x.typeName().isEmpty())
1308 .map(x -> x.typeName())
1309 .findFirst()
1310 .orElse(null);
1311 }
1312
1313 private BeanMeta.BeanMetaValue<T> findBeanMeta() {
1314 if (! cat.isUnknown())
1315 return new BeanMeta.BeanMetaValue<>(null, "Known non-bean type");
1316 return BeanMeta.create(this, implClass.get());
1317 }
1318
1319 private KeyValueTypes findKeyValueTypes() {
1320 if (cat.is(MAP) && ! cat.is(BEANMAP)) {
1321
1322 var parameters = beanContext.findParameters(inner(), inner());
1323 if (nn(parameters) && parameters.length == 2) {
1324 return new KeyValueTypes(parameters[0], parameters[1]);
1325 }
1326 return new KeyValueTypes(beanContext.getClassMeta(Object.class), beanContext.getClassMeta(Object.class));
1327 }
1328 return new KeyValueTypes(null, null);
1329 }
1330
1331 private ClassMeta<?> findElementType() {
1332 if (beanContext == null)
1333 return null;
1334 if (cat.is(ARRAY)) {
1335 return beanContext.getClassMeta(inner().getComponentType());
1336 } else if (cat.is(COLLECTION) || is(Optional.class)) {
1337
1338 var parameters = beanContext.findParameters(inner(), inner());
1339 if (nn(parameters) && parameters.length == 1) {
1340 return parameters[0];
1341 }
1342 return beanContext.getClassMeta(Object.class);
1343 }
1344 return null;
1345 }
1346
1347 @SuppressWarnings("unchecked")
1348 private BuilderSwap<T,?> findBuilderSwap() {
1349 var bc = beanContext;
1350 if (bc == null)
1351 return null;
1352 return (BuilderSwap<T,?>)BuilderSwap.findSwapFromObjectClass(bc, inner(), bc.getBeanConstructorVisibility(), bc.getBeanMethodVisibility());
1353 }
1354
1355 @SuppressWarnings("unchecked")
1356 private List<ObjectSwap<T,?>> findSwaps() {
1357 if (beanContext == null)
1358 return l();
1359
1360 var list = new ArrayList<ObjectSwap<T,?>>();
1361 var swapArray = beanContext.getSwaps();
1362 if (! swapArray.isEmpty()) {
1363 var innerClass = inner();
1364 for (var f : swapArray)
1365 if (f.getNormalClass().isParentOf(innerClass))
1366 list.add((ObjectSwap<T,?>)f);
1367 }
1368
1369 var ap = beanContext.getAnnotationProvider();
1370 ap.find(Swap.class, this).stream().map(AnnotationInfo::inner).forEach(x -> list.add(createSwap(x)));
1371 var ds = DefaultSwaps.find(this);
1372 if (ds == null)
1373 ds = AutoObjectSwap.find(beanContext, this);
1374 if (ds == null)
1375 ds = AutoNumberSwap.find(beanContext, this);
1376 if (ds == null)
1377 ds = AutoMapSwap.find(beanContext, this);
1378 if (ds == null)
1379 ds = AutoListSwap.find(beanContext, this);
1380
1381 if (nn(ds))
1382 list.add((ObjectSwap<T,?>)ds);
1383
1384 return u(list);
1385 }
1386
1387 private List<ObjectSwap<?,?>> findChildSwaps() {
1388 if (beanContext == null)
1389 return l();
1390 var swapArray = beanContext.getSwaps();
1391 if (swapArray.isEmpty())
1392 return l();
1393 var list = new ArrayList<ObjectSwap<?,?>>();
1394 var innerClass = inner();
1395 for (var f : swapArray)
1396 if (f.getNormalClass().isChildOf(innerClass))
1397 list.add(f);
1398 return u(list);
1399 }
1400
1401 private BidiMap<Object,String> findEnumValues() {
1402 if (! isEnum())
1403 return null;
1404
1405 var bc = beanContext;
1406 var useEnumNames = nn(bc) && bc.isUseEnumNames();
1407
1408 var m = BidiMap.<Object,String>create().unmodifiable();
1409 var c = inner().asSubclass(Enum.class);
1410 stream(c.getEnumConstants()).forEach(x -> m.add(x, useEnumNames ? x.name() : x.toString()));
1411 return m.build();
1412 }
1413
1414 @SuppressWarnings("unchecked")
1415 private String findExample() {
1416
1417 var example = beanMeta.get().optBeanMeta().map(x -> x.getBeanFilter()).map(x -> x.getExample()).orElse(null);
1418
1419 if (example == null)
1420 example = marshalledFilter.map(x -> x.getExample()).orElse(null);
1421
1422 if (example == null && nn(beanContext))
1423 example = beanContext.getAnnotationProvider().find(Example.class, this).stream().map(x -> x.inner().value()).filter(Utils::ne).findFirst().orElse(null);
1424
1425 if (example == null) {
1426 if (isAny(boolean.class, Boolean.class)) {
1427 example = "true";
1428 } else if (isAny(char.class, Character.class)) {
1429 example = "a";
1430 } else if (cat.is(CHARSEQ)) {
1431 example = "foo";
1432 } else if (cat.is(ENUM)) {
1433 Iterator<? extends Enum<?>> i = EnumSet.allOf(inner().asSubclass(Enum.class)).iterator();
1434 example = i.hasNext() ? (beanContext.isUseEnumNames() ? i.next().name() : i.next().toString()) : null;
1435 } else if (isAny(float.class, Float.class, double.class, Double.class)) {
1436 example = "1.0";
1437 } else if (isAny(short.class, Short.class, int.class, Integer.class, long.class, Long.class)) {
1438 example = "1";
1439 }
1440 }
1441
1442 return example;
1443 }
1444
1445 private FieldInfo findExampleField() {
1446 var ap = beanContext.getAnnotationProvider();
1447
1448 return getDeclaredFields()
1449 .stream()
1450 .filter(x -> x.isStatic() && isParentOf(x.getFieldType()) && ap.has(Example.class, x))
1451 .map(x -> x.accessible())
1452 .findFirst()
1453 .orElse(null);
1454 }
1455
1456 private MethodInfo findExampleMethod() {
1457
1458 var ap = beanContext.getAnnotationProvider();
1459
1460
1461 var m = getPublicMethod(
1462 x -> x.isStatic() && x.isNotDeprecated() && (x.hasName("example") || ap.has(Example.class, x)) && x.hasParameterTypesLenient(BeanSession.class)
1463 );
1464 if (m.isPresent()) return m.get();
1465
1466
1467 return getDeclaredMethods()
1468 .stream()
1469 .flatMap(x -> x.getMatchingMethods().stream())
1470 .filter(x -> x.isStatic() && ap.has(Example.class, x))
1471 .map(x -> x.accessible())
1472 .findFirst()
1473 .orElse(null);
1474
1475 }
1476
1477 private MethodInfo findFromStringMethod() {
1478
1479
1480
1481
1482
1483
1484
1485 var names = a("fromString", "fromValue", "valueOf", "parse", "parseString", "forName", "forString");
1486 return getPublicMethod(
1487 x -> x.isStatic() && x.isNotDeprecated() && x.hasReturnType(this) && x.hasParameterTypes(String.class) && contains(x.getName(), names)
1488 ).orElse(null);
1489
1490 }
1491
1492 @SuppressWarnings("unchecked")
1493 private ClassInfoTyped<? extends T> findImplClass() {
1494
1495 if (is(Object.class))
1496 return null;
1497
1498 var v = beanContext.getAnnotationProvider().find(Bean.class, this).stream().map(x -> x.inner()).filter(x -> neq(x.implClass(), void.class)).map(x -> ClassInfo.of(x)).findFirst().orElse(null);
1499
1500 if (v == null)
1501 v = marshalledFilter.map(x -> x.getImplClass()).map(ReflectionUtils::info).orElse(null);
1502
1503 return (ClassInfoTyped<? extends T>)v;
1504 }
1505
1506 private MarshalledFilter findMarshalledFilter() {
1507 var ap = beanContext.getAnnotationProvider();
1508 var l = ap.find(Marshalled.class, this);
1509 if (l.isEmpty())
1510 return null;
1511 return MarshalledFilter.create(inner()).applyAnnotations(reverse(l.stream().map(AnnotationInfo::inner).toList())).build();
1512 }
1513
1514 private Property<T,Object> findNameProperty() {
1515 var ap = beanContext.getAnnotationProvider();
1516
1517 var s = getAllFields()
1518 .stream()
1519 .filter(x -> ap.has(NameProperty.class, x))
1520 .map(x -> x.accessible())
1521 .map(x -> Property.<T,Object>create().field(x).build())
1522 .findFirst();
1523
1524 if (s.isPresent()) return s.get();
1525
1526 var builder = Property.<T,Object>create();
1527
1528
1529 var setterMethod = getAllMethods()
1530 .stream()
1531 .filter(x -> ap.has(NameProperty.class, x) && x.hasNumParameters(1))
1532 .findFirst();
1533
1534 if (setterMethod.isPresent()) {
1535 builder.setter(setterMethod.get().accessible());
1536
1537
1538
1539 var setterName = setterMethod.get().getSimpleName();
1540 if (setterName.startsWith("set") && setterName.length() > 3) {
1541 var propertyName = setterName.substring(3);
1542 var getterName1 = "get" + propertyName;
1543 var getterName2 = "is" + propertyName;
1544
1545 var getter = getAllMethods()
1546 .stream()
1547 .filter(x -> !x.isStatic() && x.hasNumParameters(0) &&
1548 (x.hasName(getterName1) || x.hasName(getterName2)) &&
1549 !x.getReturnType().is(Void.TYPE))
1550 .findFirst();
1551
1552 if (getter.isPresent()) {
1553 builder.getter(getter.get().accessible());
1554 } else {
1555
1556 var fieldName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
1557 var field = getAllFields()
1558 .stream()
1559 .filter(x -> !x.isStatic() && x.hasName(fieldName))
1560 .findFirst();
1561
1562 if (field.isPresent()) {
1563 var f = field.get().accessible();
1564 builder.getter(obj -> f.get(obj));
1565 }
1566 }
1567 }
1568 }
1569
1570
1571 var getterMethod = getAllMethods()
1572 .stream()
1573 .filter(x -> ap.has(NameProperty.class, x) && x.hasNumParameters(0) && !x.getReturnType().is(Void.TYPE))
1574 .findFirst();
1575
1576 if (getterMethod.isPresent()) {
1577 builder.getter(getterMethod.get().accessible());
1578 }
1579
1580
1581 if (setterMethod.isEmpty() && getterMethod.isEmpty())
1582 return null;
1583
1584 return builder.build();
1585 }
1586
1587 private ConstructorInfo findNoArgConstructor() {
1588
1589 if (is(Object.class))
1590 return null;
1591
1592 if (implClass.isPresent())
1593 return implClass.get().getPublicConstructor(x -> x.hasNumParameters(0)).orElse(null);
1594
1595 if (isAbstract())
1596 return null;
1597
1598 var numParams = isMemberClass() && isNotStatic() ? 1 : 0;
1599 return getPublicConstructors()
1600 .stream()
1601 .filter(x -> x.isPublic() && x.isNotDeprecated() && x.hasNumParameters(numParams))
1602 .findFirst()
1603 .orElse(null);
1604 }
1605
1606 private Property<T,Object> findParentProperty() {
1607 var ap = beanContext.getAnnotationProvider();
1608
1609 var s = getAllFields()
1610 .stream()
1611 .filter(x -> ap.has(ParentProperty.class, x))
1612 .map(x -> x.accessible())
1613 .map(x -> Property.<T,Object>create().field(x).build())
1614 .findFirst();
1615
1616 if (s.isPresent()) return s.get();
1617
1618 var builder = Property.<T,Object>create();
1619
1620
1621 var setterMethod = getAllMethods()
1622 .stream()
1623 .filter(x -> ap.has(ParentProperty.class, x) && x.hasNumParameters(1))
1624 .findFirst();
1625
1626 if (setterMethod.isPresent()) {
1627 builder.setter(setterMethod.get().accessible());
1628
1629
1630
1631 var setterName = setterMethod.get().getSimpleName();
1632 if (setterName.startsWith("set") && setterName.length() > 3) {
1633 var propertyName = setterName.substring(3);
1634 var getterName1 = "get" + propertyName;
1635 var getterName2 = "is" + propertyName;
1636
1637 var getter = getAllMethods()
1638 .stream()
1639 .filter(x -> !x.isStatic() && x.hasNumParameters(0) &&
1640 (x.hasName(getterName1) || x.hasName(getterName2)) &&
1641 !x.getReturnType().is(Void.TYPE))
1642 .findFirst();
1643
1644 if (getter.isPresent()) {
1645 builder.getter(getter.get().accessible());
1646 } else {
1647
1648 var fieldName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
1649 var field = getAllFields()
1650 .stream()
1651 .filter(x -> !x.isStatic() && x.hasName(fieldName))
1652 .findFirst();
1653
1654 if (field.isPresent()) {
1655 var f = field.get().accessible();
1656 builder.getter(obj -> f.get(obj));
1657 }
1658 }
1659 }
1660 }
1661
1662
1663 var getterMethod = getAllMethods()
1664 .stream()
1665 .filter(x -> ap.has(ParentProperty.class, x) && x.hasNumParameters(0) && !x.getReturnType().is(Void.TYPE))
1666 .findFirst();
1667
1668 if (getterMethod.isPresent()) {
1669 builder.getter(getterMethod.get().accessible());
1670 }
1671
1672
1673 if (setterMethod.isEmpty() && getterMethod.isEmpty())
1674 return null;
1675
1676 return builder.build();
1677 }
1678
1679 private ConstructorInfo findStringConstructor() {
1680
1681 if (is(Object.class) || isAbstract())
1682 return null;
1683
1684 if (implClass.isPresent())
1685 return implClass.get().getPublicConstructor(x -> x.hasParameterTypes(String.class)).orElse(null);
1686
1687 if (isAbstract())
1688 return null;
1689
1690 var numParams = isMemberClass() && isNotStatic() ? 2 : 1;
1691 return getPublicConstructors()
1692 .stream()
1693 .filter(x -> x.isPublic() && x.isNotDeprecated() && x.hasNumParameters(numParams))
1694 .filter(x -> x.getParameter(numParams == 2 ? 1 : 0).isType(String.class))
1695 .findFirst()
1696 .orElse(null);
1697 }
1698
1699
1700
1701
1702
1703
1704
1705
1706 protected ObjectSwap<?,?> getChildObjectSwapForSwap(Class<?> normalClass) {
1707 return childSwapMap.get(normalClass);
1708 }
1709
1710
1711
1712
1713
1714
1715
1716
1717 protected ObjectSwap<?,?> getChildObjectSwapForUnswap(Class<?> swapClass) {
1718 return childUnswapMap.get(swapClass);
1719 }
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730 protected boolean hasChildSwaps() {
1731 return ! childSwaps.get().isEmpty();
1732 }
1733
1734
1735
1736
1737
1738
1739
1740
1741 protected StringBuilder toString(StringBuilder sb, boolean simple) {
1742 var n = simple ? cnsq(inner()) : cn(inner());
1743 if (cat.is(ARRAY))
1744 return elementType.get().toString(sb, simple).append('[').append(']');
1745 if (cat.is(BEANMAP))
1746 return sb.append(cn(BeanMap.class)).append('<').append(n).append('>');
1747 if (cat.is(MAP)) {
1748 var kvTypes = keyValueTypes.get();
1749 var kt = kvTypes.optKeyType();
1750 var vt = kvTypes.optValueType();
1751 if (kt.isPresent() && vt.isPresent() && kt.get().isObject() && vt.get().isObject())
1752 return sb.append(n);
1753 return sb.append(n).append('<').append(kt.map(x -> x.toString(simple)).orElse("?")).append(',').append(vt.map(x -> x.toString(simple)).orElse("?")).append('>');
1754 }
1755 if (cat.is(COLLECTION) || is(Optional.class)) {
1756 var et = elementType.get();
1757 return sb.append(n).append(et != null && et.isObject() ? "" : "<" + (et == null ? "?" : et.toString(simple)) + ">");
1758 }
1759 return sb.append(n);
1760 }
1761 }