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

gephi / graphstore / #552

23 Apr 2026 07:35PM UTC coverage: 91.039%. Remained the same
#552

push

mbastian
Formatting

7 of 7 new or added lines in 2 files covered. (100.0%)

44 existing lines in 2 files now uncovered.

11745 of 12901 relevant lines covered (91.04%)

0.91 hits per line

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

91.92
/src/main/java/org/gephi/graph/api/AttributeUtils.java
1
/*
2
 * Copyright 2012-2013 Gephi Consortium
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5
 * use this file except in compliance with the License. You may obtain a copy of
6
 * the License at
7
 *
8
 * http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
 * License for the specific language governing permissions and limitations under
14
 * the License.
15
 */
16

17
package org.gephi.graph.api;
18

19
import it.unimi.dsi.fastutil.booleans.BooleanArrayList;
20
import it.unimi.dsi.fastutil.booleans.BooleanOpenHashSet;
21
import it.unimi.dsi.fastutil.bytes.Byte2ObjectOpenHashMap;
22
import it.unimi.dsi.fastutil.bytes.ByteArrayList;
23
import it.unimi.dsi.fastutil.bytes.ByteOpenHashSet;
24
import it.unimi.dsi.fastutil.chars.Char2ObjectOpenHashMap;
25
import it.unimi.dsi.fastutil.chars.CharArrayList;
26
import it.unimi.dsi.fastutil.chars.CharOpenHashSet;
27
import it.unimi.dsi.fastutil.doubles.Double2ObjectOpenHashMap;
28
import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
29
import it.unimi.dsi.fastutil.doubles.DoubleOpenHashSet;
30
import it.unimi.dsi.fastutil.floats.Float2ObjectOpenHashMap;
31
import it.unimi.dsi.fastutil.floats.FloatArrayList;
32
import it.unimi.dsi.fastutil.floats.FloatOpenHashSet;
33
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
34
import it.unimi.dsi.fastutil.ints.IntArrayList;
35
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
36
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
37
import it.unimi.dsi.fastutil.longs.LongArrayList;
38
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
39
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
40
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
41
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
42
import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
43
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
44
import it.unimi.dsi.fastutil.shorts.ShortOpenHashSet;
45
import java.lang.reflect.Array;
46
import java.math.BigDecimal;
47
import java.math.BigInteger;
48
import java.text.DecimalFormat;
49
import java.text.DecimalFormatSymbols;
50
import java.time.Instant;
51
import java.time.OffsetDateTime;
52
import java.time.ZoneId;
53
import java.time.ZonedDateTime;
54
import java.time.format.DateTimeFormatter;
55
import java.time.format.DateTimeFormatterBuilder;
56
import java.time.format.DateTimeParseException;
57
import java.time.temporal.ChronoField;
58
import java.util.Collections;
59
import java.util.HashMap;
60
import java.util.HashSet;
61
import java.util.concurrent.ConcurrentHashMap;
62
import java.util.List;
63
import java.util.Locale;
64
import java.util.Map;
65
import java.util.Set;
66
import org.gephi.graph.api.types.IntervalBooleanMap;
67
import org.gephi.graph.api.types.IntervalByteMap;
68
import org.gephi.graph.api.types.IntervalCharMap;
69
import org.gephi.graph.api.types.IntervalDoubleMap;
70
import org.gephi.graph.api.types.IntervalFloatMap;
71
import org.gephi.graph.api.types.IntervalIntegerMap;
72
import org.gephi.graph.api.types.IntervalLongMap;
73
import org.gephi.graph.api.types.IntervalMap;
74
import org.gephi.graph.api.types.IntervalSet;
75
import org.gephi.graph.api.types.IntervalShortMap;
76
import org.gephi.graph.api.types.IntervalStringMap;
77
import org.gephi.graph.api.types.TimeMap;
78
import org.gephi.graph.api.types.TimeSet;
79
import org.gephi.graph.api.types.TimestampBooleanMap;
80
import org.gephi.graph.api.types.TimestampByteMap;
81
import org.gephi.graph.api.types.TimestampCharMap;
82
import org.gephi.graph.api.types.TimestampDoubleMap;
83
import org.gephi.graph.api.types.TimestampFloatMap;
84
import org.gephi.graph.api.types.TimestampIntegerMap;
85
import org.gephi.graph.api.types.TimestampLongMap;
86
import org.gephi.graph.api.types.TimestampMap;
87
import org.gephi.graph.api.types.TimestampSet;
88
import org.gephi.graph.api.types.TimestampShortMap;
89
import org.gephi.graph.api.types.TimestampStringMap;
90
import org.gephi.graph.impl.ArraysParser;
91
import org.gephi.graph.impl.FormattingAndParsingUtils;
92
import org.gephi.graph.impl.GraphStoreConfiguration;
93
import org.gephi.graph.impl.IntervalsParser;
94
import org.gephi.graph.impl.TimestampsParser;
95

96
/**
97
 * Set of utility methods to manipulate supported attribute types.
98
 * <p>
99
 * The attribute system is built with a set of supported column types. This
100
 * class contains utilities to parse and convert supported types. It also
101
 * contains utilities to manipulate primitive arrays (the preferred array type)
102
 * and date/time types. Default time zone for parsing/printing dates is UTC.
103
 */
