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

jreleaser / jreleaser / #556

22 Nov 2025 04:17PM UTC coverage: 46.213% (-2.0%) from 48.203%
#556

push

github

aalmiray
feat(jdks): Allow filtering by platform

Closes #2000

Co-authored-by: Ixchel Ruiz <ixchelruiz@yahoo.com>

0 of 42 new or added lines in 5 files covered. (0.0%)

1116 existing lines in 107 files now uncovered.

24939 of 53965 relevant lines covered (46.21%)

0.46 hits per line

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

67.47
/api/jreleaser-utils/src/main/java/org/jreleaser/util/StringUtils.java
1
/*
2
 * SPDX-License-Identifier: Apache-2.0
3
 *
4
 * Copyright 2020-2025 The JReleaser authors.
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     https://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
package org.jreleaser.util;
19

20
import java.io.File;
21
import java.lang.reflect.Method;
22
import java.util.ArrayList;
23
import java.util.Arrays;
24
import java.util.Collection;
25
import java.util.Iterator;
26
import java.util.List;
27
import java.util.Locale;
28
import java.util.Objects;
29
import java.util.regex.Pattern;
30
import java.util.stream.Stream;
31

32
import static java.lang.System.lineSeparator;
33
import static java.util.stream.Collectors.joining;
34

35
/**
36
 * @author Andres Almiray
37
 * @since 0.1.0
38
 */
