Skip to content

Commit 6681a34

Browse files
committed
2 parents af15982 + fb45bd7 commit 6681a34

File tree

10 files changed

+134
-34
lines changed

10 files changed

+134
-34
lines changed

.github/workflows/codeql-analysis.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ jobs:
4545

4646
steps:
4747
- name: Checkout repository
48-
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # 4.2.1
48+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2
4949
with:
5050
persist-credentials: false
51-
- uses: actions/cache@3624ceb22c1c5a301c8db4169662070a689d9ea8 # v4.1.1
51+
- uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2
5252
with:
5353
path: ~/.m2/repository
5454
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
@@ -57,7 +57,7 @@ jobs:
5757
5858
# Initializes the CodeQL tools for scanning.
5959
- name: Initialize CodeQL
60-
uses: github/codeql-action/init@f779452ac5af1c261dce0346a8f964149f49322b # 3.26.13
60+
uses: github/codeql-action/init@662472033e021d55d94146f66f6058822b0b39fd # 3.27.0
6161
with:
6262
languages: ${{ matrix.language }}
6363
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -68,7 +68,7 @@ jobs:
6868
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
6969
# If this step fails, then you should remove it and run the build manually (see below)
7070
- name: Autobuild
71-
uses: github/codeql-action/autobuild@f779452ac5af1c261dce0346a8f964149f49322b # 3.26.13
71+
uses: github/codeql-action/autobuild@662472033e021d55d94146f66f6058822b0b39fd # 3.27.0
7272

7373
# ℹ️ Command-line programs to run using the OS shell.
7474
# 📚 https://git.io/JvXDl
@@ -82,4 +82,4 @@ jobs:
8282
# make release
8383

8484
- name: Perform CodeQL Analysis
85-
uses: github/codeql-action/analyze@f779452ac5af1c261dce0346a8f964149f49322b # 3.26.13
85+
uses: github/codeql-action/analyze@662472033e021d55d94146f66f6058822b0b39fd # 3.27.0

.github/workflows/dependency-review.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
# under the License.
1717

1818
name: 'Dependency Review'
19-
on: [push, pull_request]
19+
on: [pull_request]
2020

2121
permissions:
2222
contents: read
@@ -26,9 +26,9 @@ jobs:
2626
runs-on: ubuntu-latest
2727
steps:
2828
- name: 'Checkout Repository'
29-
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1
29+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
3030
- name: 'Dependency Review PR'
31-
uses: actions/dependency-review-action@5a2ce3f5b92ee19cbb1541a4984c76d921601d7c # v4.3.4
31+
uses: actions/dependency-review-action@4081bf99e2866ebe428fc0477b69eb4fcda7220a # v4.4.0
3232
with:
3333
base-ref: ${{ github.event.before }}
3434
head-ref: ${{ github.sha }}

.github/workflows/maven.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,17 @@ jobs:
3939
os: ubuntu-latest
4040

4141
steps:
42-
- uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1
42+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
4343
with:
4444
persist-credentials: false
45-
- uses: actions/cache@3624ceb22c1c5a301c8db4169662070a689d9ea8 # v4.1.1
45+
- uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2
4646
with:
4747
path: ~/.m2/repository
4848
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
4949
restore-keys: |
5050
${{ runner.os }}-maven-
5151
- name: Set up JDK ${{ matrix.java }}
52-
uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0
52+
uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b # v4.5.0
5353
with:
5454
distribution: 'temurin'
5555
java-version: ${{ matrix.java }}

.github/workflows/scorecards-analysis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
steps:
4141

4242
- name: "Checkout code"
43-
uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # 4.2.1
43+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2
4444
with:
4545
persist-credentials: false
4646

@@ -64,6 +64,6 @@ jobs:
6464
retention-days: 5
6565

6666
- name: "Upload to code-scanning"
67-
uses: github/codeql-action/upload-sarif@f779452ac5af1c261dce0346a8f964149f49322b # 3.26.13
67+
uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # 3.27.0
6868
with:
6969
sarif_file: results.sarif