104
public class AttributeUtils {
105

106
    private static final Set<Class> SUPPORTED_TYPES;
107
    private static final Map<Class, Class> TYPES_STANDARDIZATION;
108
    private static final DateTimeFormatter DATE_TIME_PARSER;
109
    private static final DateTimeFormatter DATE_PRINTER;
110
    private static final DateTimeFormatter DATE_TIME_PRINTER;
111
    private static final DecimalFormat TIMESTAMP_PRINTER;
112

113
    // These are used to avoid creating a lot of new instances of
114
    // DateTimeFormatter
115
    private static final Map<ZoneId, DateTimeFormatter> DATE_PRINTERS_BY_TIMEZONE;
116
    private static final Map<ZoneId, DateTimeFormatter> DATE_TIME_PRINTERS_BY_TIMEZONE;
117
    private static final Map<ZoneId, DateTimeFormatter> DATE_TIME_PARSERS_BY_TIMEZONE;
118

119
    // Collection types to speedup lookup
120
    private static final Set<Class> TYPED_LIST_TYPES;
121
    private static final Set<Class> TYPED_SET_TYPES;
122
    private static final Set<Class> TYPED_MAP_TYPES;
123

124
    static {
125
        final Set<Class> supportedTypes = new HashSet<>();
1✔
126

127
        // Primitives
128
        supportedTypes.add(Boolean.class);
1✔
129
        supportedTypes.add(boolean.class);
1✔
130
        supportedTypes.add(Integer.class);
1✔
131
        supportedTypes.add(int.class);
1✔
132
        supportedTypes.add(Short.class);
1✔
133
        supportedTypes.add(short.class);
1✔
134
        supportedTypes.add(Long.class);
1✔
135
        supportedTypes.add(long.class);
1✔
136
        supportedTypes.add(BigInteger.class);
1✔
137
        supportedTypes.add(Byte.class);
1✔
138
        supportedTypes.add(byte.class);
1✔
139
        supportedTypes.add(Float.class);
1✔
140
        supportedTypes.add(float.class);
1✔
141
        supportedTypes.add(Double.class);
1✔
142
        supportedTypes.add(double.class);
1✔
143
        supportedTypes.add(BigDecimal.class);
1✔
144
        supportedTypes.add(Character.class);
1✔
145
        supportedTypes.add(char.class);
1✔
146

147
        // Objects
148
        supportedTypes.add(String.class);
1✔
149

150
        // Instant
151
        supportedTypes.add(Instant.class);
1✔
152

153
        // Primitives Array
154
        supportedTypes.add(Boolean[].class);
1✔
155
        supportedTypes.add(boolean[].class);
1✔
156
        supportedTypes.add(Integer[].class);
1✔
157
        supportedTypes.add(int[].class);
1✔
158
        supportedTypes.add(Short[].class);
1✔
159
        supportedTypes.add(short[].class);
1✔
160
        supportedTypes.add(Long[].class);
1✔
161
        supportedTypes.add(long[].class);
1✔
162
        supportedTypes.add(BigInteger[].class);
1✔
163
        supportedTypes.add(Byte[].class);
1✔
164
        supportedTypes.add(byte[].class);
1✔
165
        supportedTypes.add(Float[].class);
1✔
166
        supportedTypes.add(float[].class);
1✔
167
        supportedTypes.add(Double[].class);
1✔
168
        supportedTypes.add(double[].class);
1✔
169
        supportedTypes.add(BigDecimal[].class);
1✔
170
        supportedTypes.add(Character[].class);
1✔
171
        supportedTypes.add(char[].class);
1✔
172

173
        // Objects array
174
        supportedTypes.add(String[].class);
1✔
175

176
        // Dynamic (timestamps)
177
        supportedTypes.add(TimestampSet.class);
1✔
178
        supportedTypes.add(TimestampBooleanMap.class);
1✔
179
        supportedTypes.add(TimestampIntegerMap.class);
1✔
180
        supportedTypes.add(TimestampShortMap.class);
1✔
181
        supportedTypes.add(TimestampLongMap.class);
1✔
182
        supportedTypes.add(TimestampByteMap.class);
1✔
183
        supportedTypes.add(TimestampFloatMap.class);
1✔
184
        supportedTypes.add(TimestampDoubleMap.class);
1✔
185
        supportedTypes.add(TimestampCharMap.class);
1✔
186
        supportedTypes.add(TimestampStringMap.class);
1✔
187

188
        // Dynamic (intervals)
189
        supportedTypes.add(IntervalSet.class);
1✔
190
        supportedTypes.add(IntervalBooleanMap.class);
1✔
191
        supportedTypes.add(IntervalIntegerMap.class);
1✔
192
        supportedTypes.add(IntervalShortMap.class);
1✔
193
        supportedTypes.add(IntervalLongMap.class);
1✔
194
        supportedTypes.add(IntervalByteMap.class);
1✔
195
        supportedTypes.add(IntervalFloatMap.class);
1✔
196
        supportedTypes.add(IntervalDoubleMap.class);
1✔
197
        supportedTypes.add(IntervalCharMap.class);
1✔
198
        supportedTypes.add(IntervalStringMap.class);
1✔
199

200
        // Lists, Maps, Sets
201
        supportedTypes.add(List.class);
1✔
202
        supportedTypes.add(Set.class);
1✔
203
        supportedTypes.add(Map.class);
1✔
204

205
        // Assign
206
        SUPPORTED_TYPES = Collections.unmodifiableSet(supportedTypes);
1✔
207

208
        // Primitive types standardization
209
        final Map<Class, Class> typesStandardization = new HashMap<>();
1✔
210
        typesStandardization.put(boolean.class, Boolean.class);
1✔
211
        typesStandardization.put(int.class, Integer.class);
1✔
212
        typesStandardization.put(short.class, Short.class);
1✔
213
        typesStandardization.put(long.class, Long.class);
1✔
214
        typesStandardization.put(byte.class, Byte.class);
1✔
215
        typesStandardization.put(float.class, Float.class);
1✔
216
        typesStandardization.put(double.class, Double.class);
1✔
217
        typesStandardization.put(char.class, Character.class);
1✔
218

219
        // Array standardization
220
        typesStandardization.put(Boolean[].class, boolean[].class);
1✔
221
        typesStandardization.put(Integer[].class, int[].class);
1✔
222
        typesStandardization.put(Short[].class, short[].class);
1✔
223
        typesStandardization.put(Long[].class, long[].class);
1✔
224
        typesStandardization.put(Byte[].class, byte[].class);
1✔
225
        typesStandardization.put(Float[].class, float[].class);
1✔
226
        typesStandardization.put(Double[].class, double[].class);
1✔
227
        typesStandardization.put(Character[].class, char[].class);
1✔
228

229
        // Assign
230
        TYPES_STANDARDIZATION = Collections.unmodifiableMap(typesStandardization);
1✔
231

232
        // Datetime - make sure UTC timezone is used by default
233
        DATE_TIME_PARSER = new DateTimeFormatterBuilder().parseCaseInsensitive()
1✔
234
                .appendOptional(DateTimeFormatter.ISO_DATE).appendOptional(DateTimeFormatter.ofPattern("yyyyMMdd"))
1✔
235
                .optionalStart().appendLiteral('T').append(DateTimeFormatter.ISO_TIME)
1✔
236
                .appendPattern("[.SSSSSSSSS][.SSSSSS][.SSS]").optionalEnd().optionalStart()
1✔
237
                .appendFraction(ChronoField.NANO_OF_SECOND, 9, 9, true).optionalEnd()
1✔
238
                // optional nanos with 6 digits (including decimal point)
239
                .optionalStart().appendFraction(ChronoField.NANO_OF_SECOND, 6, 6, true).optionalEnd()
1✔
240
                // optional nanos with 3 digits (including decimal point)
241
                .optionalStart().appendFraction(ChronoField.NANO_OF_SECOND, 3, 3, true).optionalEnd()
1✔
242
                .parseDefaulting(ChronoField.HOUR_OF_DAY, 0).parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
1✔
243
                .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0).parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
1✔
244
                .toFormatter().withZone(GraphStoreConfiguration.DEFAULT_TIME_ZONE);
1✔
245
        DATE_PRINTER = new DateTimeFormatterBuilder().parseCaseInsensitive().appendPattern("yyyy-MM-dd").toFormatter()
1✔
246
                .withZone(GraphStoreConfiguration.DEFAULT_TIME_ZONE);
1✔
247
        DATE_TIME_PRINTER = new DateTimeFormatterBuilder().parseCaseInsensitive()
1✔
248
                .append(DateTimeFormatter.ISO_LOCAL_DATE).appendLiteral('T').appendPattern("HH:mm:ss")
1✔
249
                .appendPattern(".SSS").parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
1✔
250
                .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0).parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
1✔
251
                .parseDefaulting(ChronoField.NANO_OF_SECOND, 0).appendOffset("+HH:MM", "Z").toFormatter()
1✔
252
                .withZone(GraphStoreConfiguration.DEFAULT_TIME_ZONE);
1✔
253

254
        DATE_PRINTERS_BY_TIMEZONE = new ConcurrentHashMap<>();
1✔
255
        DATE_TIME_PRINTERS_BY_TIMEZONE = new ConcurrentHashMap<>();
1✔
256
        DATE_TIME_PARSERS_BY_TIMEZONE = new ConcurrentHashMap<>();
1✔
257

258
        DATE_PRINTERS_BY_TIMEZONE.put(DATE_PRINTER.getZone(), DATE_PRINTER);
1✔
259
        DATE_TIME_PRINTERS_BY_TIMEZONE.put(DATE_TIME_PRINTER.getZone(), DATE_TIME_PRINTER);
1✔
260
        DATE_TIME_PARSERS_BY_TIMEZONE.put(DATE_TIME_PARSER.getZone(), DATE_TIME_PARSER);
1✔
261

262
        DecimalFormatSymbols decimalFormatSymbols = DecimalFormatSymbols.getInstance(Locale.ENGLISH);
1✔
263
        decimalFormatSymbols.setInfinity(FormattingAndParsingUtils.INFINITY);
1✔
264
        // 1 to 4 decimals
265
        TIMESTAMP_PRINTER = new DecimalFormat("0.0###", decimalFormatSymbols);
1✔
266

267
        // List types
268
        TYPED_LIST_TYPES = new HashSet<>();
1✔
269
        TYPED_LIST_TYPES.add(IntArrayList.class);
1✔
270
        TYPED_LIST_TYPES.add(FloatArrayList.class);
1✔
271
        TYPED_LIST_TYPES.add(DoubleArrayList.class);
1✔
272
        TYPED_LIST_TYPES.add(ShortArrayList.class);
1✔
273
        TYPED_LIST_TYPES.add(LongArrayList.class);
1✔
274
        TYPED_LIST_TYPES.add(ByteArrayList.class);
1✔
275
        TYPED_LIST_TYPES.add(BooleanArrayList.class);
1✔
276
        TYPED_LIST_TYPES.add(CharArrayList.class);
1✔
277

278
        // Set types
279
        TYPED_SET_TYPES = new HashSet<>();
1✔
280
        TYPED_SET_TYPES.add(IntOpenHashSet.class);
1✔
281
        TYPED_SET_TYPES.add(FloatOpenHashSet.class);
1✔
282
        TYPED_SET_TYPES.add(DoubleOpenHashSet.class);
1✔
283
        TYPED_SET_TYPES.add(ShortOpenHashSet.class);
1✔
284
        TYPED_SET_TYPES.add(LongOpenHashSet.class);
1✔
285
        TYPED_SET_TYPES.add(ByteOpenHashSet.class);
1✔
286
        TYPED_SET_TYPES.add(BooleanOpenHashSet.class);
1✔
287
        TYPED_SET_TYPES.add(CharOpenHashSet.class);
1✔
288

289
        // Map types
290
        TYPED_MAP_TYPES = new HashSet<>();
1✔
291
        TYPED_MAP_TYPES.add(Int2ObjectOpenHashMap.class);
1✔
292
        TYPED_MAP_TYPES.add(Float2ObjectOpenHashMap.class);
1✔
293
        TYPED_MAP_TYPES.add(Double2ObjectOpenHashMap.class);
1✔
294
        TYPED_MAP_TYPES.add(Short2ObjectOpenHashMap.class);
1✔
295
        TYPED_MAP_TYPES.add(Long2ObjectOpenHashMap.class);
1✔
296
        TYPED_MAP_TYPES.add(Byte2ObjectOpenHashMap.class);
1✔
297
        TYPED_MAP_TYPES.add(Char2ObjectOpenHashMap.class);
1✔
298
    }
1✔
299

300
    private AttributeUtils() {
301
        // Only static methods
302
    }
303

