• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

trydofor / professional-wings / #125

31 Aug 2024 04:46AM UTC coverage: 63.579% (+0.7%) from 62.919%
#125

push

web-flow
Merge pull request #290 from trydofor/develop

3.2.130

1428 of 2191 new or added lines in 106 files covered. (65.18%)

41 existing lines in 24 files now uncovered.

12923 of 20326 relevant lines covered (63.58%)

0.64 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.95
/wings/silencer/src/main/java/pro/fessional/wings/silencer/support/TypeSugar.java
1
package pro.fessional.wings.silencer.support;
2

3
import jakarta.annotation.Nullable;
4
import lombok.SneakyThrows;
5
import org.jetbrains.annotations.NotNull;
6
import org.springframework.core.ResolvableType;
7
import org.springframework.core.convert.TypeDescriptor;
8
import org.springframework.util.ClassUtils;
9
import pro.fessional.mirana.data.Null;
10
import pro.fessional.mirana.lock.ArrayKey;
11

12
import java.lang.reflect.Type;
13
import java.math.BigDecimal;
14
import java.math.BigInteger;
15
import java.time.Instant;
16
import java.time.LocalDate;
17
import java.time.LocalDateTime;
18
import java.time.LocalTime;
19
import java.time.OffsetDateTime;
20
import java.time.ZoneId;
21
import java.time.ZonedDateTime;
22
import java.util.ArrayList;
23
import java.util.Collection;
24
import java.util.Date;
25
import java.util.HashMap;
26
import java.util.HashSet;
27
import java.util.LinkedHashMap;
28
import java.util.LinkedList;
29
import java.util.List;
30
import java.util.Locale;
31
import java.util.Map;
32
import java.util.Optional;
33
import java.util.Set;
34
import java.util.TimeZone;
35
import java.util.TreeMap;
36
import java.util.TreeSet;
37
import java.util.concurrent.ConcurrentHashMap;
38
import java.util.regex.Pattern;
39

40
/**
41
 * ResolvableType for Class with Generics with cache,
42
 * 20 times faster than new ResolvableType, TypeDescriptor
43
 *
44
 * @author trydofor
45
 * @since 2024-06-09
46
 */