src/changes/changes.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ The <action> type attribute can be add,update,fix,remove.
6161
<action issue="LANG-1753" type="fix" dev="ggregory" due-to="Capt. Cutlass">StringUtils.replaceEachRepeatedly regression in 3.11+ #1297.</action>
6262
<action type="fix" dev="ggregory" due-to="Capt. Cutlass">Use simplified JUnit assertion methods #1298.</action>
6363
<action issue="LANG-1682" type="fix" dev="ggregory" due-to="Capt. Cutlass">Javadoc and test: Use Strings.CI.startsWithAny method instead #1299.</action>
64+
<action type="fix" dev="ggregory" due-to="Gary Gregory">Fix NullPointerException in FastDateParser.TimeZoneStrategy.setCalendar(FastDateParser, Calendar, String) on Java 23.</action>
6465
<action issue="LANG-1757" type="fix" dev="ggregory" due-to="Gary Gregory">Fix NullPointerException in MethodUtils.getMatchingAccessibleMethod((Class, String, Class...)).</action>
6566
<!-- ADD -->
6667
<action type="add" dev="ggregory" due-to="Gary Gregory">Add Strings and refactor StringUtils.</action>
@@ -69,6 +70,8 @@ The <action> type attribute can be add,update,fix,remove.
6970
<action type="add" dev="ggregory" due-to="Gary Gregory">Add SystemUtils.IS_JAVA_23.</action>
7071
<action type="add" dev="ggregory" due-to="Gary Gregory">Add IntegerRange.toIntStream().</action>
7172
<action type="add" dev="ggregory" due-to="Gary Gregory">Add LongRange.toLongStream().</action>
73+
<action type="add" dev="ggregory" due-to="Gary Gregory">Add IntStrams.of(int...).</action>
74+
<action type="add" dev="ggregory" due-to="Gary Gregory">Add ArrayUtils.containsAny(int[], int...).</action>
7275
<!-- UPDATE -->
7376
<action type="update" dev="ggregory" due-to="Gary Gregory, Dependabot">Bump org.apache.commons:commons-parent from 73 to 78 #1267, #1277, #1283, #1288, #1302.</action>
7477
<action type="update" dev="ggregory" due-to="Gary Gregory, Dependabot">Bump org.codehaus.mojo:taglist-maven-plugin from 3.1.0 to 3.2.1 #1300.</action>

src/main/java/org/apache/commons/lang3/ArrayUtils.java

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.apache.commons.lang3.builder.ToStringStyle;
4040
import org.apache.commons.lang3.math.NumberUtils;
4141
import org.apache.commons.lang3.mutable.MutableInt;
42+
import org.apache.commons.lang3.stream.IntStreams;
4243
import org.apache.commons.lang3.stream.Streams;
4344

