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

gephi / graphstore / #521

26 Oct 2025 04:22PM UTC coverage: 91.009%. Remained the same
#521

push

mbastian
Fix other minor issues

4 of 4 new or added lines in 1 file covered. (100.0%)

1 existing line in 1 file now uncovered.

11691 of 12846 relevant lines covered (91.01%)

0.91 hits per line

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

92.0
/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.List;
62
import java.util.Locale;
63
import java.util.Map;
64
import java.util.Set;
65
import org.gephi.graph.api.types.IntervalBooleanMap;
66
import org.gephi.graph.api.types.IntervalByteMap;
67
import org.gephi.graph.api.types.IntervalCharMap;
68
import org.gephi.graph.api.types.IntervalDoubleMap;
69
import org.gephi.graph.api.types.IntervalFloatMap;
70
import org.gephi.graph.api.types.IntervalIntegerMap;
71
import org.gephi.graph.api.types.IntervalLongMap;
72
import org.gephi.graph.api.types.IntervalMap;
73
import org.gephi.graph.api.types.IntervalSet;
74
import org.gephi.graph.api.types.IntervalShortMap;
75
import org.gephi.graph.api.types.IntervalStringMap;
76
import org.gephi.graph.api.types.TimeMap;
77
import org.gephi.graph.api.types.TimeSet;
78
import org.gephi.graph.api.types.TimestampBooleanMap;
79
import org.gephi.graph.api.types.TimestampByteMap;
80
import org.gephi.graph.api.types.TimestampCharMap;
81
import org.gephi.graph.api.types.TimestampDoubleMap;
82
import org.gephi.graph.api.types.TimestampFloatMap;
83
import org.gephi.graph.api.types.TimestampIntegerMap;
84
import org.gephi.graph.api.types.TimestampLongMap;
85
import org.gephi.graph.api.types.TimestampMap;
86
import org.gephi.graph.api.types.TimestampSet;
87
import org.gephi.graph.api.types.TimestampShortMap;
88
import org.gephi.graph.api.types.TimestampStringMap;
89
import org.gephi.graph.impl.ArraysParser;
90
import org.gephi.graph.impl.FormattingAndParsingUtils;
91
import org.gephi.graph.impl.GraphStoreConfiguration;
92
import org.gephi.graph.impl.IntervalsParser;
93
import org.gephi.graph.impl.TimestampsParser;
94

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

253
        DATE_PRINTERS_BY_TIMEZONE = new HashMap<>();
1✔
254
        DATE_TIME_PRINTERS_BY_TIMEZONE = new HashMap<>();
1✔
255
        DATE_TIME_PARSERS_BY_TIMEZONE = new HashMap<>();
1✔
256

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

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

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

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

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

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

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

308
        DateTimeFormatter formatter = cache.get(zoneId);
1✔
309
        if (formatter == null) {
1✔
310
            formatter = baseFormatter.withZone(zoneId);
1✔
311
            cache.put(zoneId, formatter);
1✔
312
        }
313

314
        return formatter;
1✔
315
    }
316

317
    private static DateTimeFormatter getDateTimeParserByTimeZone(ZoneId zoneId) {
318
        return getDateTimeFormatterByTimeZone(DATE_TIME_PARSERS_BY_TIMEZONE, DATE_TIME_PARSER, zoneId);
1✔
319
    }
320

321
    private static DateTimeFormatter getDateTimePrinterByTimeZone(ZoneId zoneId) {
322
        return getDateTimeFormatterByTimeZone(DATE_TIME_PRINTERS_BY_TIMEZONE, DATE_TIME_PRINTER, zoneId);
1✔
323
    }
324

325
    private static DateTimeFormatter getDatePrinterByTimeZone(ZoneId zoneId) {
326
        return getDateTimeFormatterByTimeZone(DATE_PRINTERS_BY_TIMEZONE, DATE_PRINTER, zoneId);
1✔
327
    }
328