304
    private static DateTimeFormatter getDateTimeFormatterByTimeZone(Map<ZoneId, DateTimeFormatter> cache, DateTimeFormatter baseFormatter, ZoneId zoneId) {
305
        if (zoneId == null) {
1✔
306
            return baseFormatter;
1✔
307
        }
308

309
        return cache.computeIfAbsent(zoneId, z -> baseFormatter.withZone(z));
1✔
310
    }
311

312
    private static DateTimeFormatter getDateTimeParserByTimeZone(ZoneId zoneId) {
313
        return getDateTimeFormatterByTimeZone(DATE_TIME_PARSERS_BY_TIMEZONE, DATE_TIME_PARSER, zoneId);
1✔
314
    }
315

316
    private static DateTimeFormatter getDateTimePrinterByTimeZone(ZoneId zoneId) {
317
        return getDateTimeFormatterByTimeZone(DATE_TIME_PRINTERS_BY_TIMEZONE, DATE_TIME_PRINTER, zoneId);
1✔
318
    }
319

320
    private static DateTimeFormatter getDatePrinterByTimeZone(ZoneId zoneId) {
321
        return getDateTimeFormatterByTimeZone(DATE_PRINTERS_BY_TIMEZONE, DATE_PRINTER, zoneId);
1✔
322
    }
323

324
    /**
325
     * Returns the string representation of the given value.
326
     *
327
     * @param value value
328
     * @return string representation
329
     */
330
    public static String print(Object value) {
331
        return print(value, TimeFormat.DOUBLE, null);
1✔
332
    }
333

334
    /**
335
     * Returns the string representation of the given value.
336
     *
337
     * @param value value
338
     * @param timeFormat time format
339
     * @param zoneId time zone
340
     * @return string representation
341
     */
342
    public static String print(Object value, TimeFormat timeFormat, ZoneId zoneId) {
343
        if (value == null) {
1✔
344
            return "null";
1✔
345
        }
346
        if (value instanceof TimeSet) {
1✔
347
            return ((TimeSet) value).toString(timeFormat, zoneId);
1✔
348
        }
349
        if (value instanceof TimeMap) {
1✔
350
            return ((TimeMap) value).toString(timeFormat, zoneId);
1✔
351
        }
352
        if (value instanceof Instant) {
1✔
353
            return value.toString();
1✔
354
        }
355
        if (value.getClass().isArray()) {
1✔
356
            return printArray(value);
1✔
357
        }
358
        return value.toString();
1✔
359
    }
360

361
    /**
362
     * Parses the given string using the type class provided and returns an
363
     * instance.
364
     *
365
     * @param str string to parse
366
     * @param typeClass class of the desired type
367
     * @param zoneId time zone to use or null to use default time zone (UTC), for
368
     *        dynamic types and <code>Instant</code> only
369
     * @return an instance of the type class, or null if <em>str</em> is null or
370
     *         empty
371
     */
372
    public static Object parse(String str, Class typeClass, ZoneId zoneId) {
373
        if (str == null || str.isEmpty()) {
1✔
374
            return null;
1✔
375
        }
376

377
        if (str.equalsIgnoreCase("null")) {
1✔
378
            return null;
1✔
379
        }
380

381
        if (typeClass.isPrimitive()) {
1✔
382
            typeClass = getStandardizedType(typeClass);// For primitives we can
1✔
383
                                                       // use auto-unboxing
384
        }
385

386
        // Simple and primitive types:
387
        if (typeClass.equals(String.class)) {
1✔
388
            return str;
1✔
389
        } else if (typeClass.equals(Byte.class)) {
1✔
390
            return Byte.valueOf(str);
1✔
391
        } else if (typeClass.equals(Short.class)) {
1✔
392
            return Short.valueOf(str);
1✔
393
        } else if (typeClass.equals(Integer.class)) {
1✔
394
            return Integer.valueOf(str);
1✔
395
        } else if (typeClass.equals(Long.class)) {
1✔
396
            return Long.valueOf(str);
1✔
397
        } else if (typeClass.equals(Float.class)) {
1✔
398
            return Float.valueOf(str);
1✔
399
        } else if (typeClass.equals(Double.class)) {
1✔
400
            return Double.valueOf(str);
1✔
401
        } else if (typeClass.equals(BigInteger.class)) {
1✔
402
            return new BigInteger(str);
1✔
403
        } else if (typeClass.equals(BigDecimal.class)) {
1✔
404
            return new BigDecimal(str);
1✔
405
        } else if (typeClass.equals(Boolean.class)) {
1✔
406
            if (str.length() == 1) {
1✔
407
                if (str.charAt(0) == '1') {
1✔
408
                    return Boolean.TRUE;
1✔
409
                } else if (str.charAt(0) == '0') {
1✔
410
                    return Boolean.FALSE;
1✔
411
                }
412
            }
413
            return Boolean.valueOf(str);
1✔
414
        } else if (typeClass.equals(Character.class)) {
1✔
415
            if (str.length() > 1) {
1✔
416
                throw new IllegalArgumentException("The string has a length > 1");
1✔
417
            }
418
            return str.charAt(0);
1✔
419
        }
420

421
        // Instant
422
        if (typeClass.equals(Instant.class)) {
1✔
423
            double milliseconds = FormattingAndParsingUtils.parseDateTimeOrTimestamp(str, zoneId);
1✔
424
            return Instant.ofEpochMilli(Math.round(milliseconds));
1✔
425
        }
426

427
        // Interval types:
428
        if (typeClass.equals(IntervalSet.class)) {
1✔
429
            return IntervalsParser.parseIntervalSet(str, zoneId);
1✔
430
        } else if (typeClass.equals(IntervalStringMap.class)) {
1✔
431
            return IntervalsParser.parseIntervalMap(String.class, str, zoneId);
1✔
432
        } else if (typeClass.equals(IntervalByteMap.class)) {
1✔
433
            return IntervalsParser.parseIntervalMap(Byte.class, str, zoneId);
1✔
434
        } else if (typeClass.equals(IntervalShortMap.class)) {
1✔
435
            return IntervalsParser.parseIntervalMap(Short.class, str, zoneId);
1✔
436
        } else if (typeClass.equals(IntervalIntegerMap.class)) {
1✔
437
            return IntervalsParser.parseIntervalMap(Integer.class, str, zoneId);
1✔
438
        } else if (typeClass.equals(IntervalLongMap.class)) {
1✔
439
            return IntervalsParser.parseIntervalMap(Long.class, str, zoneId);
1✔
440
        } else if (typeClass.equals(IntervalFloatMap.class)) {
1✔
441
            return IntervalsParser.parseIntervalMap(Float.class, str, zoneId);
1✔
442
        } else if (typeClass.equals(IntervalDoubleMap.class)) {
1✔
443
            return IntervalsParser.parseIntervalMap(Double.class, str, zoneId);
1✔
444
        } else if (typeClass.equals(IntervalBooleanMap.class)) {
1✔
445
            return IntervalsParser.parseIntervalMap(Boolean.class, str, zoneId);
1✔
446
        } else if (typeClass.equals(IntervalCharMap.class)) {
1✔
447
            return IntervalsParser.parseIntervalMap(Character.class, str, zoneId);
1✔
448
        }
449

450
        // Timestamp types:
451
        if (typeClass.equals(TimestampSet.class)) {
1✔
452
            return TimestampsParser.parseTimestampSet(str, zoneId);
1✔
453
        } else if (typeClass.equals(TimestampStringMap.class)) {
1✔
454
            return TimestampsParser.parseTimestampMap(String.class, str, zoneId);
1✔
455
        } else if (typeClass.equals(TimestampByteMap.class)) {
1✔
456
            return TimestampsParser.parseTimestampMap(Byte.class, str, zoneId);
1✔
457
        } else if (typeClass.equals(TimestampShortMap.class)) {
1✔
458
            return TimestampsParser.parseTimestampMap(Short.class, str, zoneId);
1✔
459
        } else if (typeClass.equals(TimestampIntegerMap.class)) {
1✔
460
            return TimestampsParser.parseTimestampMap(Integer.class, str, zoneId);
1✔
461
        } else if (typeClass.equals(TimestampLongMap.class)) {
1✔
462
            return TimestampsParser.parseTimestampMap(Long.class, str, zoneId);
1✔
463
        } else if (typeClass.equals(TimestampFloatMap.class)) {
1✔
464
            return TimestampsParser.parseTimestampMap(Float.class, str, zoneId);
1✔
465
        } else if (typeClass.equals(TimestampDoubleMap.class)) {
1✔
466
            return TimestampsParser.parseTimestampMap(Double.class, str, zoneId);
1✔
467
        } else if (typeClass.equals(TimestampBooleanMap.class)) {
1✔
468
            return TimestampsParser.parseTimestampMap(Boolean.class, str, zoneId);
1✔
469
        } else if (typeClass.equals(TimestampCharMap.class)) {
1✔
470
            return TimestampsParser.parseTimestampMap(Character.class, str, zoneId);
1✔
471
        }
472

473
        // Array types:
474
        if (typeClass.equals(boolean[].class)) {
1✔
475
            return ArraysParser.parseArrayAsPrimitiveArray(Boolean[].class, str);
1✔
476
        } else if (typeClass.equals(char[].class)) {
1✔
477
            return ArraysParser.parseArrayAsPrimitiveArray(Character[].class, str);
×
478
        } else if (typeClass.equals(byte[].class)) {
1✔
479
            return ArraysParser.parseArrayAsPrimitiveArray(Byte[].class, str);
1✔
480
        } else if (typeClass.equals(short[].class)) {
1✔
481
            return ArraysParser.parseArrayAsPrimitiveArray(Short[].class, str);
1✔
482
        } else if (typeClass.equals(int[].class)) {
1✔
483
            return ArraysParser.parseArrayAsPrimitiveArray(Integer[].class, str);
1✔
484
        } else if (typeClass.equals(long[].class)) {
1✔
485
            return ArraysParser.parseArrayAsPrimitiveArray(Long[].class, str);
1✔
486
        } else if (typeClass.equals(float[].class)) {
1✔
487
            return ArraysParser.parseArrayAsPrimitiveArray(Float[].class, str);
1✔
488
        } else if (typeClass.equals(double[].class)) {
1✔
489
            return ArraysParser.parseArrayAsPrimitiveArray(Double[].class, str);
1✔
490
        } else if (typeClass.equals(Boolean[].class) || typeClass.equals(String[].class) || typeClass
1✔
491
                .equals(Character[].class) || typeClass.equals(Byte[].class) || typeClass
1✔
492
                        .equals(Short[].class) || typeClass.equals(Integer[].class) || typeClass
1✔
493
                                .equals(Long[].class) || typeClass.equals(Float[].class) || typeClass
1✔
494
                                        .equals(Double[].class) || typeClass
1✔
495
                                                .equals(BigInteger[].class) || typeClass.equals(BigDecimal[].class)) {
1✔
496
            return ArraysParser.parseArray(typeClass, str);
1✔
497
        }
498

499
        throw new IllegalArgumentException("Unsupported type " + typeClass.getCanonicalName());
1✔
500
    }
