• 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

93.68
/src/main/java/org/gephi/graph/impl/FormattingAndParsingUtils.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
package org.gephi.graph.impl;
17

18
import java.io.IOException;
19
import java.io.StringReader;
20
import java.lang.reflect.Array;
21
import java.math.BigDecimal;
22
import java.math.BigInteger;
23
import java.time.ZoneId;
24
import java.time.format.DateTimeParseException;
25
import org.gephi.graph.api.AttributeUtils;
26

27
/**
28
 * Utils for formatting and parsing special data types (dynamic intervals,
29
 * timestamps and arrays).
30
 *
31
 * @author Eduardo Ramos
32
 */
33
public final class FormattingAndParsingUtils {
×
34

35
    // Bounds
36
    public static final char DYNAMIC_TYPE_LEFT_BOUND = '<';
37
    public static final char DYNAMIC_TYPE_RIGHT_BOUND = '>';
38
    public static final char LEFT_BOUND_BRACKET = '(';
39
    public static final char LEFT_BOUND_SQUARE_BRACKET = '[';
40
    public static final char RIGHT_BOUND_BRACKET = ')';
41
    public static final char RIGHT_BOUND_SQUARE_BRACKET = ']';
42
    public static final char COMMA = ',';
43

44
    public static final String EMPTY_VALUE = "<empty>";
45
    public static final String INFINITY = "Infinity";
46

47
    /**
48
     * Parses an ISO date with or without time or a timestamp (in milliseconds).
49
     * Returns the date or timestamp converted to a timestamp in milliseconds.
50
     *
51
     * @param timeStr Date or timestamp string
52
     * @param zoneId Time zone to use or null to use default time zone (UTC)
53
     * @return Timestamp
54
     * @throws DateTimeParseException if the time cannot be parsed
55
     */
56
    public static double parseDateTimeOrTimestamp(String timeStr, ZoneId zoneId) throws DateTimeParseException {
57
        double value;
58
        try {
59
            // Try first to parse as a single double:
60
            value = Double.parseDouble(infinityIgnoreCase(timeStr));
1✔
61
            if (Double.isNaN(value)) {
1✔
62
                throw new IllegalArgumentException("NaN is not allowed as an interval bound");
×
63
            }
64
        } catch (NumberFormatException ex) {
1✔
65
            value = AttributeUtils.parseDateTime(timeStr, zoneId);
1✔
66
        }
1✔
67

68
        return value;
1✔
69
    }
70

71
    /**
72
     * Parses an ISO date with or without time or a timestamp (in milliseconds).
73
     * Returns the date or timestamp converted to a timestamp in milliseconds.
74
     * Default time zone is used (UTC).
75
     *
76
     * @param timeStr Date or timestamp string
77
     * @return Timestamp
78
     * @throws DateTimeParseException if the time cannot be parsed
79
     */
80
    public static double parseDateTimeOrTimestamp(String timeStr) throws DateTimeParseException {
81
        return parseDateTimeOrTimestamp(timeStr, null);
1✔
82
    }
83

84
    /**
85
     * Parse literal value until detecting the end of it (quote can be ' or ")
86
     *
87
     * @param reader Input reader
88
     * @param quote Quote mode that started this literal (' or ")
89
     * @return Parsed value
90
     * @throws IOException Unexpected read error
91
     */
92
    protected static String parseLiteral(StringReader reader, char quote) throws IOException {
93
        StringBuilder sb = new StringBuilder();
1✔
94
        boolean escapeEnabled = false;
1✔
95

96
        int r;
97
        char c;
98
        while ((r = reader.read()) != -1) {
1✔
99
            c = (char) r;
1✔
100
            if (c == quote) {
1✔
101
                if (escapeEnabled) {
1✔
102
                    sb.append(quote);
1✔
103
                    escapeEnabled = false;
1✔
104
                } else {
105
                    return sb.toString();
1✔
106
                }
107
            } else {
108
                switch (c) {
1✔
109
                    case '\\':
110
                        if (escapeEnabled) {
1✔
111
                            sb.append('\\');
×
112

113
                            escapeEnabled = false;
×
114
                        } else {
115
                            escapeEnabled = true;
1✔
116
                        }
117
                        break;
1✔
118
                    default:
119
                        if (escapeEnabled) {
1✔
120
                            escapeEnabled = false;
1✔
121
                        }
122
                        sb.append(c);
1✔
123
                }
124
            }
125
        }
126

127
        return sb.toString();
×
128
    }
129

130
    /**
131
     * Parses a value until end is detected either by a comma or a bounds closing
132
     * character.
133
     *
134
     * @param reader Input reader
135
     * @return Parsed value
136
     * @throws IOException Unexpected read error
137
     */
138
    protected static String parseValue(StringReader reader) throws IOException {
139
        StringBuilder sb = new StringBuilder();
1✔
140
        int r;
141
        char c;
142
        while ((r = reader.read()) != -1) {
1✔
143
            c = (char) r;
1✔
144
            switch (c) {
1✔
145
                case RIGHT_BOUND_BRACKET:
146
                case RIGHT_BOUND_SQUARE_BRACKET:
147
                    reader.skip(-1);// Go backwards 1 position, for detecting
1✔
148
                                    // end of bounds
149
                case COMMA:
150
                    return sb.toString().trim();
1✔
151
                default:
152
                    sb.append(c);
1✔
153
            }
154
        }
155

156
        return sb.toString().trim();
1✔
157
    }
158

159
    /**
160
     * Converts a string parsed with {@link #parseValue(java.io.StringReader)} to
161
     * the target type, taking into account dynamic parsing quirks such as numbers
162
     * with/without decimals and infinity values.
163
     *
164
     * @param <T> Target type
165
     * @param typeClass Target type class
166
     * @param valString String to parse
167
     * @return Converted value
168
     */
169
    protected static <T> T convertValue(Class<T> typeClass, String valString) {
170
        Object value;
171
        if (typeClass.equals(String.class)) {
1✔
172
            value = valString;
1✔
173
        } else if (typeClass.equals(Byte.class) || typeClass.equals(byte.class) || typeClass
1✔
174
                .equals(Short.class) || typeClass.equals(short.class) || typeClass.equals(Integer.class) || typeClass
1✔
175
                        .equals(int.class) || typeClass.equals(Long.class) || typeClass
1✔
176
                                .equals(long.class) || typeClass.equals(BigInteger.class)) {
1✔
177
            value = parseNumberWithoutDecimals((Class<? extends Number>) typeClass, valString);
1✔
178
        } else if (typeClass.equals(Float.class) || typeClass.equals(float.class) || typeClass
1✔
179
                .equals(Double.class) || typeClass.equals(double.class) || typeClass.equals(BigDecimal.class)) {
1✔
180
            value = parseNumberWithDecimals((Class<? extends Number>) typeClass, valString);
1✔
181
        } else {
182
            value = AttributeUtils.parse(valString, typeClass);
1✔
183
        }
184

185
        return (T) value;
1✔
186
    }
187

188
    /**
189
     * Method for allowing inputs such as "infinity" when parsing decimal numbers
190
     *
191
     * @param value Input String
192
     * @return Input String with fixed "Infinity" syntax if necessary.
193
     */
194
    private static String infinityIgnoreCase(String value) {
195
        value = value.trim();
1✔
196
        if (value.equalsIgnoreCase(INFINITY)) {
1✔
197
            return INFINITY;
1✔
198
        }
199
        if (value.equalsIgnoreCase("-" + INFINITY)) {
1✔
200
            return "-" + INFINITY;
1✔
201
        }
202

203
        return value;
1✔
204
    }
205

206
    private static <T extends Number> T parseNumberWithoutDecimals(Class<T> typeClass, String valString) {
207
        valString = removeDecimalDigitsFromString(valString);
1✔
208

209
        return (T) AttributeUtils.parse(valString, typeClass);
1✔
210
    }
211

212
    private static <T extends Number> T parseNumberWithDecimals(Class<T> typeClass, String valString) {
213
        valString = infinityIgnoreCase(valString);
1✔
214

215
        return (T) AttributeUtils.parse(valString, typeClass);
1✔
216
    }
217

218
    /**
219
     * Removes anything after the dot of decimal numbers in a string when necessary.
220
     * Used for trying to parse decimal numbers as not decimal. For example
221
     * BigDecimal to BigInteger.
222
     *
223
     * @param s String to remove decimal digits
224
     * @return String without dot and decimal digits.
225
     */
226
    private static String removeDecimalDigitsFromString(String s) {
227
        int firstDotIndex = s.indexOf('.');
1✔
228
        if (firstDotIndex > 0) {
1✔
229
            return s.substring(0, firstDotIndex);
1✔
230
        } else {
231
            return s;
1✔
232
        }
233
    }
234

235
    private static final char[] DYNAMIC_SPECIAL_CHARACTERS = " ;,()[]\"'".toCharArray();
1✔
236

237
    /**
238
     * @param value String value
239
     * @return True if the string contains special characters for dynamic types
240
     *         intervals syntax
241
     */
242
    public static boolean containsDynamicSpecialCharacters(String value) {
243
        for (char c : DYNAMIC_SPECIAL_CHARACTERS) {
1✔
244
            if (value.indexOf(c) != -1) {
1✔
245
                return true;
1✔
246
            }
247
        }
248
        return false;
1✔
249
    }
250

251
    public static <T> String printArray(Object arr) {
252
        if (arr == null) {
1✔
UNCOV
253
            return null;
×
254
        }
255

256
        int size = Array.getLength(arr);
1✔
257
        if (size == 0) {
1✔
258
            return FormattingAndParsingUtils.EMPTY_VALUE;
1✔
259
        }
260

261
        StringBuilder sb = new StringBuilder();
1✔
262
        sb.append('[');
1✔
263
        for (int i = 0; i < size; i++) {
1✔
264
            Object value = Array.get(arr, i);
1✔
265
            if (value != null) {
1✔
266
                String stringValue = value.toString();
1✔
267
                if (stringValue.equals("null") || containsArraySpecialCharacters(stringValue) || stringValue.trim()
1✔
268
                        .isEmpty()) {
1✔
269
                    sb.append('"');
1✔
270
                    sb.append(stringValue.replace("\\", "\\\\").replace("\"", "\\\""));
1✔
271
                    sb.append('"');
1✔
272
                } else {
273
                    sb.append(stringValue);
1✔
274
                }
275
            } else {
1✔
276
                sb.append("null");
1✔
277
            }
278

279
            if (i < size - 1) {
1✔
280
                sb.append(", ");
1✔
281
            }
282
        }
283
        sb.append(']');
1✔
284

285
        return sb.toString();
1✔
286
    }
287

288
    private static final char[] ARRAY_SPECIAL_CHARACTERS = " ,[]\"'".toCharArray();
1✔
289

290
    /**
291
     * @param value String value
292
     * @return True if the string contains special characters for arrays intervals
293
     *         syntax
294
     */
295
    private static boolean containsArraySpecialCharacters(String value) {
296
        for (char c : ARRAY_SPECIAL_CHARACTERS) {
1✔
297
            if (value.indexOf(c) != -1) {
1✔
298
                return true;
1✔
299
            }
300
        }
301
        return false;
1✔
302
    }
303
}
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