329
    /**
330
     * Returns the string representation of the given value.
331
     *
332
     * @param value value
333
     * @return string representation
334
     */
335
    public static String print(Object value) {
336
        return print(value, TimeFormat.DOUBLE, null);
1✔
337
    }
338

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

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

382
        if (str.equalsIgnoreCase("null")) {
1✔
383
            return null;
1✔
384
        }
385

386
        if (typeClass.isPrimitive()) {
1✔
387
            typeClass = getStandardizedType(typeClass);// For primitives we can
1✔
388
                                                       // use auto-unboxing
389
        }
390

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

426
        // Instant
427
        if (typeClass.equals(Instant.class)) {
1✔
428
            double milliseconds = FormattingAndParsingUtils.parseDateTimeOrTimestamp(str, zoneId);
1✔
429
            return Instant.ofEpochMilli((long) milliseconds);
1✔
430
        }
431

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

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

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

504
        throw new IllegalArgumentException("Unsupported type " + typeClass.getCanonicalName());
1✔
505
    }
506

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

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

553
    /**
554
     * Returns the primitive array given a wrapped primitive array.
555
     * <p>
556
     * Example: Returns <em>int[]</em> array given an <em>Integer[]</em> array
557
     *
558
     * @param array wrapped primitive array instance
559
     * @return primitive array instance
560
     * @throws IllegalArgumentException Thrown if any of the array values is null
561
     */
562
    public static Object getPrimitiveArray(Object[] array) {
563
        if (!isSupported(array.getClass())) {
1✔
564
            throw new IllegalArgumentException("Unsupported type " + array.getClass().getCanonicalName());
1✔
565
        }
566
        Class arrayClass = array.getClass().getComponentType();
1✔
567
        if (!arrayClass
1✔
568
                .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✔
569
            Class primitiveClass = getPrimitiveType(arrayClass);
1✔
570

571
            int arrayLength = array.length;
1✔
572
            Object primitiveArray = Array.newInstance(primitiveClass, arrayLength);
1✔
573

574
            for (int i = 0; i < arrayLength; i++) {
1✔
575
                Object obj = array[i];
1✔
576
                Array.set(primitiveArray, i, obj);
1✔
577
            }
578
            return primitiveArray;
1✔
579
        }
580
        return array;
1✔
581
    }
582

583
    /**
584
     * Returns the set of types supported.
585
     *
586
     * @return set of supported types
587
     */
588
    public static Set<Class> getSupportedTypes() {
589
        return SUPPORTED_TYPES;
1✔
590
    }
591

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

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

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

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

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

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

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

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