501

502
    /**
503
     * Parses the given string using the type class provided and returns an
504
     * instance.
505
     *
506
     * Default time zone is used (UTC) for dynamic types (timestamps/intervals).
507
     *
508
     * @param str string to parse
509
     * @param typeClass class of the desired type
510
     * @return an instance of the type class, or null if <em>str</em> is null or
511
     *         empty
512
     */
513
    public static Object parse(String str, Class typeClass) {
514
        return parse(str, typeClass, null);
1✔
515
    }
516

517
    /**
518
     * Returns the primitive type for the given wrapped primitive.
519
     * <p>
520
     * Example: Returns <em>int.class</em> given <em>Integer.class</em>
521
     *
522
     * @param type type to get the primitive type from
523
     * @return primitive type
524
     */
525
    public static Class getPrimitiveType(Class type) {
526
        if (!type.isPrimitive()) {
1✔
527
            if (type.equals(Boolean.class)) {
1✔
528
                return boolean.class;
1✔
529
            } else if (type.equals(Integer.class)) {
1✔
530
                return int.class;
1✔
531
            } else if (type.equals(Short.class)) {
1✔
532
                return short.class;
1✔
533
            } else if (type.equals(Long.class)) {
1✔
534
                return long.class;
1✔
535
            } else if (type.equals(Byte.class)) {
1✔
536
                return byte.class;
1✔
537
            } else if (type.equals(Float.class)) {
1✔
538
                return float.class;
1✔
539
            } else if (type.equals(Double.class)) {
1✔
540
                return double.class;
1✔
541
            } else if (type.equals(Character.class)) {
1✔
542
                return char.class;
1✔
543
            }
544
        }
545
        throw new IllegalArgumentException("The type should be a wrapped primitive");
1✔
546
    }
547

548
    /**
549
     * Returns the primitive array given a wrapped primitive array.
550
     * <p>
551
     * Example: Returns <em>int[]</em> array given an <em>Integer[]</em> array
552
     *
553
     * @param array wrapped primitive array instance
554
     * @return primitive array instance
555
     * @throws IllegalArgumentException Thrown if any of the array values is null
556
     */
557
    public static Object getPrimitiveArray(Object[] array) {
558
        if (!isSupported(array.getClass())) {
1✔
559
            throw new IllegalArgumentException("Unsupported type " + array.getClass().getCanonicalName());
1✔
560
        }
561
        Class arrayClass = array.getClass().getComponentType();
1✔
562
        if (!arrayClass
1✔
563
                .isPrimitive() && (arrayClass == Double.class || arrayClass == Float.class || arrayClass == Long.class || arrayClass == Integer.class || arrayClass == Short.class || arrayClass == Character.class || arrayClass == Byte.class || arrayClass == Boolean.class)) {
1✔
564
            Class primitiveClass = getPrimitiveType(arrayClass);
1✔
565

566
            int arrayLength = array.length;
1✔
567
            Object primitiveArray = Array.newInstance(primitiveClass, arrayLength);
1✔
568

569
            for (int i = 0; i < arrayLength; i++) {
1✔
570
                Object obj = array[i];
1✔
571
                Array.set(primitiveArray, i, obj);
1✔
572
            }
573
            return primitiveArray;
1✔
574
        }
575
        return array;
1✔
576
    }
577

578
    /**
579
     * Returns the set of types supported.
580
     *
581
     * @return set of supported types
582
     */
583
    public static Set<Class> getSupportedTypes() {
584
        return SUPPORTED_TYPES;
1✔
585
    }
586

587
    /**
588
     * Returns true if <em>type</em> is a supported type.
589
     *
590
     * @param type type to test support
591
     * @return true if supported, false otherwise
592
     */
593
    public static boolean isSupported(Class type) {
594
        if (type == null) {
1✔
595
            throw new NullPointerException();
1✔
596
        }
597
        return SUPPORTED_TYPES.contains(type) || isCollectionType(type) || isMapType(type);
1✔
598
    }
599

600
    /**
601
     * Returns the standardized type for the given type class.
602
     * <p>
603
     * For instance, <code>getStandardizedType(int.class)</code> would return
604
     * <code>Integer.class</code>.
605
     *
606
     * @param type type to standardize
607
     * @return standardized type
608
     */
609
    public static Class getStandardizedType(Class type) {
610
        if (!isSupported(type)) {
1✔
611
            throw new IllegalArgumentException("Unsupported type " + type.getCanonicalName());
1✔
612
        }
613
        Class t = TYPES_STANDARDIZATION.get(type);
1✔
614
        if (t != null) {
1✔
615
            return t;
1✔
616
        }
617
        return type;
1✔
618
    }
619

620
    /**
621
     * Returns true if <em>type</em> is a standardized type.
622
     * <p>
623
     * Non standardized types are transformed into standardized types using
624
     * {@link #getStandardizedType(java.lang.Class) }.
625
     *
626
     * @param type the type to test
627
     * @return true if <em>type</em> is standardized, false otherwise
628
     */
629
    public static boolean isStandardizedType(Class type) {
630
        if (!isSupported(type)) {
1✔
631
            throw new IllegalArgumentException("Unsupported type " + type.getCanonicalName());
1✔
632
        }
633
        return TYPES_STANDARDIZATION.get(type) == null;
1✔
634
    }
635

636
    /**
637
     * Returns the dynamic timestamp map value type for the given type.
638
     *
639
     * @param type static type
640
     * @return timestamp map type
641
     */
642
    public static Class<? extends TimestampMap> getTimestampMapType(Class type) {
643
        if (!isSupported(type)) {
1✔
644
            throw new IllegalArgumentException("Unsupported type " + type.getCanonicalName());
1✔
645
        }
646
        type = getStandardizedType(type);
1✔
647
        if (type.equals(Boolean.class)) {
1✔
648
            return TimestampBooleanMap.class;
1✔
649
        } else if (type.equals(Integer.class)) {
1✔
650
            return TimestampIntegerMap.class;
1✔
651
        } else if (type.equals(Short.class)) {
1✔
652
            return TimestampShortMap.class;
1✔
653
        } else if (type.equals(Long.class)) {
1✔
654
            return TimestampLongMap.class;
1✔
655
        } else if (type.equals(Byte.class)) {
1✔
656
            return TimestampByteMap.class;
1✔
657
        } else if (type.equals(Float.class)) {
1✔
658
            return TimestampFloatMap.class;
1✔
659
        } else if (type.equals(Double.class)) {
1✔
660
            return TimestampDoubleMap.class;
1✔
661
        } else if (type.equals(Character.class)) {
1✔
662
            return TimestampCharMap.class;
1✔
663
        } else if (type.equals(String.class)) {
1✔
664
            return TimestampStringMap.class;
1✔
665
        }
666
        throw new IllegalArgumentException("Unsupported type " + type.getCanonicalName());
×
667
    }
668

669
    /**
670
     * Returns the dynamic timestamp map value type for the given type.
671
     *
672
     * @param type static type
673
     * @return timestamp map type
674
     */