39
public final class StringUtils {
40
    private static final String PROPERTY_SET_PREFIX = "set";
41
    private static final String PROPERTY_GET_PREFIX = "get";
42
    private static final Pattern GETTER_PATTERN_1 = Pattern.compile("^get[A-Z][\\w]*$");
1✔
43
    private static final Pattern GETTER_PATTERN_2 = Pattern.compile("^is[A-Z][\\w]*$");
1✔
44
    private static final Pattern SETTER_PATTERN = Pattern.compile("^set[A-Z][\\w]*$");
1✔
45
    private static final String ERROR_METHOD_NULL = "Argument 'method' must not be null";
46
    private static final Pattern REGEX_CHARS = Pattern.compile("[{}()\\[\\].+*?^$\\\\|/]");
1✔
47

48
    private StringUtils() {
49
        // noop
50
    }
51

52
    /**
53
     * Capitalizes a String (makes the first char uppercase) taking care
54
     * of blank strings and single character strings.
55
     *
56
     * @param str The String to be capitalized
57
     * @return Capitalized version of the target string if it is not blank
58
     */
59
    public static String capitalize(String str) {
60
        if (isBlank(str)) {
1✔
61
            return str;
1✔
62
        }
63

64
        if (str.length() == 1) {
1✔
65
            return str.toUpperCase(Locale.ENGLISH);
1✔
66
        }
67

68
        return str.substring(0, 1).toUpperCase(Locale.ENGLISH) + str.substring(1);
1✔
69
    }
70

71
    public static String getFilenameExtension(String path) {
72
        if (null == path) {
1✔
73
            return null;
×
74
        }
75

76
        int extIndex = path.lastIndexOf(".");
1✔
77
        if (extIndex == -1) {
1✔
78
            return null;
×
79
        }
80

81
        int folderIndex = path.lastIndexOf(File.separator);
1✔
82
        if (folderIndex > extIndex) {
1✔
83
            return null;
×
84
        }
85

86
        return path.substring(extIndex + 1);
1✔
87
    }
88

89
    public static String getFilename(String path) {
90
        if (null == path) {
1✔
91
            return null;
×
92
        }
93

94
        int extIndex = path.lastIndexOf(".");
1✔
95
        if (extIndex == -1) {
1✔
96
            return null;
×
97
        }
98

99
        int folderIndex = path.lastIndexOf(File.separator);
1✔
100
        if (folderIndex > extIndex) {
1✔
101
            return null;
×
102
        }
103

104
        folderIndex = folderIndex < 0 ? 0 : folderIndex;
1✔
105

106
        return path.substring(folderIndex, extIndex);
1✔
107
    }
108

109
    public static String getFilename(String path, Collection<String> extensions) {
110
        for (String extension : extensions) {
1✔
111
            extension = extension.startsWith(".") ? extension : "." + extension;
1✔
112
            if (path.endsWith(extension)) {
1✔
113
                return path.substring(0, path.length() - extension.length());
1✔
114
            }
115
        }
1✔
116

117
        return path;
1✔
118
    }
119

120
    /**
121
     * Retrieves the name of a setter for the specified property name
122
     *
123
     * @param propertyName The property name
124
     * @return The setter equivalent
125
     */
126
    public static String getSetterName(String propertyName) {
127
        return PROPERTY_SET_PREFIX + capitalize(propertyName);
1✔
128
    }
129

130
    /**
131
     * Calculate the name for a getter method to retrieve the specified property
132
     *
133
     * @param propertyName The property name
134
     * @return The name for the getter method for this property, if it were to exist, i.e. getConstraints
135
     */
136
    public static String getGetterName(String propertyName) {
137
        return PROPERTY_GET_PREFIX + capitalize(propertyName);
1✔
138
    }
139

140
    /**
141
     * Returns the class name for the given logical name and trailing name. For example "person" and "Controller" would evaluate to "PersonController"
142
     *
143
     * @param logicalName  The logical name
144
     * @param trailingName The trailing name
145
     * @return The class name
146
     */
147
    public static String getClassName(String logicalName, String trailingName) {
148
        if (isBlank(logicalName)) {
1✔
149
            throw new IllegalArgumentException("Argument [logicalName] must not be null or blank");
×
150
        }
151

152

153
        String className = capitalize(logicalName);
1✔
154
        if (null != trailingName) {
1✔
155
            className = className + trailingName;
1✔
156
        }
157

158
        return className;
1✔
159
    }
160

161
    /**
162
     * Returns the class name representation of the given name
163
     *
164
     * @param name The name to convert
165
     * @return The property name representation
166
     */
167
    public static String getClassNameRepresentation(String name) {
168
        StringBuilder buf = new StringBuilder();
1✔
169
        if (null != name && name.length() > 0) {
1✔
170
            String[] tokens = name.split("[^\\w\\d]");
1✔
171
            for (String token1 : tokens) {
1✔
172
                String token = token1.trim();
1✔
173
                buf.append(capitalize(token));
1✔
174
            }
175
        }
176

177
        return buf.toString();
1✔
178
    }
179

180
    /**
181
     * Converts foo-bar into FooBar. Empty and null strings are returned
182
     * as-is.
183
     *
184
     * @param name The lower case hyphen separated name
185
     * @return The class name equivalent.
186
     */
187
    public static String getClassNameForLowerCaseHyphenSeparatedName(String name) {
188
        // Handle null and empty strings.
189
        if (isBlank(name)) {
1✔
190
            return name;
×
191
        }
192

193
        if (name.contains("-")) {
1✔
194
            StringBuilder buf = new StringBuilder();
1✔
195
            String[] tokens = name.split("-");
1✔
196
            for (String token : tokens) {
1✔
197
                if (null == token || token.length() == 0) {
1✔
198
                    continue;
×
199
                }
200

201
                buf.append(capitalize(token));
1✔
202
            }
203

204
            return buf.toString();
1✔
205
        }
206

207
        return capitalize(name);
1✔
208
    }
209

210
    /**
211
     * Converts foo-bar into Foo Bar. Empty and null strings are returned
212
     * as-is.
213
     *
214
     * @param name The lower case hyphen separated name
215
     * @return The capitalized name equivalent.
216
     */
217
    public static String getCapitalizedName(String name) {
218
        // Handle null and empty strings.
219
        if (isBlank(name)) {
1✔
220
            return name;
×
221
        }
222

223
        if (name.contains("-")) {
1✔
UNCOV
224
            StringBuilder buf = new StringBuilder();
×
UNCOV
225
            String[] tokens = name.split("-");
×
UNCOV
226
            for (String token : tokens) {
×
UNCOV
227
                if (null == token || token.length() == 0) {
×
228
                    continue;
×
229
                }
UNCOV
230
                if (buf.length() > 0) {
×
UNCOV
231
                    buf.append(' ');
×
232
                }
UNCOV
233
                buf.append(capitalize(token));
×
234
            }
235

UNCOV
236
            return buf.toString();
×
237
        }
238

239
        return capitalize(name);
1✔
240
    }
241

242
    /**
243
     * Retrieves the logical class name of a Griffon artifact given the Griffon class
244
     * and a specified trailing name
245
     *
246
     * @param clazz        The class
247
     * @param trailingName The trailing name such as "Controller" or "TagLib"
248
     * @return The logical class name
249
     */
250
    public static String getLogicalName(Class<?> clazz, String trailingName) {
251
        return getLogicalName(clazz.getName(), trailingName);
×
252
    }
253

254
    /**
255
     * Retrieves the logical name of the class without the trailing name
256
     *
257
     * @param name         The name of the class
258
     * @param trailingName The trailing name
259
     * @return The logical name
260
     */
261
    public static String getLogicalName(String name, String trailingName) {
262
        if (isNotBlank(name) && isNotBlank(trailingName)) {
1✔
263
            String shortName = getShortName(name);
1✔
264
            if (shortName.endsWith(trailingName)) {
1✔
265
                return shortName.substring(0, shortName.length() - trailingName.length());
1✔
266
            }
267
        }
268

269
        return name;
×
270
    }
271

272
    public static String getLogicalPropertyName(String className, String trailingName) {
273
        if (isNotBlank(className) && isNotBlank(trailingName) && className.length() == trailingName.length() + 1 && className.endsWith(trailingName)) {
1✔
274
            return className.substring(0, 1).toLowerCase(Locale.ENGLISH);
1✔
275
        }
276

277
        return getLogicalName(getPropertyName(className), trailingName);
1✔
278
    }
279

280
    /**
281
     * Shorter version of getPropertyNameRepresentation
282
     *
283
     * @param name The name to convert
284
     * @return The property name version
285
     */
286
    public static String getPropertyName(String name) {
287
        return getPropertyNameRepresentation(name);
1✔
288
    }
289

290
    /**
291
     * Shorter version of getPropertyNameRepresentation
292
     *
293
     * @param clazz The clazz to convert
294
     * @return The property name version
295
     */
296
    public static String getPropertyName(Class<?> clazz) {
297
        return getPropertyNameRepresentation(clazz);
1✔
298
    }
299

300
    /**
301
     * Returns the property name representation of the given {@code Method}
302
     *
303
     * @param method The method to inspect
304
     * @return The property name representation
305
     * @since 3.0.0
306
     */
307
    public static String getPropertyName(Method method) {
308
        Objects.requireNonNull(method, ERROR_METHOD_NULL);
×
309
        String name = method.getName();
×
310
        if (GETTER_PATTERN_1.matcher(name).matches() || SETTER_PATTERN.matcher(name).matches()) {
×
311
            return uncapitalize(name.substring(3));
×
312
        } else if (GETTER_PATTERN_2.matcher(name).matches()) {
×
313
            return uncapitalize(name.substring(2));
×
314
        }
315

316
        return name;
×
317
    }
318

319
    /**
320
     * Returns the property name equivalent for the specified class
321
     *
322
     * @param targetClass The class to get the property name for
323
     * @return A property name representation of the class name (eg. MyClass becomes myClass)
324
     */
325
    public static String getPropertyNameRepresentation(Class<?> targetClass) {
326
        String shortName = getShortName(targetClass);
1✔
327
        return getPropertyNameRepresentation(shortName);
1✔
328
    }
329

330
    /**
331
     * Returns the property name representation of the given name
332
     *
333
     * @param name The name to convert
334
     * @return The property name representation
335
     */
336
    public static String getPropertyNameRepresentation(String name) {
337
        if (isBlank(name)) {
1✔
338
            return name;
×
339
        }
340

341
        // Strip any package from the name.
342
        int pos = name.lastIndexOf(".");
1✔
343
        if (pos != -1) {
1✔
344
            name = name.substring(pos + 1);
1✔
345
        }
346

347
        // Check whether the name begins with two upper case letters.
348
        if (name.length() > 1 && Character.isUpperCase(name.charAt(0)) && Character.isUpperCase(name.charAt(1))) {
1✔
349
            return name;
1✔
350
        }
351

352
        String propertyName = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
1✔
353
        if (propertyName.contains(" ")) {
1✔
354
            propertyName = propertyName.replaceAll("\\s", "");
1✔
355
        }
356

357
        return propertyName;
1✔
358
    }
359

360
    /**
361
     * Converts foo-bar into fooBar
362
     *
363
     * @param name The lower case hyphen separated name
364
     * @return The property name equivalent
365
     */
366
    public static String getPropertyNameForLowerCaseHyphenSeparatedName(String name) {
367
        return getPropertyName(getClassNameForLowerCaseHyphenSeparatedName(name));
1✔
368
    }
369

370
    /**
371
     * Returns the class name without the package prefix
372
     *
373
     * @param targetClass The class to get a short name for
374
     * @return The short name of the class
375
     */
376
    public static String getShortName(Class<?> targetClass) {
377
        String className = targetClass.getName();
1✔
378
        return getShortName(className);
1✔
379
    }
380

381
    /**
382
     * Returns the class name without the package prefix
383
     *
384
     * @param className The class name to get a short name for
385
     * @return The short name of the class
386
     */
387
    public static String getShortName(String className) {
388
        if (isBlank(className)) {
1✔
389
            return className;
×
390
        }
391

392
        int i = className.lastIndexOf(".");
1✔
393
        if (i > -1) {
1✔
394
            className = className.substring(i + 1);
1✔
395
        }
396

397
        return className;
1✔
398
    }
399

400
    /**
401
     * Converts a property name into its natural language equivalent eg ('firstName' becomes 'First Name')
402
     *
403
     * @param name The property name to convert
404
     * @return The converted property name
405
     */
406
    public static String getNaturalName(String name) {
407
        name = getShortName(name);
1✔
408
        if (isBlank(name)) {
1✔
409
            return name;
×
410
        }
411

412
        List<String> words = new ArrayList<>();
1✔
413
        int i = 0;
1✔
414
        char[] chars = name.toCharArray();
1✔
415
        for (char c : chars) {
1✔
416
            String w;
417
            if (i >= words.size()) {
1✔
418
                w = "";
1✔
419
                words.add(i, w);
1✔
420
            } else {
421
                w = words.get(i);
1✔
422
            }
423

424
            if (Character.isLowerCase(c) || Character.isDigit(c)) {
1✔
425
                if (Character.isLowerCase(c) && w.length() == 0) {
1✔
426
                    c = Character.toUpperCase(c);
1✔
427
                } else if (w.length() > 1 && Character.isUpperCase(w.charAt(w.length() - 1))) {
1✔
428
                    w = "";
1✔
429
                    words.add(++i, w);
1✔
430
                }
431

432
                words.set(i, w + c);
1✔
433
            } else if (Character.isUpperCase(c)) {
1✔
434
                if (i == 0 && w.length() == 0 || Character.isUpperCase(w.charAt(w.length() - 1))) {
1✔
435
                    words.set(i, w + c);
1✔
436
                } else {
437
                    words.add(++i, String.valueOf(c));
1✔
438
                }
439
            }
440
        }
441

442
        StringBuilder buf = new StringBuilder();
1✔
443
        Iterator<String> j = words.iterator();
1✔
444
        while (j.hasNext()) {
1✔
445
            String word = j.next();
1✔
446
            buf.append(word);
1✔
447
            if (j.hasNext()) {
1✔
448
                buf.append(" ");
1✔
449
            }
450
        }
1✔
451

452
        return buf.toString();
1✔
453
    }
454

455
    /**
456
     * <p>Determines whether a given string is <code>null</code>, empty,
457
     * or only contains whitespace. If it contains anything other than
458
     * whitespace then the string is not considered to be blank and the
459
     * method returns <code>false</code>.</p>
460
     *
461
     * @param str The string to test.
462
     * @return <code>   true</code> if the string is <code>null</code>, or
463
     * blank.
464
     */
465
    public static boolean isBlank(String str) {
466
        if (null == str || str.length() == 0) {
1✔
467
            return true;
1✔
468
        }
469

470
        for (char c : str.toCharArray()) {
1✔
471
            if (!Character.isWhitespace(c)) {
1✔
472
                return false;
1✔
473
            }
474
        }
475

476
        return true;
1✔
477
    }
478

479
    /**
480
     * <p>Determines whether a given string is not <code>null</code>, empty,
481
     * or only contains whitespace. If it contains anything other than
482
     * whitespace then the string is not considered to be blank and the
483
     * method returns <code>true</code>.</p>
484
     *
485
     * @param str The string to test.
486
     * @return <code>   true</code> if the string is not <code>null</code>, nor
487
     * blank.
488
     */
489
    public static boolean isNotBlank(String str) {
490
        return !isBlank(str);
1✔
491
    }
492

493
    /**
494
     * Checks that the specified String is not {@code blank}. This
495
     * method is designed primarily for doing parameter validation in methods
496
     * and constructors, as demonstrated below:
497
     * <blockquote><pre>
498
     *  Foo(String str) {*     this.str = GriffonNameUtils.requireNonBlank(str)
499
     * }* </pre></blockquote>
500
     *
501
     * @param str the String to check for blank
502
     * @return {@code str} if not {@code blank}
503
     * @throws IllegalArgumentException if {@code str} is {@code blank}
504
     */
505
    public static String requireNonBlank(String str) {
506
        if (isBlank(str)) {
×
507
            throw new IllegalArgumentException();
×
508
        }
509

510
        return str;
×
511
    }
512

513
    /**
514
     * Checks that the specified String is not {@code blank} and
515
     * throws a customized {@link IllegalArgumentException} if it is. This method
516
     * is designed primarily for doing parameter validation in methods and
517
     * constructors with multiple parameters, as demonstrated below:
518
     * <blockquote><pre>
519
     *  Foo(String str) {*     this.str = GriffonNameUtils.requireNonBlank(str, "str must not be null")
520
     * }* </pre></blockquote>
521
     *
522
     * @param str     the String to check for blank
523
     * @param message detail message to be used in the event that a {@code
524
     *                IllegalArgumentException} is thrown
525
     * @return {@code str} if not {@code blank}
526
     * @throws IllegalArgumentException if {@code str} is {@code blank}
527
     */
528
    public static String requireNonBlank(String str, String message) {
529
        if (isBlank(str)) {
1✔
530
            throw new IllegalArgumentException(message);
×
531
        }
532

533
        return str;
1✔
534
    }
535

536
    /**
537
     * Retrieves the hyphenated name representation of the supplied class. For example
538
     * MyFunkyGriffonThingy would be my-funky-griffon-thingy.
539
     *
540
     * @param clazz The class to convert
541
     * @return The hyphenated name representation
542
     */
543
    public static String getHyphenatedName(Class<?> clazz) {
544
        if (null == clazz) {
1✔
545
            return null;
×
546
        }
547

548
        return getHyphenatedName(clazz.getName());
1✔
549
    }
550

551
    /**
552
     * Retrieves the hyphenated name representation of the given class name.
553
     * For example MyFunkyGriffonThingy would be my-funky-griffon-thingy.
554
     *
555
     * @param name The class name to convert.
556
     * @return The hyphenated name representation.
557
     */
558
    public static String getHyphenatedName(String name) {
559
        if (isBlank(name)) {
1✔
560
            return name;
×
561
        }
562

563
        if (name.endsWith(".groovy")) {
1✔
564
            name = name.substring(0, name.length() - 7);
×
565
        }
566

567
        if (name.contains("-")) return name.toLowerCase(Locale.ENGLISH);
1✔
568

569
        String naturalName = getNaturalName(getShortName(name));
1✔
570
        return naturalName.replaceAll("\\s", "-").toLowerCase(Locale.ENGLISH);
1✔
571
    }
572

573
    /**
574
     * Uncapitalizes a String (makes the first char lowercase) taking care
575
     * of blank strings and single character strings.
576
     *
577
     * @param str The String to be uncapitalized
578
     * @return Uncapitalized version of the target string if it is not blank
579
     */
580
    public static String uncapitalize(String str) {
581
        if (isBlank(str)) {
1✔
582
            return str;
1✔
583
        }
584

585
        if (str.length() == 1) {
1✔
586
            return String.valueOf(Character.toLowerCase(str.charAt(0)));
1✔
587
        }
588

589
        return Character.toLowerCase(str.charAt(0)) + str.substring(1);
1✔
590
    }
591

592
    public static Object splitValue(String value) {
593
        if (isBlank(value) || value.length() == 1) return value;
×
594
        char splitter = value.charAt(value.length() - 1);
×
595
        return Arrays.asList(value.substring(0, value.length() - 1).split(escape(splitter)));
×
596
    }
597

598
    private static String escape(char character) {
599
        switch (character) {
×
600
            case '$':
601
            case '(':
602
            case ')':
603
            case '.':
604
            case '[':
605
            case '\\':
606
            case ']':
607
            case '^':
608
            case '{':
609
            case '|':
610
            case '}':
611
                return "\\" + character;
×
612
            default:
613
                return "" + character;
×
614
        }
615
    }
616

617
    public static String padLeft(String str, int numChars) {
618
        return padLeft(str, numChars, " ");
×
619
    }
620

621
    public static String padLeft(String str, int numChars, String padding) {
622
        return numChars <= str.length() ? str : getPadding(padding, numChars - str.length()) + str;
1✔
623
    }
624

625
    public static String padRight(String str, int numChars) {
626
        return padRight(str, numChars, " ");
×
627
    }
628

629
    public static String padRight(String str, int numChars, String padding) {
630
        return numChars <= str.length() ? str : str + getPadding(padding, numChars - str.length());
×
631
    }
632

633
    private static String getPadding(String padding, int length) {
634
        return padding.length() < length ? times(padding, length / padding.length() + 1).substring(0, length) : "" + padding.subSequence(0, length);
1✔
635
    }
636

637
    public static String times(String str, int num) {
638
        if (num < 0) {
×
639
            throw new IllegalArgumentException("times() should be called with a number >= 0, got " + num);
×
640
        } else if (num == 0) {
×
641
            return "";
×
642
        } else {
643
            StringBuilder b = new StringBuilder(str);
×
644

645
            for (int i = 1; i < num; ++i) {
×
646
                b.append(str);
×
647
            }
648

649
            return b.toString();
×
650
        }
651
    }
652

653
    public static String stripMargin(String str) {
654
        return Stream.of(str.split(lineSeparator()))
1✔
655
            .map(String::trim)
1✔
656
            .collect(joining(lineSeparator()));
1✔
657
    }
658

659
    public static String escapeRegexChars(String str) {
660
        if (str.isEmpty()) return "";
1✔
661
        boolean start = false;
1✔
662
        boolean end = false;
1✔
663

664
        String s = str;
1✔
665
        if (s.charAt(0) == '^' && s.length() > 1) {
1✔
666
            start = true;
×
667
            s = s.substring(1);
×
668
        }
669
        if (s.charAt(s.length() - 1) == '$' && s.length() > 1) {
1✔
670
            end = true;
×
671
            s = s.substring(0, s.length() - 2);
×
672
        }
673

674
        String replaced = REGEX_CHARS.matcher(s).replaceAll("\\\\$0");
1✔
675
        return (start ? "^" : "") + replaced + (end ? "$" : "");
1✔
676
    }
677

678
    public static String toSafeRegexPattern(String str) {
679
        StringBuilder b = new StringBuilder();
1✔
680
        if (!str.startsWith("^")) {
1✔
681
            b.append(".*");
1✔
682
        }
683
        b.append(escapeRegexChars(str));
1✔
684
        if (!str.endsWith("$")) {
1✔
685
            b.append(".*");
1✔
686
        }
687

688
        return b.toString();
1✔
689
    }
690

691
    public static String normalizeRegexPattern(String str) {
692
        StringBuilder b = new StringBuilder();
1✔
693
        if (!str.startsWith("^")) {
1✔
694
            b.append(".*");
×
695
        }
696
        b.append(str);
1✔
697
        if (!str.endsWith("$")) {
1✔
698
            b.append(".*");
1✔
699
        }
700

701
        return b.toString();
1✔
702
    }
703

704
    public static Pattern toSafePattern(String str) {
705
        return Pattern.compile(toSafeRegexPattern(str));
×
706
    }
707

708
    public static boolean isTrue(Object o, boolean defaultIfAbsent) {
709
        if (null == o) return defaultIfAbsent;
1✔
710
        if (o instanceof Boolean) return (Boolean) o;
1✔
711
        return "true".equalsIgnoreCase(String.valueOf(o).trim());
1✔
712
    }
713

714
    public static boolean isTrue(Object o) {
715
        return isTrue(o, false);
1✔
716
    }
717

718
    public static boolean isFalse(Object o) {
719
        return !isTrue(o);
1✔
720
    }
721

722
    /**
723
     * Applies single or double quotes to a string if it contains whitespace characters
724
     *
725
     * @param str the String to be surrounded by quotes
726
     * @return a copy of the original String, surrounded by quotes
727
     */
728
    public static String quote(String str) {
729
        if (isBlank(str)) {
1✔
730
            return str;
1✔
731
        }
732
        for (int i = 0; i < str.length(); i++) {
1✔
733
            if (Character.isWhitespace(str.charAt(i))) {
1✔
734
                str = applyQuotes(str);
1✔
735
                break;
1✔
736
            }
737
        }
738
        return str;
1✔
739
    }
740

741
    /**
742
     * Removes single or double quotes from a String
743
     *
744
     * @param str the String from which quotes will be removed
745
     * @return the unquoted String
746
     */
747
    public static String unquote(String str) {
748
        if (isBlank(str)) {
1✔
749
            return str;
1✔
750
        }
751
        boolean hasDoubleQuotes = str.startsWith("'") && str.endsWith("'");
1✔
752
        boolean hasSingleQuotes = str.startsWith("\"") && str.endsWith("\"");
1✔
753
        if (hasDoubleQuotes || hasSingleQuotes) {
1✔
754
            return str.substring(1, str.length() - 1);
1✔
755
        }
756
        return str;
1✔
757
    }
758

759
    private static String applyQuotes(String string) {
760
        if (null == string || string.length() == 0) {
1✔
761
            return "\"\"";
×
762
        }
763

764
        char b;
765
        char c = 0;
1✔
766
        int i;
767
        int len = string.length();
1✔
768
        StringBuilder sb = new StringBuilder(len * 2);
1✔
769
        String t;
770
        char[] chars = string.toCharArray();
1✔
771
        char[] buffer = new char[1030];
1✔
772
        int bufferIndex = 0;
1✔
773
        sb.append('"');
1✔
774
        for (i = 0; i < len; i += 1) {
1✔
775
            if (bufferIndex > 1024) {
1✔
776
                sb.append(buffer, 0, bufferIndex);
×
777
                bufferIndex = 0;
×
778
            }
779
            b = c;
1✔
780
            c = chars[i];
1✔
781
            switch (c) {
1✔
782
                case '\\':
783
                case '"':
784
                    buffer[bufferIndex++] = '\\';
×
785
                    buffer[bufferIndex++] = c;
×
786
                    break;
×
787
                case '/':
788
                    if (b == '<') {
×
789
                        buffer[bufferIndex++] = '\\';
×
790
                    }
791
                    buffer[bufferIndex++] = c;
×
792
                    break;
×
793
                default:
794
                    if (c < ' ') {
1✔
795
                        switch (c) {
×
796
                            case '\b':
797
                                buffer[bufferIndex++] = '\\';
×
798
                                buffer[bufferIndex++] = 'b';
×
799
                                break;
×
800
                            case '\t':
801
                                buffer[bufferIndex++] = '\\';
×
802
                                buffer[bufferIndex++] = 't';
×
803
                                break;
×
804
                            case '\n':
805
                                buffer[bufferIndex++] = '\\';
×
806
                                buffer[bufferIndex++] = 'n';
×
807
                                break;
×
808
                            case '\f':
809
                                buffer[bufferIndex++] = '\\';
×
810
                                buffer[bufferIndex++] = 'f';
×
811
                                break;
×
812
                            case '\r':
813
                                buffer[bufferIndex++] = '\\';
×
814
                                buffer[bufferIndex++] = 'r';
×
815
                                break;
×
816
                            default:
817
                                t = "000" + Integer.toHexString(c);
×
818
                                int tLength = t.length();
×
819
                                buffer[bufferIndex++] = '\\';
×
820
                                buffer[bufferIndex++] = 'u';
×
821
                                buffer[bufferIndex++] = t.charAt(tLength - 4);
×
822
                                buffer[bufferIndex++] = t.charAt(tLength - 3);
×
823
                                buffer[bufferIndex++] = t.charAt(tLength - 2);
×
824
                                buffer[bufferIndex++] = t.charAt(tLength - 1);
×
825
                        }
826
                    } else {
827
                        buffer[bufferIndex++] = c;
1✔
828
                    }
829
            }
830
        }
831
        sb.append(buffer, 0, bufferIndex);
1✔
832
        sb.append('"');
1✔
833
        return sb.toString();
1✔
834
    }
835
}
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