770
    private static List getStandardizedList(List list) {
771
        Class listClass = list.getClass();
1✔
772
        if (TYPED_LIST_TYPES.contains(listClass)) {
1✔
773
            return list;
×
774
        }
775

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

816
    private static Set getStandardizedSet(Set set) {
817
        Class setClass = set.getClass();
1✔
818
        if (TYPED_SET_TYPES.contains(setClass)) {
1✔
UNCOV
819
            return set;
×
820
        }
821

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

862
    private static Map getStandardizedMap(Map<?, ?> map) {
863
        Class mapClass = map.getClass();
1✔
864
        if (TYPED_MAP_TYPES.contains(mapClass)) {
1✔
865
            return map;
×
866
        }
867

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

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

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

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

975
    /**
976
     * Returns true if <em>type</em> is a dynamic type.
977
     *
978
     * @param type type to test
979
     * @return true if <em>type</em> is a dynamic type, false otherwise
980
     */
981
    public static boolean isDynamicType(Class type) {
982
        return (!type.equals(TimestampMap.class) && TimestampMap.class.isAssignableFrom(type)) || type
1✔
983
                .equals(TimestampSet.class) || (!type.equals(IntervalMap.class) && IntervalMap.class
1✔
984
                        .isAssignableFrom(type)) || type.equals(IntervalSet.class);
1✔
985
    }
986

987
    /**
988
     * Returns true if <em>type</em> is a simple type.
989
     * <p>
990
     * Simple types are primitives, String and wrapper types (e.g. Integer).
991
     *
992
     * @param type type to test
993
     * @return true if <em>type</em> is a simple type, false otherwise
994
     */
995
    public static boolean isSimpleType(Class type) {
996
        return (type
1✔
997
                .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✔
998
    }
999

1000
    /**
1001
     * Returns true if <em>type</em> is an array type.
1002
     *
1003
     * @param type type to test
1004
     * @return true if <em>type</em> is an array type, false otherwise
1005
     */
1006
    public static boolean isArrayType(Class type) {
1007
        return type.isArray() && isSupported(type.getComponentType());
1✔
1008
    }
1009

1010
    /**
1011
     * Returns true if <em>type</em> is a collection type.
1012
     * <p>
1013
     * Collection types are either <em>List</em> or <em>Set</em>.
1014
     *
1015
     * @param type type to test
1016
     * @return true if <em>type</em> is a collection type, false otherwise
1017
     */
1018
    public static boolean isCollectionType(Class type) {
1019
        return List.class.isAssignableFrom(type) || Set.class.isAssignableFrom(type);
1✔
1020
    }
1021

1022
    /**
1023
     * Returns true if <em>type</em> is a map type.
1024
     * <p>
1025
     * Collection types implement the <em>Map</em> interface.
1026
     *
1027
     * @param type type to test
1028
     * @return true if <em>type</em> is a map type, false otherwise
1029
     */
1030
    public static boolean isMapType(Class type) {
1031
        return Map.class.isAssignableFrom(type);
1✔
1032
    }
1033

1034
    /**
1035
     * Returns the type name for the given type.
1036
     *
1037
     * @param type type to get its name
1038
     * @return type name
1039
     */
1040
    public static String getTypeName(Class type) {
1041
        if (!isSupported(type)) {
1✔
1042
            throw new IllegalArgumentException("Unsupported type " + type.getCanonicalName());
1✔
1043
        }
1044
        type = getStandardizedType(type);
1✔
1045
        return type.getSimpleName().toLowerCase();
1✔
1046
    }
1047

1048
    /**
1049
     * Parses the given time and returns its milliseconds representation.
1050
     *
1051
     * @param dateTime type to parse
1052
     * @param zoneId time zone to use or null to use default time zone (UTC)
1053
     * @return milliseconds representation
1054
     * @throws DateTimeParseException if the time cannot be parsed
1055
     */
1056
    public static double parseDateTime(String dateTime, ZoneId zoneId) throws DateTimeParseException {
1057
        DateTimeFormatter dateTimeParserByTimeZone = getDateTimeParserByTimeZone(zoneId);
1✔
1058
        Instant instant = dateTimeParserByTimeZone.parse(dateTime, Instant::from);
1✔
1059
        return (double) instant.toEpochMilli();
1✔
1060
    }
1061

1062
    /**
1063
     * Parses the given time and returns its milliseconds representation. Default
1064
     * time zone is used (UTC).
1065
     *
1066
     * @param dateTime the type to parse
1067
     * @return milliseconds representation
1068
     * @throws DateTimeParseException if the time cannot be parsed
1069
     */
1070
    public static double parseDateTime(String dateTime) throws DateTimeParseException {
1071
        return parseDateTime(dateTime, null);
1✔
1072
    }
1073

1074
    /**
1075
     * Parses an ISO date with or without time or a timestamp (in milliseconds).
1076
     * Returns the date or timestamp converted to a timestamp in milliseconds.
1077
     *
1078
     * @param timeStr Date or timestamp string
1079
     * @param zoneId Time zone to use or null to use default time zone (UTC)
1080
     * @return Timestamp
1081
     * @throws DateTimeParseException if the time cannot be parsed
1082
     */
1083
    public static double parseDateTimeOrTimestamp(String timeStr, ZoneId zoneId) throws DateTimeParseException {
1084
        return FormattingAndParsingUtils.parseDateTimeOrTimestamp(timeStr, zoneId);
1✔
1085
    }
1086

1087
    /**
1088
     * Parses an ISO date with or without time or a timestamp (in milliseconds).
1089
     * Returns the date or timestamp converted to a timestamp in milliseconds.
1090
     * Default time zone is used (UTC).
1091
     *
1092
     * @param timeStr Date or timestamp string
1093
     * @return Timestamp
1094
     * @throws DateTimeParseException if the time cannot be parsed
1095
     */
1096
    public static double parseDateTimeOrTimestamp(String timeStr) throws DateTimeParseException {
1097
        return FormattingAndParsingUtils.parseDateTimeOrTimestamp(timeStr);
1✔
1098
    }
1099

1100
    /**
1101
     * Returns the string representation of the given timestamp.
1102
     *
1103
     * @param timestamp the time, in milliseconds
1104
     * @return formatted timestamp
1105
     */
1106
    public static String printTimestamp(double timestamp) {
1107
        return TIMESTAMP_PRINTER.format(timestamp);
1✔
1108
    }
1109

1110
    /**
1111
     * Returns the date's string representation of the given timestamp.
1112
     *
1113
     * @param timestamp time, in milliseconds
1114
     * @param zoneId time zone to use or null to use default time zone (UTC)
1115
     * @return formatted date
1116
     */
1117
    public static String printDate(double timestamp, ZoneId zoneId) {
1118
        if (Double.isInfinite(timestamp) || Double.isNaN(timestamp)) {
1✔
1119
            return printTimestamp(timestamp);
1✔
1120
        }
1121
        return printDate(Instant.ofEpochMilli((long) timestamp), zoneId);
1✔
1122
    }
1123

1124
    /**
1125
     * Returns the date's string representation of the given instant.
1126
     *
1127
     * @param instant instant to format
1128
     * @param zoneId time zone to use or null to use default time zone (UTC)
1129
     * @return formatted date
1130
     */
1131
    public static String printDate(Instant instant, ZoneId zoneId) {
1132
        DateTimeFormatter datePrinterByTimeZone = getDatePrinterByTimeZone(zoneId);
1✔
1133
        ZonedDateTime zonedDateTime = instant.atZone(datePrinterByTimeZone.getZone());
1✔
1134
        return zonedDateTime.format(datePrinterByTimeZone);
1✔
1135
    }
1136

1137
    /**
1138
     * Returns the date's string representation of the given timestamp. Default time
1139
     * zone is used (UTC).
1140
     *
1141
     * @param timestamp time, in milliseconds
1142
     * @return formatted date
1143
     */
1144
    public static String printDate(double timestamp) {
1145
        return printDate(timestamp, null);
1✔
1146
    }
1147

1148
    /**
1149
     * Returns the time's string representation of the given timestamp.
1150
     *
1151
     * @param timestamp time, in milliseconds
1152
     * @param zoneId time zone to use or null to use default time zone (UTC)
1153
     * @return formatted time
1154
     */
1155
    public static String printDateTime(double timestamp, ZoneId zoneId) {
1156
        if (Double.isInfinite(timestamp) || Double.isNaN(timestamp)) {
1✔
1157
            return printTimestamp(timestamp);
1✔
1158
        }
1159
        return printDateTime(Instant.ofEpochMilli((long) timestamp), zoneId);
1✔
1160
    }
1161

1162
    /**
1163
     * Returns the time's string representation of the given instant.
1164
     *
1165
     * @param instant instant to format
1166
     * @param zoneId time zone to use or null to use default time zone (UTC)
1167
     * @return formatted time
1168
     */
1169
    public static String printDateTime(Instant instant, ZoneId zoneId) {
1170
        DateTimeFormatter dateTimePrinterByTimeZone = getDateTimePrinterByTimeZone(zoneId);
1✔
1171
        ZonedDateTime zonedDateTime2 = instant.atZone(dateTimePrinterByTimeZone.getZone());
1✔
1172
        OffsetDateTime time = OffsetDateTime.from(zonedDateTime2);
1✔
1173
        return time.format(dateTimePrinterByTimeZone);
1✔
1174
    }
1175

1176
    /**
1177
     * Returns the time's string representation of the given timestamp. Default time
1178
     * zone is used (UTC).
1179
     *
1180
     * @param timestamp time, in milliseconds
1181
     * @return formatted time
1182
     */
1183
    public static String printDateTime(double timestamp) {
1184
        return printDateTime(timestamp, null);
1✔
1185
    }
1186

1187
    /**
1188
     * Returns the string representation of the given timestamp in the given format.
1189
     *
1190
     * @param timestamp time, in milliseconds
1191
     * @param timeFormat time format
1192
     * @param zoneId time zone to use or null to use default time zone (UTC).
1193
     * @return formatted timestamp
1194
     */
1195
    public static String printTimestampInFormat(double timestamp, TimeFormat timeFormat, ZoneId zoneId) {
1196
        switch (timeFormat) {
1✔
1197
            case DATE:
1198
                return AttributeUtils.printDate(timestamp, zoneId);
1✔
1199
            case DATETIME:
1200
                return AttributeUtils.printDateTime(timestamp, zoneId);
1✔
1201
            case DOUBLE:
1202
                return AttributeUtils.printTimestamp(timestamp);
1✔
1203
        }
1204

1205
        throw new UnsupportedOperationException("Unknown TimeFormat");
×
1206
    }
1207

1208
    /**
1209
     * Returns the string representation of the given timestamp in the given format.
1210
     * Default time zone is used (UTC).
1211
     *
1212
     * @param timestamp time, in milliseconds
1213
     * @param timeFormat time format
1214
     * @return formatted timestamp
1215
     */
1216
    public static String printTimestampInFormat(double timestamp, TimeFormat timeFormat) {
1217
        return printTimestampInFormat(timestamp, timeFormat, null);
×
1218
    }
1219

1220
    /**
1221
     * Returns the string representation of the given array. The used format is the
1222
     * same format supported by {@link #parse(java.lang.String, java.lang.Class)}
1223
     * method
1224
     *
1225
     * @param arr Input array. Can be an array of objects or primitives.
1226
     * @return formatted array
1227
     */
1228
    public static String printArray(Object arr) {
1229
        return FormattingAndParsingUtils.printArray(arr);
1✔
1230
    }
1231

1232
    /**
1233
     * Returns true if the given column is a node column.
1234
     *
1235
     * @param colum column to test
1236
     * @return true if the column is a node column, false otherwise
1237
     */
1238
    public static boolean isNodeColumn(Column colum) {
1239
        return colum.getTable().getElementClass().equals(Node.class);
1✔
1240
    }
1241

1242
    /**
1243
     * Returns true if the given column is an edge column.
1244
     *
1245
     * @param colum column to test
1246
     * @return true if the column is an edge column, false otherwise
1247
     */
1248
    public static boolean isEdgeColumn(Column colum) {
1249
        return colum.getTable().getElementClass().equals(Edge.class);
1✔
1250
    }
1251

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

1272
        // Primitive
1273
        if (isSimpleType(typeClass)) {
1✔
1274
            return obj;
1✔
1275
        }
1276

1277
        // Instant
1278
        if (typeClass.equals(Instant.class)) {
1✔
1279
            return obj;
1✔
1280
        }
1281

1282
        // Interval types:
1283
        if (typeClass.equals(IntervalSet.class)) {
1✔
1284
            return new IntervalSet((IntervalSet) obj);
1✔
1285
        } else if (typeClass.equals(IntervalStringMap.class)) {
1✔
1286
            return new IntervalStringMap((IntervalStringMap) obj);
1✔
1287
        } else if (typeClass.equals(IntervalByteMap.class)) {
1✔
1288
            return new IntervalByteMap((IntervalByteMap) obj);
1✔
1289
        } else if (typeClass.equals(IntervalShortMap.class)) {
1✔
1290
            return new IntervalShortMap((IntervalShortMap) obj);
1✔
1291
        } else if (typeClass.equals(IntervalIntegerMap.class)) {
1✔
1292
            return new IntervalIntegerMap((IntervalIntegerMap) obj);
1✔
1293
        } else if (typeClass.equals(IntervalLongMap.class)) {
1✔
1294
            return new IntervalLongMap((IntervalLongMap) obj);
1✔
1295
        } else if (typeClass.equals(IntervalFloatMap.class)) {
1✔
1296
            return new IntervalFloatMap((IntervalFloatMap) obj);
1✔
1297
        } else if (typeClass.equals(IntervalDoubleMap.class)) {
1✔
1298
            return new IntervalDoubleMap((IntervalDoubleMap) obj);
1✔
1299
        } else if (typeClass.equals(IntervalBooleanMap.class)) {
1✔
1300
            return new IntervalBooleanMap((IntervalBooleanMap) obj);
1✔
1301
        } else if (typeClass.equals(IntervalCharMap.class)) {
1✔
1302
            return new IntervalCharMap((IntervalCharMap) obj);
1✔
1303
        }
1304

1305
        // Timestamp types:
1306
        if (typeClass.equals(TimestampSet.class)) {
1✔
1307
            return new TimestampSet((TimestampSet) obj);
1✔
1308
        } else if (typeClass.equals(TimestampStringMap.class)) {
1✔
1309
            return new TimestampStringMap((TimestampStringMap) obj);
1✔
1310
        } else if (typeClass.equals(TimestampByteMap.class)) {
1✔
1311
            return new TimestampByteMap((TimestampByteMap) obj);
1✔
1312
        } else if (typeClass.equals(TimestampShortMap.class)) {
1✔
1313
            return new TimestampShortMap((TimestampShortMap) obj);
1✔
1314
        } else if (typeClass.equals(TimestampIntegerMap.class)) {
1✔
1315
            return new TimestampIntegerMap((TimestampIntegerMap) obj);
1✔
1316
        } else if (typeClass.equals(TimestampLongMap.class)) {
1✔
1317
            return new TimestampLongMap((TimestampLongMap) obj);
1✔
1318
        } else if (typeClass.equals(TimestampFloatMap.class)) {
1✔
1319
            return new TimestampFloatMap((TimestampFloatMap) obj);
1✔
1320
        } else if (typeClass.equals(TimestampDoubleMap.class)) {
1✔
1321
            return new TimestampDoubleMap((TimestampDoubleMap) obj);
1✔
1322
        } else if (typeClass.equals(TimestampBooleanMap.class)) {
1✔
1323
            return new TimestampBooleanMap((TimestampBooleanMap) obj);
1✔
1324
        } else if (typeClass.equals(TimestampCharMap.class)) {
1✔
1325
            return new TimestampCharMap((TimestampCharMap) obj);
1✔
1326
        }
1327

1328
        // Array
1329
        if (isArrayType(typeClass)) {
1✔
1330
            Class componentType = typeClass.getComponentType();
1✔
1331
            int length = Array.getLength(obj);
1✔
1332
            Object dest = Array.newInstance(componentType, length);
1✔
1333
            System.arraycopy(obj, 0, dest, 0, length);
1✔
1334
            return dest;
1✔
1335
        }
1336

1337
        // List
1338
        if (obj instanceof CharArrayList) {
1✔
1339
            return new CharArrayList((CharArrayList) obj);
×
1340
        } else if (obj instanceof BooleanArrayList) {
1✔
1341
            return new BooleanArrayList((BooleanArrayList) obj);
×
1342
        } else if (obj instanceof ByteArrayList) {
1✔
1343
            return new ByteArrayList((ByteArrayList) obj);
×
1344
        } else if (obj instanceof ShortArrayList) {
1✔
1345
            return new ShortArrayList((ShortArrayList) obj);
×
1346
        } else if (obj instanceof IntArrayList) {
1✔
1347
            return new IntArrayList((IntArrayList) obj);
×
1348
        } else if (obj instanceof LongArrayList) {
1✔
1349
            return new LongArrayList((LongArrayList) obj);
×
1350
        } else if (obj instanceof FloatArrayList) {
1✔
1351
            return new FloatArrayList((FloatArrayList) obj);
×
1352
        } else if (obj instanceof DoubleArrayList) {
1✔
1353
            return new DoubleArrayList((DoubleArrayList) obj);
×
1354
        } else if (obj instanceof ObjectArrayList) {
1✔
1355
            return new ObjectArrayList((ObjectArrayList) obj);
1✔
1356
        }
1357

1358
        // Map
1359
        if (obj instanceof Char2ObjectOpenHashMap) {
1✔
1360
            return new Char2ObjectOpenHashMap((Char2ObjectOpenHashMap) obj);
×
1361
        } else if (obj instanceof Byte2ObjectOpenHashMap) {
1✔
1362
            return new Byte2ObjectOpenHashMap((Byte2ObjectOpenHashMap) obj);
×
1363
        } else if (obj instanceof Short2ObjectOpenHashMap) {
1✔
1364
            return new Short2ObjectOpenHashMap((Short2ObjectOpenHashMap) obj);
×
1365
        } else if (obj instanceof Int2ObjectOpenHashMap) {
1✔
1366
            return new Int2ObjectOpenHashMap((Int2ObjectOpenHashMap) obj);
×
1367
        } else if (obj instanceof Long2ObjectOpenHashMap) {
1✔
1368
            return new Long2ObjectOpenHashMap((Long2ObjectOpenHashMap) obj);
×
1369
        } else if (obj instanceof Float2ObjectOpenHashMap) {
1✔
1370
            return new Float2ObjectOpenHashMap((Float2ObjectOpenHashMap) obj);
×
1371
        } else if (obj instanceof Double2ObjectOpenHashMap) {
1✔
1372
            return new Double2ObjectOpenHashMap((Double2ObjectOpenHashMap) obj);
×
1373
        } else if (obj instanceof Object2ObjectOpenHashMap) {
1✔
1374
            return new Object2ObjectOpenHashMap((Object2ObjectOpenHashMap) obj);
1✔
1375
        }
1376

1377
        // Set
1378
        if (obj instanceof CharOpenHashSet) {
1✔
1379
            return new CharOpenHashSet((CharOpenHashSet) obj);
×
1380
        } else if (obj instanceof BooleanOpenHashSet) {
1✔
1381
            return new BooleanOpenHashSet((BooleanOpenHashSet) obj);
×
1382
        } else if (obj instanceof ByteOpenHashSet) {
1✔
1383
            return new ByteOpenHashSet((ByteOpenHashSet) obj);
×
1384
        } else if (obj instanceof ShortOpenHashSet) {
1✔
1385
            return new ShortOpenHashSet((ShortOpenHashSet) obj);
×
1386
        } else if (obj instanceof IntOpenHashSet) {
1✔
1387
            return new IntOpenHashSet((IntOpenHashSet) obj);
×
1388
        } else if (obj instanceof LongOpenHashSet) {
1✔
1389
            return new LongOpenHashSet((LongOpenHashSet) obj);
×
1390
        } else if (obj instanceof FloatOpenHashSet) {
1✔
1391
            return new FloatOpenHashSet((FloatOpenHashSet) obj);
×
1392
        } else if (obj instanceof DoubleOpenHashSet) {
1✔
1393
            return new DoubleOpenHashSet((DoubleOpenHashSet) obj);
×
1394
        } else if (obj instanceof ObjectOpenHashSet) {
1✔
1395
            return new ObjectOpenHashSet((ObjectOpenHashSet) obj);
1✔
1396
        }
1397

1398
        return obj;
×
1399
    }
1400
}
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