675
    public static Class<? extends IntervalMap> getIntervalMapType(Class type) {
676
        if (!isSupported(type)) {
1✔
677
            throw new IllegalArgumentException("Unsupported type " + type.getCanonicalName());
1✔
678
        }
679
        type = getStandardizedType(type);
1✔
680
        if (type.equals(Boolean.class)) {
1✔
681
            return IntervalBooleanMap.class;
1✔
682
        } else if (type.equals(Integer.class)) {
1✔
683
            return IntervalIntegerMap.class;
1✔
684
        } else if (type.equals(Short.class)) {
1✔
685
            return IntervalShortMap.class;
1✔
686
        } else if (type.equals(Long.class)) {
1✔
687
            return IntervalLongMap.class;
1✔
688
        } else if (type.equals(Byte.class)) {
1✔
689
            return IntervalByteMap.class;
1✔
690
        } else if (type.equals(Float.class)) {
1✔
691
            return IntervalFloatMap.class;
1✔
692
        } else if (type.equals(Double.class)) {
1✔
693
            return IntervalDoubleMap.class;
1✔
694
        } else if (type.equals(Character.class)) {
1✔
695
            return IntervalCharMap.class;
1✔
696
        } else if (type.equals(String.class)) {
1✔
697
            return IntervalStringMap.class;
1✔
698
        }
699
        throw new IllegalArgumentException("Unsupported type " + type.getCanonicalName());
×
700
    }
701

702
    /**
703
     * Returns the static type for the given time map type.
704
     *
705
     * @param type time map type
706
     * @return static type
707
     */
708
    public static Class getStaticType(Class<? extends TimeMap> type) {
709
        if (!isSupported(type)) {
1✔
710
            throw new IllegalArgumentException("Unsupported type " + type.getCanonicalName());
1✔
711
        }
712

713
        if (type.equals(TimestampBooleanMap.class) || type.equals(IntervalBooleanMap.class)) {
1✔
714
            return Boolean.class;
1✔
715
        } else if (type.equals(TimestampIntegerMap.class) || type.equals(IntervalIntegerMap.class)) {
1✔
716
            return Integer.class;
1✔
717
        } else if (type.equals(TimestampShortMap.class) || type.equals(IntervalShortMap.class)) {
1✔
718
            return Short.class;
1✔
719
        } else if (type.equals(TimestampLongMap.class) || type.equals(IntervalLongMap.class)) {
1✔
720
            return Long.class;
1✔
721
        } else if (type.equals(TimestampByteMap.class) || type.equals(IntervalByteMap.class)) {
1✔
722
            return Byte.class;
1✔
723
        } else if (type.equals(TimestampFloatMap.class) || type.equals(IntervalFloatMap.class)) {
1✔
724
            return Float.class;
1✔
725
        } else if (type.equals(TimestampDoubleMap.class) || type.equals(IntervalDoubleMap.class)) {
1✔
726
            return Double.class;
1✔
727
        } else if (type.equals(TimestampCharMap.class) || type.equals(IntervalCharMap.class)) {
1✔
728
            return Character.class;
1✔
729
        } else if (type.equals(TimestampStringMap.class) || type.equals(IntervalStringMap.class)) {
1✔
730
            return String.class;
1✔
731
        }
732
        throw new IllegalArgumentException("Unsupported type " + type.getCanonicalName());
×
733
    }
734

735
    /**
736
     * Transform the given <em>value</em> instance in a standardized type if
737
     * necessary.
738
     * <p>
739
     * This function transforms wrapped primitive arrays in primitive arrays.
740
     *
741
     * @param value value to standardize
742
     * @return standardized value, or <em>value</em> if already standardized
743
     */
744
    public static Object standardizeValue(Object value) {
745
        if (value == null) {
1✔
746
            return null;
1✔
747
        }
748
        Class type = value.getClass();
1✔
749
        if (!isSupported(type)) {
1✔
750
            throw new IllegalArgumentException("Unsupported type " + type.getCanonicalName());
1✔
751
        }
752
        if (type.isArray() && !type.getComponentType().isPrimitive()) {
1✔
753
            return getPrimitiveArray((Object[]) value);
1✔
754
        }
755
        if (List.class.isAssignableFrom(type)) {
1✔
756
            return getStandardizedList((List) value);
1✔
757
        } else if (Set.class.isAssignableFrom(type)) {
1✔
758
            return getStandardizedSet((Set) value);
1✔
759
        } else if (Map.class.isAssignableFrom(type)) {
1✔
760
            return getStandardizedMap((Map) value);
1✔
761
        }
762
        return value;
1✔
763
    }
764

765
    private static List getStandardizedList(List list) {
766
        Class listClass = list.getClass();
1✔
767
        if (TYPED_LIST_TYPES.contains(listClass)) {
1✔
768
            return list;
×
769
        }
770

771
        Class oCls = null;
1✔
772
        for (Object o : list) {
1✔
773
            if (o != null) {
1✔
774
                if (oCls == null) {
1✔
775
                    oCls = o.getClass();
1✔
776
                } else if (!o.getClass().equals(oCls)) {
1✔
777
                    throw new IllegalArgumentException("The list contains mixed classes");
1✔
778
                }
779
            }
780
        }
1✔
781
        if (oCls != null && !(isSimpleType(oCls) || isArrayType(oCls))) {
1✔
782
            throw new IllegalArgumentException("The list contains unsupported type " + oCls.getCanonicalName());
1✔
783
        }
784
        if (oCls != null) {
1✔
785
            if (oCls.equals(Integer.class)) {
1✔
786
                return new IntArrayList(list);
1✔
787
            } else if (oCls.equals(Float.class)) {
1✔
UNCOV
788
                return new FloatArrayList(list);
×
789
            } else if (oCls.equals(Double.class)) {
1✔
UNCOV
790
                return new DoubleArrayList(list);
×
791
            } else if (oCls.equals(Short.class)) {
1✔
UNCOV
792
                return new ShortArrayList(list);
×
793
            } else if (oCls.equals(Byte.class)) {
1✔
UNCOV
794
                return new ByteArrayList(list);
×
795
            } else if (oCls.equals(Long.class)) {
1✔
UNCOV
796
                return new LongArrayList(list);
×
797
            } else if (oCls.equals(Boolean.class)) {
1✔
UNCOV
798
                return new BooleanArrayList(list);
×
799
            } else if (oCls.equals(Character.class)) {
1✔
UNCOV
800
                return new CharArrayList(list);
×
801
            }
802
        }
803
        List result = new ObjectArrayList(list.size());
1✔
804
        for (Object o : list) {
1✔
805
            result.add(standardizeValue(o));
1✔
806
        }
1✔
807
        return result;
1✔
808
    }
809

810
    private static Set getStandardizedSet(Set set) {
811
        Class setClass = set.getClass();
1✔
812
        if (TYPED_SET_TYPES.contains(setClass)) {
1✔
UNCOV
813
            return set;
×
814
        }
815

816
        Class oCls = null;
1✔
817
        for (Object o : set) {
1✔
818
            if (o != null) {
1✔
819
                if (oCls == null) {
1✔
820
                    oCls = o.getClass();
1✔
821
                } else if (!o.getClass().equals(oCls)) {
1✔
822
                    throw new IllegalArgumentException("The set contains mixed classes");
1✔
823
                }
824
            }
825
        }
1✔
826
        if (oCls != null && !(isSimpleType(oCls) || isArrayType(oCls))) {
1✔
827
            throw new IllegalArgumentException("The set contains unsupported type " + oCls.getCanonicalName());
1✔
828
        }
829
        if (oCls != null) {
1✔
830
            if (oCls.equals(Integer.class)) {
1✔
831
                return new IntOpenHashSet(set);
1✔
832
            } else if (oCls.equals(Float.class)) {
1✔
833
                return new FloatOpenHashSet(set);
×
834
            } else if (oCls.equals(Double.class)) {
1✔
835
                return new DoubleOpenHashSet(set);
×
836
            } else if (oCls.equals(Short.class)) {
1✔
837
                return new ShortOpenHashSet(set);
×
838
            } else if (oCls.equals(Byte.class)) {
1✔
839
                return new ByteOpenHashSet(set);
×
840
            } else if (oCls.equals(Long.class)) {
1✔
841
                return new LongOpenHashSet(set);
×
842
            } else if (oCls.equals(Boolean.class)) {
1✔
843
                return new BooleanOpenHashSet(set);
×
844
            } else if (oCls.equals(Character.class)) {
1✔
UNCOV
845
                return new CharOpenHashSet(set);
×
846
            }
847
        }
848
        Set result = new ObjectOpenHashSet(set.size());
1✔
849
        for (Object o : set) {
1✔
850
            result.add(standardizeValue(o));
1✔
851
        }
1✔
852
        return result;
1✔
853
    }
854