4445
/**
@@ -1572,6 +1573,10 @@ public static boolean contains(final boolean[] array, final boolean valueToFind)
15721573
* <p>
15731574
* The method returns {@code false} if a {@code null} array is passed in.
15741575
* </p>
1576+
* <p>
1577+
* If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
1578+
* {@link Arrays#sort(byte[])} and {@link Arrays#binarySearch(byte[], byte)}.
1579+
* </p>
15751580
*
15761581
* @param array the array to search through
15771582
* @param valueToFind the value to find
@@ -1586,6 +1591,10 @@ public static boolean contains(final byte[] array, final byte valueToFind) {
15861591
* <p>
15871592
* The method returns {@code false} if a {@code null} array is passed in.
15881593
* </p>
1594+
* <p>
1595+
* If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
1596+
* {@link Arrays#sort(char[])} and {@link Arrays#binarySearch(char[], char)}.
1597+
* </p>
15891598
*
15901599
* @param array the array to search through
15911600
* @param valueToFind the value to find
@@ -1601,6 +1610,10 @@ public static boolean contains(final char[] array, final char valueToFind) {
16011610
* <p>
16021611
* The method returns {@code false} if a {@code null} array is passed in.
16031612
* </p>
1613+
* <p>
1614+
* If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
1615+
* {@link Arrays#sort(double[])} and {@link Arrays#binarySearch(double[], double)}.
1616+
* </p>
16041617
*
16051618
* @param array the array to search through
16061619
* @param valueToFind the value to find
@@ -1618,6 +1631,10 @@ public static boolean contains(final double[] array, final double valueToFind) {
16181631
* The method returns {@code false} if a {@code null} array
16191632
* is passed in.
16201633
* </p>
1634+
* <p>
1635+
* If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
1636+
* {@link Arrays#sort(double[])} and {@link Arrays#binarySearch(double[], double)}.
1637+
* </p>
16211638
*
16221639
* @param array the array to search
16231640
* @param valueToFind the value to find
@@ -1633,6 +1650,10 @@ public static boolean contains(final double[] array, final double valueToFind, f
16331650
* <p>
16341651
* The method returns {@code false} if a {@code null} array is passed in.
16351652
* </p>
1653+
* <p>
1654+
* If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
1655+
* {@link Arrays#sort(float[])} and {@link Arrays#binarySearch(float[], float)}.
1656+
* </p>
16361657
*
16371658
* @param array the array to search through
16381659
* @param valueToFind the value to find
@@ -1647,6 +1668,10 @@ public static boolean contains(final float[] array, final float valueToFind) {
16471668
* <p>
16481669
* The method returns {@code false} if a {@code null} array is passed in.
16491670
* </p>
1671+
* <p>
1672+
* If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
1673+
* {@link Arrays#sort(int[])} and {@link Arrays#binarySearch(int[], int)}.
1674+
* </p>
16501675
*
16511676
* @param array the array to search through
16521677
* @param valueToFind the value to find
@@ -1661,6 +1686,10 @@ public static boolean contains(final int[] array, final int valueToFind) {
16611686
* <p>
16621687
* The method returns {@code false} if a {@code null} array is passed in.
16631688
* </p>
1689+
* <p>
1690+
* If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
1691+
* {@link Arrays#sort(long[])} and {@link Arrays#binarySearch(long[], long)}.
1692+
* </p>
16641693
*
16651694
* @param array the array to search through
16661695
* @param valueToFind the value to find
@@ -1675,6 +1704,10 @@ public static boolean contains(final long[] array, final long valueToFind) {
16751704
* <p>
16761705
* The method returns {@code false} if a {@code null} array is passed in.
16771706
* </p>
1707+
* <p>
1708+
* If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
1709+
* {@link Arrays#sort(Object[], Comparator)} and {@link Arrays#binarySearch(Object[], Object)}.
1710+
* </p>
16781711
*
16791712
* @param array the array to search through
16801713
* @param objectToFind the object to find
@@ -1689,6 +1722,10 @@ public static boolean contains(final Object[] array, final Object objectToFind)
16891722
* <p>
16901723
* The method returns {@code false} if a {@code null} array is passed in.
16911724
* </p>
1725+
* <p>
1726+
* If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
1727+
* {@link Arrays#sort(short[])} and {@link Arrays#binarySearch(short[], short)}.
1728+
* </p>
16921729
*
16931730
* @param array the array to search through
16941731
* @param valueToFind the value to find
@@ -1698,14 +1735,37 @@ public static boolean contains(final short[] array, final short valueToFind) {
16981735
return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
16991736
}
17001737

1738+
/**
1739+
* Checks if any of the ints are in the given array.
1740+
* <p>
1741+
* The method returns {@code false} if a {@code null} array is passed in.
1742+
* </p>
1743+
* <p>
1744+
* If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
1745+
* {@link Arrays#sort(int[])} and {@link Arrays#binarySearch(int[], int)}.
1746+
* </p>
1747+
*
1748+
* @param array the array to search through
1749+
* @param objectsToFind any of the ints to find
1750+
* @return {@code true} if the array contains any of the ints
1751+
* @since 3.18.0
1752+
*/
1753+
public static boolean containsAny(final int[] array, final int... objectsToFind) {
1754+
return IntStreams.of(objectsToFind).anyMatch(e -> contains(array, e));
1755+
}
1756+
17011757
/**
17021758
* Checks if any of the objects are in the given array.
17031759
* <p>
17041760
* The method returns {@code false} if a {@code null} array is passed in.
17051761
* </p>
1762+
* <p>
1763+
* If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
1764+
* {@link Arrays#sort(Object[], Comparator)} and {@link Arrays#binarySearch(Object[], Object)}.
1765+
* </p>
17061766
*
1707-
* @param array the array to search through
1708-
* @param objectsToFind any of the objects to find
1767+
* @param array the array to search through
1768+
* @param objectsToFind any of the objects to find
17091769
* @return {@code true} if the array contains any of the objects
17101770
* @since 3.13.0
17111771
*/