NEW
47
public class TypeSugar {
×
48

49
    public static final TypeDescriptor StringDescriptor = TypeDescriptor.valueOf(String.class);
1✔
50
    public static final TypeDescriptor BooleanDescriptor = TypeDescriptor.valueOf(Boolean.class);
1✔
51
    public static final TypeDescriptor IntegerDescriptor = TypeDescriptor.valueOf(Integer.class);
1✔
52
    public static final TypeDescriptor LongDescriptor = TypeDescriptor.valueOf(Long.class);
1✔
53
    public static final TypeDescriptor DoubleDescriptor = TypeDescriptor.valueOf(Double.class);
1✔
54
    public static final TypeDescriptor FloatDescriptor = TypeDescriptor.valueOf(Float.class);
1✔
55
    public static final TypeDescriptor BigDecimalDescriptor = TypeDescriptor.valueOf(BigDecimal.class);
1✔
56

57
    public static final TypeDescriptor LocalDateDescriptor = TypeDescriptor.valueOf(LocalDate.class);
1✔
58
    public static final TypeDescriptor LocalTimeDescriptor = TypeDescriptor.valueOf(LocalTime.class);
1✔
59
    public static final TypeDescriptor LocalDateTimeDescriptor = TypeDescriptor.valueOf(LocalDateTime.class);
1✔
60
    public static final TypeDescriptor ZonedDateTimeDescriptor = TypeDescriptor.valueOf(ZonedDateTime.class);
1✔
61
    public static final TypeDescriptor OffsetDateTimeDescriptor = TypeDescriptor.valueOf(OffsetDateTime.class);
1✔
62
    public static final TypeDescriptor ZoneIdDescriptor = TypeDescriptor.valueOf(ZoneId.class);
1✔
63

64

65
    //
66
    private static final ConcurrentHashMap<Object, ResolvableType> CacheResolvable = new ConcurrentHashMap<>();
1✔
67
    private static final ConcurrentHashMap<Object, TypeDescriptor> CacheDescriptor = new ConcurrentHashMap<>();
1✔
68

69
    /**
70
     * by cache
71
     */
72
    @NotNull
73
    public static TypeDescriptor describe(@NotNull Class<?> clazz, Class<?>... generics) {
74
        Object key = generics == null || generics.length == 0
1✔
75
            ? clazz
1✔
76
            : new ArrayKey(clazz, generics);
1✔
77
        return CacheDescriptor.computeIfAbsent(key, ignore -> describeNew(clazz, generics));
1✔
78
    }
79

80
    /**
81
     * by cache
82
     */
83
    @NotNull
84
    public static ResolvableType resolve(@NotNull Class<?> clazz, Class<?>... generics) {
85
        Object key = generics == null || generics.length == 0
1✔
86
            ? clazz
1✔
87
            : new ArrayKey(clazz, generics);
1✔
88
        return CacheResolvable.computeIfAbsent(key, ignore -> resolveNew(clazz, generics));
1✔
89
    }
90

91
    /**
92
     * by cache
93
     */
94
    @NotNull
95
    public static Type type(@NotNull Class<?> clazz, Class<?>... generics) {
96
        return resolve(clazz, generics).getType();
1✔
97
    }
98

99
    /**
100
     * no cache
101
     */
102
    @NotNull
103
    public static TypeDescriptor describeNew(@NotNull Class<?> clazz, Class<?>... generics) {
104
        return new TypeDescriptor(resolveNew(clazz, generics), null, null);
1✔
105
    }
106

107
    /**
108
     * no cache
109
     */
110
    @NotNull
111
    public static ResolvableType resolveNew(@NotNull Class<?> clazz, Class<?>... generics) {
112
        final int rootCnt = clazz.getTypeParameters().length;
1✔
113
        if (rootCnt == 0) return ResolvableType.forClass(clazz);
1✔
114

115
        final int paraCnt = generics == null ? 0 : generics.length;
1✔
116
        final ResolvableType[] rootArg = new ResolvableType[rootCnt];
1✔
117
        if (paraCnt <= rootCnt) {
1✔
118
            for (int i = 0; i < paraCnt; i++) {
1✔
119
                rootArg[i] = ResolvableType.forClass(generics[i]);
1✔
120
            }
121
            for (int i = paraCnt; i < rootCnt; i++) {
1✔
122
                rootArg[i] = ResolvableType.forClass(Object.class);
1✔
123
            }
124
        }
125
        else {
126
            int nextIdx = 0;
1✔
127
            for (int ri = 0; ri < rootCnt; ri++) {
1✔
128
                Class<?> rt = generics[nextIdx++];
1✔
129
                int rc = rt.getTypeParameters().length;
1✔
130
                nextIdx = resolve(rt, rootArg, ri, rc, generics, nextIdx);
1✔
131
            }
132
        }
133

134
        return ResolvableType.forClassWithGenerics(clazz, rootArg);
1✔
135
    }
136

137
    private static final ConcurrentHashMap<String, String> ShortLong = new ConcurrentHashMap<>();
1✔
138
    private static final Pattern TypeSplit = Pattern.compile("[,<> ]+");
1✔
139

140
    public static boolean shorten(@NotNull Class<?> claz) {
141
        String v1 = ShortLong.putIfAbsent(claz.getSimpleName(), claz.getName());
1✔
142
        return v1 == null;
1✔
143
    }
144

145
    static {
146
        shorten(void.class);
1✔
147
        shorten(boolean.class);
1✔
148
        shorten(byte.class);
1✔
149
        shorten(char.class);
1✔
150
        shorten(short.class);
1✔
151
        shorten(int.class);
1✔
152
        shorten(long.class);
1✔
153
        shorten(float.class);
1✔
154
        shorten(double.class);
1✔
155

156
        shorten(Void.class);
1✔
157
        shorten(String.class);
1✔
158
        shorten(Object.class);
1✔
159

160
        shorten(Boolean.class);
1✔
161
        shorten(Byte.class);
1✔
162
        shorten(Character.class);
1✔
163
        shorten(Short.class);
1✔
164
        shorten(Integer.class);
1✔
165
        shorten(Long.class);
1✔
166
        shorten(Float.class);
1✔
167
        shorten(Double.class);
1✔
168
        shorten(BigDecimal.class);
1✔
169
        shorten(BigInteger.class);
1✔
170

171
        shorten(Date.class);
1✔
172
        shorten(ZoneId.class);
1✔
173
        shorten(TimeZone.class);
1✔
174
        shorten(Locale.class);
1✔
175
        shorten(LocalDate.class);
1✔
176
        shorten(LocalTime.class);
1✔
177
        shorten(LocalDateTime.class);
1✔
178
        shorten(ZonedDateTime.class);
1✔
179
        shorten(OffsetDateTime.class);
1✔
180
        shorten(Instant.class);
1✔
181

182
        shorten(Collection.class);
1✔
183
        shorten(Optional.class);
1✔
184
        shorten(List.class);
1✔
185
        shorten(ArrayList.class);
1✔
186
        shorten(LinkedList.class);
1✔
187
        shorten(Map.class);
1✔
188
        shorten(HashMap.class);
1✔
189
        shorten(TreeMap.class);
1✔
190
        shorten(LinkedHashMap.class);
1✔
191
        shorten(Set.class);
1✔
192
        shorten(HashSet.class);
1✔
193
        shorten(TreeSet.class);
1✔
194

195
        shorten(ConcurrentHashMap.class);
1✔
196
    }
1✔
197

198
    @NotNull
199
    public static String outline(@NotNull ResolvableType type) {
200
        return outline(type, true);
1✔
201
    }
202

203
    @NotNull
204
    public static String outline(@NotNull ResolvableType type, boolean shorten) {
205
        String st = type.toString();
1✔
206
        st = st.replace("?", "Object");
1✔
207

208
        if (shorten) {
1✔
209
            for (Map.Entry<String, String> en : ShortLong.entrySet()) {
1✔
210
                st = st.replace(en.getValue(), en.getKey());
1✔
211
            }
1✔
212
        }
213

214
        return st;
1✔
215
    }
216

217
    @Nullable
218
    public static ResolvableType resolve(String structs) {
219
        if (structs == null) return null;
1✔
220
        return CacheResolvable.computeIfAbsent(structs, ignore -> resolveNew(structs));
1✔
221
    }
222

NEW
223
    @SneakyThrows
×
224
    @Nullable
225
    public static ResolvableType resolveNew(String structs) {
226
        if (structs == null || structs.isEmpty()) return null;
1✔
227

228
        // java.util.Map<java.util.List<java.util.List<java.lang.Long[]>>, java.lang.String>
229
        String[] pts = TypeSplit.split(structs.trim());
1✔
230
        if (pts.length == 0) return null;
1✔
231

232
        List<Class<?>> clz = new ArrayList<>(pts.length);
1✔
233
        for (String str : pts) {
1✔
234
            if (str.isEmpty()) continue; // should not happen
1✔
235

236
            // java.util.List<?>
237
            if (str.equals("?")) {
1✔
NEW
238
                clz.add(Object.class);
×
NEW
239
                continue;
×
240
            }
241

242
            final String name;
243
            if (str.endsWith("[]")) {
1✔
244
                String sub = str.substring(0, str.length() - 2);
1✔
245
                name = ShortLong.getOrDefault(sub, sub) + "[]";
1✔
246
            }
1✔
247
            else {
248
                name = ShortLong.getOrDefault(str, str);
1✔
249
            }
250
            clz.add(ClassUtils.forName(name, null));
1✔
251
        }
252

253
        final int size = clz.size();
1✔
254
        if (size == 0) return null;
1✔
255
        if (size == 1) return resolve(clz.get(0));
1✔
256
        Class<?>[] ots = clz.subList(1, size).toArray(Null.ClzArr);
1✔
257
        return resolve(clz.get(0), ots);
1✔
258
    }
259

260
    private static int resolve(Class<?> rootClz, ResolvableType[] rootArg, int rootIdx, int paraCnt, Class<?>[] nextClz, int nextIdx) {
261
        if (paraCnt <= 0) {
1✔
262
            rootArg[rootIdx] = ResolvableType.forClass(rootClz);
1✔
263
        }
264
        else {
265
            final ResolvableType[] args = new ResolvableType[paraCnt];
1✔
266
            for (int i = 0; i < paraCnt; i++) {
1✔
267
                Class<?> root = nextClz[nextIdx++];
1✔
268
                int c1 = root.getTypeParameters().length;
1✔
269
                nextIdx = resolve(root, args, i, c1, nextClz, nextIdx);
1✔
270
            }
271
            rootArg[rootIdx] = ResolvableType.forClassWithGenerics(rootClz, args);
1✔
272
        }
273
        return nextIdx;
1✔
274
    }
275
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc