1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package gov.nist.secauto.metaschema.core.metapath;
28
29 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
30
31 import java.util.List;
32 import java.util.stream.Collectors;
33
34 import edu.umd.cs.findbugs.annotations.NonNull;
35 import edu.umd.cs.findbugs.annotations.Nullable;
36
37 final class ExpressionUtils {
38 private ExpressionUtils() {
39
40 }
41
42 @NonNull
43 public static <RESULT_TYPE> Class<? extends RESULT_TYPE> analyzeStaticResultType(
44 @NonNull Class<RESULT_TYPE> baseType,
45 @NonNull List<IExpression> expressions) {
46
47 Class<? extends RESULT_TYPE> retval;
48 if (expressions.isEmpty()) {
49
50 retval = baseType;
51 } else {
52 List<Class<?>> expressionClasses = ObjectUtils.notNull(expressions.stream()
53 .map(expr -> expr.getStaticResultType()).collect(Collectors.toList()));
54
55
56 if (checkDerivedFrom(baseType, expressionClasses)) {
57 retval = findCommonBase(baseType, expressionClasses);
58 } else {
59 retval = baseType;
60 }
61 }
62 return retval;
63 }
64
65 @NonNull
66 private static <RESULT_TYPE> Class<? extends RESULT_TYPE> findCommonBase(
67 @NonNull Class<RESULT_TYPE> baseType,
68 @NonNull List<Class<?>> expressionClasses) {
69 Class<? extends RESULT_TYPE> retval;
70 if (expressionClasses.size() == 1) {
71 @SuppressWarnings("unchecked") Class<? extends RESULT_TYPE> result
72 = (Class<? extends RESULT_TYPE>) expressionClasses.iterator().next();
73 assert result != null;
74 retval = result;
75 } else {
76 @SuppressWarnings("unchecked") Class<? extends RESULT_TYPE> first
77 = (Class<? extends RESULT_TYPE>) expressionClasses.iterator().next();
78 assert first != null;
79 if (baseType.equals(first)) {
80
81 retval = baseType;
82 } else {
83
84 Class<?> leastCommon = getCommonBaseClass(
85 baseType,
86 first,
87 ObjectUtils.notNull(expressionClasses.subList(1, expressionClasses.size())));
88 @SuppressWarnings("unchecked") Class<? extends RESULT_TYPE> newBase
89 = (Class<? extends RESULT_TYPE>) leastCommon;
90 if (newBase != null) {
91 retval = newBase;
92 } else {
93 retval = baseType;
94 }
95 }
96 }
97 return retval;
98 }
99
100 @Nullable
101 private static Class<?> getCommonBaseClass(@NonNull Class<?> baseType,
102 @NonNull Class<?> first, @NonNull List<Class<?>> expressionClasses) {
103 boolean match = true;
104 for (Class<?> clazz : expressionClasses) {
105 if (!first.isAssignableFrom(clazz)) {
106 match = false;
107 break;
108 }
109 }
110
111 Class<?> retval = null;
112 if (match) {
113 retval = first;
114 } else {
115 for (Class<?> clazz : first.getInterfaces()) {
116 assert clazz != null;
117
118 if (baseType.isAssignableFrom(clazz)) {
119 Class<?> newBase = getCommonBaseClass(baseType, clazz, expressionClasses);
120 if (newBase != null) {
121 retval = newBase;
122 break;
123 }
124 }
125 }
126 }
127 return retval;
128 }
129
130 private static boolean checkDerivedFrom(@NonNull Class<?> baseType,
131 @NonNull List<Class<?>> expressionClasses) {
132 boolean retval = true;
133 for (Class<?> clazz : expressionClasses) {
134 if (!baseType.isAssignableFrom(clazz)) {
135 retval = false;
136 break;
137 }
138 }
139 return retval;
140 }
141
142 }