src/main/java/org/apache/commons/lang3/stream/IntStreams.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@
2828
*/
2929
public class IntStreams {
3030

31+
/**
32+
* Null-safe version of {@link IntStream#of(int[])}.
33+
*
34+
* @param values the elements of the new stream, may be {@code null}.
35+
* @return the new stream on {@code values} or {@link IntStream#empty()}.
36+
* @since 3.18.0
37+
*/
38+
@SafeVarargs // Creating a stream from an array is safe
39+
public static IntStream of(final int... values) {
40+
return values == null ? IntStream.empty() : IntStream.of(values);
41+
}
42+
3143
/**
3244
* Shorthand for {@code IntStream.range(0, i)}.
3345
*

src/main/java/org/apache/commons/lang3/time/FastDateParser.java

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.text.ParsePosition;
2525
import java.text.SimpleDateFormat;
2626
import java.util.ArrayList;
27+
import java.util.Arrays;
2728
import java.util.Calendar;
2829
import java.util.Comparator;
2930
import java.util.Date;
@@ -35,12 +36,14 @@
3536
import java.util.Objects;
3637
import java.util.Set;
3738
import java.util.TimeZone;
39+
import java.util.TreeMap;
3840
import java.util.TreeSet;
3941
import java.util.concurrent.ConcurrentHashMap;
4042
import java.util.concurrent.ConcurrentMap;
4143
import java.util.regex.Matcher;
4244
import java.util.regex.Pattern;
4345

46+
import org.apache.commons.lang3.ArraySorter;
4447
import org.apache.commons.lang3.LocaleUtils;
4548

4649
/**
@@ -494,14 +497,19 @@ public String toString() {
494497
private static final String RFC_822_TIME_ZONE = "[+-]\\d{4}";
495498

496499
private static final String GMT_OPTION = TimeZones.GMT_ID + "[+-]\\d{1,2}:\\d{2}";
500+
497501
/**
498-
* Index of zone id
502+
* Index of zone id from {@link DateFormatSymbols#getZoneStrings()}.
499503
*/
500504
private static final int ID = 0;
501505

502506
private final Locale locale;
503507

504-
private final Map<String, TzInfo> tzNames = new HashMap<>();
508+
/**
509+
* Using lower case only or upper case only will cause problems with some Locales like Turkey, Armenia, Colognian and also depending on the Java
510+
* version. For details, see https://garygregory.wordpress.com/2015/11/03/java-lowercase-conversion-turkey/
511+
*/
512+
private final Map<String, TzInfo> tzNames = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
505513

506514
/**
507515
* Constructs a Strategy that parses a TimeZone
@@ -543,30 +551,23 @@ public String toString() {
543551
break;
544552
}
545553
final String zoneName = zoneNames[i];
546-
if (zoneName != null) {
547-
final String key = zoneName.toLowerCase(locale);
548-
// ignore the data associated with duplicates supplied in
549-
// the additional names
550-
if (sorted.add(key)) {
551-
tzNames.put(key, tzInfo);
552-
}
554+
// ignore the data associated with duplicates supplied in the additional names
555+
if (zoneName != null && sorted.add(zoneName)) {
556+
tzNames.put(zoneName, tzInfo);
553557
}
554558
}
555559
}
556-
557560
// Order is undefined.
558-
for (final String tzId : TimeZone.getAvailableIDs()) {
561+
for (final String tzId : ArraySorter.sort(TimeZone.getAvailableIDs())) {
559562
if (tzId.equalsIgnoreCase(TimeZones.GMT_ID)) {
560563
continue;
561564
}
562565
final TimeZone tz = TimeZone.getTimeZone(tzId);
563566
final String zoneName = tz.getDisplayName(locale);
564-
final String key = zoneName.toLowerCase(locale);
565-
if (sorted.add(key)) {
566-
tzNames.put(key, new TzInfo(tz, tz.observesDaylightTime()));
567+
if (sorted.add(zoneName)) {
568+
tzNames.put(zoneName, new TzInfo(tz, tz.observesDaylightTime()));
567569
}
568570
}
569-
570571
// order the regex alternatives with longer strings first, greedy
571572
// match will ensure the longest string will be consumed
572573
sorted.forEach(zoneName -> simpleQuote(sb.append('|'), zoneName));
@@ -583,11 +584,16 @@ void setCalendar(final FastDateParser parser, final Calendar calendar, final Str
583584
if (tz != null) {
584585
calendar.setTimeZone(tz);
585586
} else {
586-
final String lowerCase = timeZone.toLowerCase(locale);
587-
TzInfo tzInfo = tzNames.get(lowerCase);
587+
TzInfo tzInfo = tzNames.get(timeZone);
588588
if (tzInfo == null) {
589589
// match missing the optional trailing period
590-
tzInfo = tzNames.get(lowerCase + '.');
590+
tzInfo = tzNames.get(timeZone + '.');
591+
if (tzInfo == null) {
592+
// show chars in case this is multiple byte character issue
593+
final char[] charArray = timeZone.toCharArray();
594+
throw new IllegalStateException(String.format("Can't find time zone '%s' (%d %s) in %s", timeZone, charArray.length,
595+
Arrays.toString(charArray), new TreeSet<>(tzNames.keySet())));
596+
}
591597
}
592598
calendar.set(Calendar.DST_OFFSET, tzInfo.dstOffset);
593599
calendar.set(Calendar.ZONE_OFFSET, tzInfo.zone.getRawOffset());
@@ -1079,6 +1085,7 @@ private void readObject(final ObjectInputStream in) throws IOException, ClassNot
10791085
public String toString() {
10801086
return "FastDateParser[" + pattern + ", " + locale + ", " + timeZone.getID() + "]";
10811087
}
1088+
10821089
/**
10831090
* Converts all state of this instance to a String handy for debugging.
10841091
*

0 commit comments

Comments
 (0)