855
    private static Map getStandardizedMap(Map<?, ?> map) {
856
        Class mapClass = map.getClass();
1✔
857
        if (TYPED_MAP_TYPES.contains(mapClass)) {
1✔
UNCOV
858
            return map;
×
859
        }
860

861
        Class oCls = null;
1✔
862
        for (Map.Entry entry : map.entrySet()) {
1✔
863
            Object key = entry.getKey();
1✔
864
            Object value = entry.getValue();
1✔
865
            if (key != null) {
1✔
866
                if (oCls == null) {
1✔
867
                    oCls = key.getClass();
1✔
868
                } else if (!key.getClass().equals(oCls)) {
1✔
869
                    throw new IllegalArgumentException("The map contains mixed key classes");
1✔
870
                }
871
            }
872
            if (value != null && !(isSimpleType(value.getClass()) || isArrayType(value.getClass()))) {
1✔
873
                throw new IllegalArgumentException(
1✔
874
                        "The map contains unsupported value type " + value.getClass().getCanonicalName());
1✔
875
            }
876
        }
1✔
877
        if (oCls != null && !isSimpleType(oCls)) {
1✔
878
            throw new IllegalArgumentException("The map contains unsupported key type " + oCls.getCanonicalName());
1✔
879
        }
880
        if (oCls != null) {
1✔
881
            if (oCls.equals(Integer.class)) {
1✔
882
                return new Int2ObjectOpenHashMap(map);
1✔
883
            } else if (oCls.equals(Float.class)) {
1✔
UNCOV
884
                return new Float2ObjectOpenHashMap(map);
×
885
            } else if (oCls.equals(Double.class)) {
1✔
UNCOV
886
                return new Double2ObjectOpenHashMap(map);
×
887
            } else if (oCls.equals(Short.class)) {
1✔
UNCOV
888
                return new Short2ObjectOpenHashMap(map);
×
889
            } else if (oCls.equals(Byte.class)) {
1✔
UNCOV
890
                return new Byte2ObjectOpenHashMap(map);
×
891
            } else if (oCls.equals(Long.class)) {
1✔
UNCOV
892
                return new Long2ObjectOpenHashMap(map);
×
893
            } else if (oCls.equals(Character.class)) {
1✔
UNCOV
894
                return new Char2ObjectOpenHashMap(map);
×
895
            }
896
        }
897
        Map result = new Object2ObjectOpenHashMap(map.size());
1✔
898
        for (Map.Entry o : map.entrySet()) {
1✔
899
            result.put(o.getKey(), standardizeValue(o.getValue()));
1✔
900
        }
1✔
901
        return result;
1✔
902
    }
903

904
    /**
905
     * Returns true if <em>type</em> is a number type.
906
     * <p>
907
     * This can be true for static, arrays and dynamic types.
908
     *
909
     * @param type type to test
910
     * @return true if <em>type</em> is a number type, false otherwise
911
     */
912
    public static boolean isNumberType(Class type) {
913
        if (!isSupported(type)) {
1✔
914
            throw new IllegalArgumentException("Unsupported type " + type.getCanonicalName());
1✔
915
        }
916
        type = getStandardizedType(type);
1✔
917
        return Number.class.isAssignableFrom(type) || int[].class.isAssignableFrom(type) || float[].class
1✔
918
                .isAssignableFrom(type) || double[].class.isAssignableFrom(type) || byte[].class
1✔
919
                        .isAssignableFrom(type) || short[].class.isAssignableFrom(type) || long[].class
1✔
920
                                .isAssignableFrom(type) || type.equals(TimestampIntegerMap.class) || type
1✔
921
                                        .equals(TimestampFloatMap.class) || type
1✔
922
                                                .equals(TimestampDoubleMap.class) || type
1✔
923
                                                        .equals(TimestampLongMap.class) || type
1✔
924
                                                                .equals(TimestampShortMap.class) || type
1✔
925
                                                                        .equals(TimestampByteMap.class) || type
1✔
926
                                                                                .equals(IntervalIntegerMap.class) || type
1✔
927
                                                                                        .equals(IntervalFloatMap.class) || type
1✔
928
                                                                                                .equals(IntervalDoubleMap.class) || type
1✔
929
                                                                                                        .equals(IntervalLongMap.class) || type
1✔
930
                                                                                                                .equals(IntervalShortMap.class) || type
1✔
931
                                                                                                                        .equals(IntervalByteMap.class);
1✔
932
    }
933

934
    /**
935
     * Returns true if <em>type</em> is a string type
936
     * <p>
937
     * This can be true for static, arrays and dynamic types.
938
     *
939
     * @param type type to test
940
     * @return true if <em>type</em> is a string type, false otherwise
941
     */
942
    public static boolean isStringType(Class type) {
943
        if (!isSupported(type)) {
1✔
944
            throw new IllegalArgumentException("Unsupported type " + type.getCanonicalName());
1✔
945
        }
946
        return type.equals(String.class) || type.equals(String[].class) || type.equals(TimestampStringMap.class) || type
1✔
947
                .equals(IntervalStringMap.class);
1✔
948
    }
949

950
    /**
951
     * Returns true if <em>type</em> is a boolean type
952
     * <p>
953
     * This can be true for static, arrays and dynamic types.
954
     *
955
     * @param type type to test
956
     * @return true if <em>type</em> is a boolean type, false otherwise
957
     */
958
    public static boolean isBooleanType(Class type) {
959
        if (!isSupported(type)) {
1✔
960
            throw new IllegalArgumentException("Unsupported type " + type.getCanonicalName());
1✔
961
        }
962
        type = getStandardizedType(type);
1✔
963
        return type.equals(Boolean.class) || type.equals(boolean[].class) || type
1✔
964
                .equals(TimestampBooleanMap.class) || type.equals(IntervalBooleanMap.class);
1✔
965
    }
966

967
    /**
968
     * Returns true if <em>type</em> is a dynamic type.
969
     *
970
     * @param type type to test
971
     * @return true if <em>type</em> is a dynamic type, false otherwise
972
     */
973
    public static boolean isDynamicType(Class type) {
974
        return (!type.equals(TimestampMap.class) && TimestampMap.class.isAssignableFrom(type)) || type
1✔
975
                .equals(TimestampSet.class) || (!type.equals(IntervalMap.class) && IntervalMap.class
1✔
976
                        .isAssignableFrom(type)) || type.equals(IntervalSet.class);
1✔
977
    }
978

979
    /**
980
     * Returns true if <em>type</em> is a simple type.
981
     * <p>
982
     * Simple types are primitives, String and wrapper types (e.g. Integer).
983
     *
984
     * @param type type to test
985
     * @return true if <em>type</em> is a simple type, false otherwise
986
     */
987
    public static boolean isSimpleType(Class type) {
988
        return (type
1✔
989
                .isPrimitive() && type != void.class) || type == Double.class || type == Float.class || type == Long.class || type == Integer.class || type == Short.class || type == Character.class || type == Byte.class || type == Boolean.class || type == String.class;
1✔
990
    }
991

992
    /**
993
     * Returns true if <em>type</em> is an array type.
994
     *
995
     * @param type type to test
996
     * @return true if <em>type</em> is an array type, false otherwise
997
     */
998
    public static boolean isArrayType(Class type) {
999
        return type.isArray() && isSupported(type.getComponentType());
1✔
1000
    }
1001

1002
    /**
1003
     * Returns true if <em>type</em> is a collection type.
1004
     * <p>
1005
     * Collection types are either <em>List</em> or <em>Set</em>.
1006
     *
1007
     * @param type type to test
1008
     * @return true if <em>type</em> is a collection type, false otherwise
1009
     */
1010
    public static boolean isCollectionType(Class type) {
1011
        return List.class.isAssignableFrom(type) || Set.class.isAssignableFrom(type);
1✔
1012
    }
1013

1014
    /**
1015
     * Returns true if <em>type</em> is a map type.
1016
     * <p>
1017
     * Collection types implement the <em>Map</em> interface.
1018
     *
1019
     * @param type type to test
1020
     * @return true if <em>type</em> is a map type, false otherwise
1021
     */
1022
    public static boolean isMapType(Class type) {
1023
        return Map.class.isAssignableFrom(type);
1✔
1024
    }
1025

1026
    /**
1027
     * Returns the type name for the given type.
1028
     *
1029
     * @param type type to get its name
1030
     * @return type name
1031
     */
1032
    public static String getTypeName(Class type) {
1033
        if (!isSupported(type)) {
1✔
1034
            throw new IllegalArgumentException("Unsupported type " + type.getCanonicalName());
1✔
1035
        }
1036
        type = getStandardizedType(type);
1✔
1037
        return type.getSimpleName().toLowerCase();
1✔
1038
    }
1039

1040
    /**
1041
     * Parses the given time and returns its milliseconds representation.
1042
     *
1043
     * @param dateTime type to parse
1044
     * @param zoneId time zone to use or null to use default time zone (UTC)
1045
     * @return milliseconds representation
1046
     * @throws DateTimeParseException if the time cannot be parsed
1047
     */
1048
    public static double parseDateTime(String dateTime, ZoneId zoneId) throws DateTimeParseException {
1049
        DateTimeFormatter dateTimeParserByTimeZone = getDateTimeParserByTimeZone(zoneId);
1✔
1050
        Instant instant = dateTimeParserByTimeZone.parse(dateTime, Instant::from);
1✔
1051
        return (double) instant.toEpochMilli();
1✔
1052
    }
1053

1054
    /**
1055
     * Parses the given time and returns its milliseconds representation. Default
1056
     * time zone is used (UTC).
1057
     *
1058
     * @param dateTime the type to parse
1059
     * @return milliseconds representation
1060
     * @throws DateTimeParseException if the time cannot be parsed
1061
     */
1062
    public static double parseDateTime(String dateTime) throws DateTimeParseException {
1063
        return parseDateTime(dateTime, null);
1✔
1064
    }
1065

1066
    /**
1067
     * Parses an ISO date with or without time or a timestamp (in milliseconds).
1068
     * Returns the date or timestamp converted to a timestamp in milliseconds.
1069
     *
1070
     * @param timeStr Date or timestamp string
1071
     * @param zoneId Time zone to use or null to use default time zone (UTC)
1072
     * @return Timestamp
1073
     * @throws DateTimeParseException if the time cannot be parsed
1074
     */
1075
    public static double parseDateTimeOrTimestamp(String timeStr, ZoneId zoneId) throws DateTimeParseException {
1076
        return FormattingAndParsingUtils.parseDateTimeOrTimestamp(timeStr, zoneId);
1✔
1077
    }
1078

1079
    /**
1080
     * Parses an ISO date with or without time or a timestamp (in milliseconds).
1081
     * Returns the date or timestamp converted to a timestamp in milliseconds.
1082
     * Default time zone is used (UTC).
1083
     *
1084
     * @param timeStr Date or timestamp string
1085
     * @return Timestamp
1086
     * @throws DateTimeParseException if the time cannot be parsed
1087
     */
1088
    public static double parseDateTimeOrTimestamp(String timeStr) throws DateTimeParseException {
1089
        return FormattingAndParsingUtils.parseDateTimeOrTimestamp(timeStr);
1✔
1090
    }
1091

1092
    /**
1093
     * Returns the string representation of the given timestamp.
1094
     *
1095
     * @param timestamp the time, in milliseconds
1096
     * @return formatted timestamp
1097
     */
1098
    public static String printTimestamp(double timestamp) {
1099
        return TIMESTAMP_PRINTER.format(timestamp);
1✔
1100
    }
1101

1102
    /**
1103
     * Returns the date's string representation of the given timestamp.
1104
     *
1105
     * @param timestamp time, in milliseconds
1106
     * @param zoneId time zone to use or null to use default time zone (UTC)
1107
     * @return formatted date
1108
     */
1109
    public static String printDate(double timestamp, ZoneId zoneId) {
1110
        if (Double.isInfinite(timestamp) || Double.isNaN(timestamp)) {
1✔
1111
            return printTimestamp(timestamp);
1✔
1112
        }
1113
        return printDate(Instant.ofEpochMilli((long) timestamp), zoneId);
1✔
1114
    }
1115

1116
    /**
1117
     * Returns the date's string representation of the given instant.
1118
     *
1119
     * @param instant instant to format
1120
     * @param zoneId time zone to use or null to use default time zone (UTC)
1121
     * @return formatted date
1122
     */
1123
    public static String printDate(Instant instant, ZoneId zoneId) {
1124
        DateTimeFormatter datePrinterByTimeZone = getDatePrinterByTimeZone(zoneId);
1✔
1125
        ZonedDateTime zonedDateTime = instant.atZone(datePrinterByTimeZone.getZone());
1✔
1126
        return zonedDateTime.format(datePrinterByTimeZone);
1✔
1127
    }
1128

1129
    /**
1130
     * Returns the date's string representation of the given timestamp. Default time
1131
     * zone is used (UTC).
1132
     *
1133
     * @param timestamp time, in milliseconds
1134
     * @return formatted date
1135
     */
1136
    public static String printDate(double timestamp) {
1137
        return printDate(timestamp, null);
1✔
1138
    }
1139

1140
    /**
1141
     * Returns the time's string representation of the given timestamp.
1142
     *
1143
     * @param timestamp time, in milliseconds
1144
     * @param zoneId time zone to use or null to use default time zone (UTC)
1145
     * @return formatted time
1146
     */
1147
    public static String printDateTime(double timestamp, ZoneId zoneId) {
1148
        if (Double.isInfinite(timestamp) || Double.isNaN(timestamp)) {
1✔
1149
            return printTimestamp(timestamp);
1✔
1150
        }
1151
        return printDateTime(Instant.ofEpochMilli((long) timestamp), zoneId);
1✔
1152
    }
1153

1154
    /**
1155
     * Returns the time's string representation of the given instant.
1156
     *
1157
     * @param instant instant to format
1158
     * @param zoneId time zone to use or null to use default time zone (UTC)
1159
     * @return formatted time
1160
     */
1161
    public static String printDateTime(Instant instant, ZoneId zoneId) {
1162
        DateTimeFormatter dateTimePrinterByTimeZone = getDateTimePrinterByTimeZone(zoneId);
1✔
1163
        ZonedDateTime zonedDateTime2 = instant.atZone(dateTimePrinterByTimeZone.getZone());
1✔
1164
        OffsetDateTime time = OffsetDateTime.from(zonedDateTime2);
1✔
1165
        return time.format(dateTimePrinterByTimeZone);
1✔
1166
    }
1167

1168
    /**
1169
     * Returns the time's string representation of the given timestamp. Default time
1170
     * zone is used (UTC).
1171
     *
1172
     * @param timestamp time, in milliseconds
1173
     * @return formatted time
1174
     */
1175
    public static String printDateTime(double timestamp) {
1176
        return printDateTime(timestamp, null);
1✔
1177
    }
1178

1179
    /**
1180
     * Returns the string representation of the given timestamp in the given format.
1181
     *
1182
     * @param timestamp time, in milliseconds
1183
     * @param timeFormat time format
1184
     * @param zoneId time zone to use or null to use default time zone (UTC).
1185
     * @return formatted timestamp
1186
     */
1187
    public static String printTimestampInFormat(double timestamp, TimeFormat timeFormat, ZoneId zoneId) {
1188
        switch (timeFormat) {
1✔
1189
            case DATE:
1190
                return AttributeUtils.printDate(timestamp, zoneId);
1✔
1191
            case DATETIME:
1192
                return AttributeUtils.printDateTime(timestamp, zoneId);
1✔
1193
            case DOUBLE:
1194
                return AttributeUtils.printTimestamp(timestamp);
1✔
1195
        }
1196

UNCOV
1197
        throw new UnsupportedOperationException("Unknown TimeFormat");
×
1198
    }
1199

1200
    /**
1201
     * Returns the string representation of the given timestamp in the given format.
1202
     * Default time zone is used (UTC).
1203
     *
1204
     * @param timestamp time, in milliseconds
1205
     * @param timeFormat time format
1206
     * @return formatted timestamp
1207
     */
1208
    public static String printTimestampInFormat(double timestamp, TimeFormat timeFormat) {
UNCOV
1209
        return printTimestampInFormat(timestamp, timeFormat, null);
×
1210
    }
1211

1212
    /**
1213
     * Returns the string representation of the given array. The used format is the
1214
     * same format supported by {@link #parse(java.lang.String, java.lang.Class)}
1215
     * method
1216
     *
1217
     * @param arr Input array. Can be an array of objects or primitives.
1218
     * @return formatted array
1219
     */
1220
    public static String printArray(Object arr) {
1221
        return FormattingAndParsingUtils.printArray(arr);
1✔
1222
    }
1223

1224
    /**
1225
     * Returns true if the given column is a node column.
1226
     *
1227
     * @param colum column to test
1228
     * @return true if the column is a node column, false otherwise
1229
     */
1230
    public static boolean isNodeColumn(Column colum) {
1231
        return colum.getTable().getElementClass().equals(Node.class);
1✔
1232
    }
1233

1234
    /**
1235
     * Returns true if the given column is an edge column.
1236
     *
1237
     * @param colum column to test
1238
     * @return true if the column is an edge column, false otherwise
1239
     */
1240
    public static boolean isEdgeColumn(Column colum) {
1241
        return colum.getTable().getElementClass().equals(Edge.class);
1✔
1242
    }
1243

1244
    /**
1245
     * Returns a copy of the provided object.
1246
     * <p>
1247
     * The copy is a deep copy for arrays, {@link IntervalSet},
1248
     * {@link TimestampSet}, sets and lists
1249
     *
1250
     * @param obj object to copy
1251
     * @return copy of the provided object
1252
     */
1253
    public static Object copy(Object obj) {
1254
        if (obj == null) {
1✔
1255
            return null;
1✔
1256
        }
1257
        Class typeClass = obj.getClass();
1✔
1258
        if (!isSupported(typeClass)) {
1✔
UNCOV
1259
            throw new IllegalArgumentException("Unsupported type " + typeClass.getCanonicalName());
×
1260
        }
1261
        typeClass = getStandardizedType(typeClass);
1✔
1262
        obj = standardizeValue(obj);
1✔
1263

1264
        // Primitive
1265
        if (isSimpleType(typeClass)) {
1✔
1266
            return obj;
1✔
1267
        }
1268

1269
        // Instant
1270
        if (typeClass.equals(Instant.class)) {
1✔
1271
            return obj;
1✔
1272
        }
1273

1274
        // Interval types:
1275
        if (typeClass.equals(IntervalSet.class)) {
1✔
1276
            return new IntervalSet((IntervalSet) obj);
1✔
1277
        } else if (typeClass.equals(IntervalStringMap.class)) {
1✔
1278
            return new IntervalStringMap((IntervalStringMap) obj);
1✔
1279
        } else if (typeClass.equals(IntervalByteMap.class)) {
1✔
1280
            return new IntervalByteMap((IntervalByteMap) obj);
1✔
1281
        } else if (typeClass.equals(IntervalShortMap.class)) {
1✔
1282
            return new IntervalShortMap((IntervalShortMap) obj);
1✔
1283
        } else if (typeClass.equals(IntervalIntegerMap.class)) {
1✔
1284
            return new IntervalIntegerMap((IntervalIntegerMap) obj);
1✔
1285
        } else if (typeClass.equals(IntervalLongMap.class)) {
1✔
1286
            return new IntervalLongMap((IntervalLongMap) obj);
1✔
1287
        } else if (typeClass.equals(IntervalFloatMap.class)) {
1✔
1288
            return new IntervalFloatMap((IntervalFloatMap) obj);
1✔
1289
        } else if (typeClass.equals(IntervalDoubleMap.class)) {
1✔
1290
            return new IntervalDoubleMap((IntervalDoubleMap) obj);
1✔
1291
        } else if (typeClass.equals(IntervalBooleanMap.class)) {
1✔
1292
            return new IntervalBooleanMap((IntervalBooleanMap) obj);
1✔
1293
        } else if (typeClass.equals(IntervalCharMap.class)) {
1✔
1294
            return new IntervalCharMap((IntervalCharMap) obj);
1✔
1295
        }
1296

1297
        // Timestamp types:
1298
        if (typeClass.equals(TimestampSet.class)) {
1✔
1299
            return new TimestampSet((TimestampSet) obj);
1✔
1300
        } else if (typeClass.equals(TimestampStringMap.class)) {
1✔
1301
            return new TimestampStringMap((TimestampStringMap) obj);
1✔
1302
        } else if (typeClass.equals(TimestampByteMap.class)) {
1✔
1303
            return new TimestampByteMap((TimestampByteMap) obj);
1✔
1304
        } else if (typeClass.equals(TimestampShortMap.class)) {
1✔
1305
            return new TimestampShortMap((TimestampShortMap) obj);
1✔
1306
        } else if (typeClass.equals(TimestampIntegerMap.class)) {
1✔
1307
            return new TimestampIntegerMap((TimestampIntegerMap) obj);
1✔
1308
        } else if (typeClass.equals(TimestampLongMap.class)) {
1✔
1309
            return new TimestampLongMap((TimestampLongMap) obj);
1✔
1310
        } else if (typeClass.equals(TimestampFloatMap.class)) {
1✔
1311
            return new TimestampFloatMap((TimestampFloatMap) obj);
1✔
1312
        } else if (typeClass.equals(TimestampDoubleMap.class)) {
1✔
1313
            return new TimestampDoubleMap((TimestampDoubleMap) obj);
1✔
1314
        } else if (typeClass.equals(TimestampBooleanMap.class)) {
1✔
1315
            return new TimestampBooleanMap((TimestampBooleanMap) obj);
1✔
1316
        } else if (typeClass.equals(TimestampCharMap.class)) {
1✔
1317
            return new TimestampCharMap((TimestampCharMap) obj);
1✔
1318
        }
1319

1320
        // Array
1321
        if (isArrayType(typeClass)) {
1✔
1322
            Class componentType = typeClass.getComponentType();
1✔
1323
            int length = Array.getLength(obj);
1✔
1324
            Object dest = Array.newInstance(componentType, length);
1✔
1325
            System.arraycopy(obj, 0, dest, 0, length);
1✔
1326
            return dest;
1✔
1327
        }
1328

1329
        // List
1330
        if (obj instanceof CharArrayList) {
1✔
UNCOV
1331
            return new CharArrayList((CharArrayList) obj);
×
1332
        } else if (obj instanceof BooleanArrayList) {
1✔
UNCOV
1333
            return new BooleanArrayList((BooleanArrayList) obj);
×
1334
        } else if (obj instanceof ByteArrayList) {
1✔
UNCOV
1335
            return new ByteArrayList((ByteArrayList) obj);
×
1336
        } else if (obj instanceof ShortArrayList) {
1✔
UNCOV
1337
            return new ShortArrayList((ShortArrayList) obj);
×
1338
        } else if (obj instanceof IntArrayList) {
1✔
UNCOV
1339
            return new IntArrayList((IntArrayList) obj);
×
1340
        } else if (obj instanceof LongArrayList) {
1✔
UNCOV
1341
            return new LongArrayList((LongArrayList) obj);
×
1342
        } else if (obj instanceof FloatArrayList) {
1✔
UNCOV
1343
            return new FloatArrayList((FloatArrayList) obj);
×
1344
        } else if (obj instanceof DoubleArrayList) {
1✔
UNCOV
1345
            return new DoubleArrayList((DoubleArrayList) obj);
×
1346
        } else if (obj instanceof ObjectArrayList) {
1✔
1347
            return new ObjectArrayList((ObjectArrayList) obj);
1✔
1348
        }
1349

1350
        // Map
1351
        if (obj instanceof Char2ObjectOpenHashMap) {
1✔
UNCOV
1352
            return new Char2ObjectOpenHashMap((Char2ObjectOpenHashMap) obj);
×
1353
        } else if (obj instanceof Byte2ObjectOpenHashMap) {
1✔
UNCOV
1354
            return new Byte2ObjectOpenHashMap((Byte2ObjectOpenHashMap) obj);
×
1355
        } else if (obj instanceof Short2ObjectOpenHashMap) {
1✔
UNCOV
1356
            return new Short2ObjectOpenHashMap((Short2ObjectOpenHashMap) obj);
×
1357
        } else if (obj instanceof Int2ObjectOpenHashMap) {
1✔
UNCOV
1358
            return new Int2ObjectOpenHashMap((Int2ObjectOpenHashMap) obj);
×
1359
        } else if (obj instanceof Long2ObjectOpenHashMap) {
1✔
UNCOV
1360
            return new Long2ObjectOpenHashMap((Long2ObjectOpenHashMap) obj);
×
1361
        } else if (obj instanceof Float2ObjectOpenHashMap) {
1✔
UNCOV
1362
            return new Float2ObjectOpenHashMap((Float2ObjectOpenHashMap) obj);
×
1363
        } else if (obj instanceof Double2ObjectOpenHashMap) {
1✔
UNCOV
1364
            return new Double2ObjectOpenHashMap((Double2ObjectOpenHashMap) obj);
×
1365
        } else if (obj instanceof Object2ObjectOpenHashMap) {
1✔
1366
            return new Object2ObjectOpenHashMap((Object2ObjectOpenHashMap) obj);
1✔
1367
        }
1368

1369
        // Set
1370
        if (obj instanceof CharOpenHashSet) {
1✔
UNCOV
1371
            return new CharOpenHashSet((CharOpenHashSet) obj);
×
1372
        } else if (obj instanceof BooleanOpenHashSet) {
1✔
UNCOV
1373
            return new BooleanOpenHashSet((BooleanOpenHashSet) obj);
×
1374
        } else if (obj instanceof ByteOpenHashSet) {
1✔
UNCOV
1375
            return new ByteOpenHashSet((ByteOpenHashSet) obj);
×
1376
        } else if (obj instanceof ShortOpenHashSet) {
1✔
UNCOV
1377
            return new ShortOpenHashSet((ShortOpenHashSet) obj);
×
1378
        } else if (obj instanceof IntOpenHashSet) {
1✔
UNCOV
1379
            return new IntOpenHashSet((IntOpenHashSet) obj);
×
1380
        } else if (obj instanceof LongOpenHashSet) {
1✔
UNCOV
1381
            return new LongOpenHashSet((LongOpenHashSet) obj);
×
1382
        } else if (obj instanceof FloatOpenHashSet) {
1✔
UNCOV
1383
            return new FloatOpenHashSet((FloatOpenHashSet) obj);
×
1384
        } else if (obj instanceof DoubleOpenHashSet) {
1✔
UNCOV
1385
            return new DoubleOpenHashSet((DoubleOpenHashSet) obj);
×
1386
        } else if (obj instanceof ObjectOpenHashSet) {
1✔
1387
            return new ObjectOpenHashSet((ObjectOpenHashSet) obj);
1✔
1388
        }
1389

UNCOV
1390
        return obj;
×
1391
    }
1392
}
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

© 2026 Coveralls, Inc