diff --git a/paimon-api/src/main/java/org/apache/paimon/utils/StringUtils.java b/paimon-api/src/main/java/org/apache/paimon/utils/StringUtils.java index c189de92e5d6..2b8f3f395c4b 100644 --- a/paimon-api/src/main/java/org/apache/paimon/utils/StringUtils.java +++ b/paimon-api/src/main/java/org/apache/paimon/utils/StringUtils.java @@ -307,6 +307,112 @@ public static boolean isNotEmpty(CharSequence cs) { return !isEmpty(cs); } + public static boolean isBlank(final CharSequence cs) { + if (isEmpty(cs)) { + return true; + } + + for (int i = 0; i < cs.length(); i++) { + if (!Character.isWhitespace(cs.charAt(i))) { + return false; + } + } + return true; + } + + public static boolean equals(final CharSequence cs1, final CharSequence cs2) { + if (cs1 == cs2) { + return true; + } + if (cs1 == null || cs2 == null || cs1.length() != cs2.length()) { + return false; + } + + for (int i = 0; i < cs1.length(); i++) { + if (cs1.charAt(i) != cs2.charAt(i)) { + return false; + } + } + return true; + } + + public static boolean startsWith(final CharSequence str, final CharSequence prefix) { + if (str == prefix) { + return true; + } + if (str == null || prefix == null) { + return false; + } + + return str.toString().startsWith(prefix.toString()); + } + + public static boolean endsWith(final CharSequence str, final CharSequence suffix) { + if (str == suffix) { + return true; + } + if (str == null || suffix == null) { + return false; + } + + return str.toString().endsWith(suffix.toString()); + } + + public static String substringBeforeLast(final String str, final String separator) { + if (isEmpty(str) || isEmpty(separator)) { + return str; + } + + int pos = str.lastIndexOf(separator); + if (pos == INDEX_NOT_FOUND) { + return str; + } + + return str.substring(0, pos); + } + + public static String substringAfterLast(final String str, final String separator) { + if (isEmpty(str)) { + return str; + } + if (isEmpty(separator)) { + return EMPTY; + } + + int pos = str.lastIndexOf(separator); + if (pos == INDEX_NOT_FOUND || pos == str.length() - separator.length()) { + return EMPTY; + } + + return str.substring(pos + separator.length()); + } + + public static String stripEnd(final String str, final String stripChars) { + if (isEmpty(str)) { + return str; + } + + int end = str.length(); + if (stripChars == null) { + while (end != 0 && Character.isWhitespace(str.charAt(end - 1))) { + end--; + } + } else if (stripChars.isEmpty()) { + return str; + } else { + while (end != 0 && stripChars.indexOf(str.charAt(end - 1)) != INDEX_NOT_FOUND) { + end--; + } + } + + return str.substring(0, end); + } + + public static String trimToNull(final String str) { + String trimmed = trim(str); + return isEmpty(trimmed) ? null : trimmed; + } + public static String randomNumericString(int len) { StringBuilder builder = new StringBuilder(); ThreadLocalRandom rnd = ThreadLocalRandom.current(); @@ -445,6 +551,61 @@ public static String[] split( return list.toArray(new String[list.size()]); } + /** + * Joins the elements of the provided array into a single String containing the provided list of + * elements. + * + *

No delimiter is added before or after the list. A {@code null} separator is the same as an + * empty String (""). + * + * @param array the array of values to join together, may be null + * @param separator the separator character to use, null treated as "" + * @return the joined String, {@code null} if null array input + */ + public static String join(final Object[] array, final String separator) { + if (array == null) { + return null; + } + return join(array, separator, 0, array.length); + } + + /** + * Joins the elements of the provided array into a single String containing the provided list of + * elements. + * + *

No delimiter is added before or after the list. A {@code null} separator is the same as an + * empty String (""). + * + * @param array the array of values to join together, may be null + * @param separator the separator character to use, null treated as "" + * @param startIndex the first index to start joining from + * @param endIndex the index to stop joining from (exclusive) + * @return the joined String, {@code null} if null array input + */ + public static String join( + final Object[] array, + final String separator, + final int startIndex, + final int endIndex) { + if (array == null) { + return null; + } + final int noOfItems = endIndex - startIndex; + if (noOfItems <= 0) { + return EMPTY; + } + final StringBuilder buf = new StringBuilder(noOfItems * 16); + for (int i = startIndex; i < endIndex; i++) { + if (i > startIndex) { + buf.append(separator); + } + if (array[i] != null) { + buf.append(array[i]); + } + } + return buf.toString(); + } + /** * Joins the elements of the provided {@code Iterable} into a single String containing the * provided elements. diff --git a/paimon-benchmark/paimon-cluster-benchmark/src/main/java/org/apache/paimon/benchmark/metric/cpu/ProcfsBasedProcessTree.java b/paimon-benchmark/paimon-cluster-benchmark/src/main/java/org/apache/paimon/benchmark/metric/cpu/ProcfsBasedProcessTree.java index b1a9b3fd8699..e500d2820c53 100644 --- a/paimon-benchmark/paimon-cluster-benchmark/src/main/java/org/apache/paimon/benchmark/metric/cpu/ProcfsBasedProcessTree.java +++ b/paimon-benchmark/paimon-cluster-benchmark/src/main/java/org/apache/paimon/benchmark/metric/cpu/ProcfsBasedProcessTree.java @@ -20,13 +20,13 @@ import org.apache.paimon.benchmark.metric.cpu.clock.Clock; import org.apache.paimon.benchmark.metric.cpu.clock.SystemClock; +import org.apache.paimon.utils.StringUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.io.filefilter.AndFileFilter; import org.apache.commons.io.filefilter.DirectoryFileFilter; import org.apache.commons.io.filefilter.RegexFileFilter; import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.StringUtils; import java.io.BufferedReader; import java.io.File; diff --git a/paimon-benchmark/paimon-micro-benchmarks/src/test/java/org/apache/paimon/benchmark/Benchmark.java b/paimon-benchmark/paimon-micro-benchmarks/src/test/java/org/apache/paimon/benchmark/Benchmark.java index 939f8cf90bdc..450e7035a40b 100644 --- a/paimon-benchmark/paimon-micro-benchmarks/src/test/java/org/apache/paimon/benchmark/Benchmark.java +++ b/paimon-benchmark/paimon-micro-benchmarks/src/test/java/org/apache/paimon/benchmark/Benchmark.java @@ -18,7 +18,8 @@ package org.apache.paimon.benchmark; -import org.apache.paimon.shade.org.apache.commons.lang3.StringUtils; +import org.apache.paimon.utils.StringUtils; + import org.apache.paimon.shade.org.apache.commons.lang3.SystemUtils; import java.io.BufferedReader; diff --git a/paimon-common/src/test/java/org/apache/paimon/utils/StringUtilsTest.java b/paimon-common/src/test/java/org/apache/paimon/utils/StringUtilsTest.java index b281812a13d7..b80d5bc2bf7d 100644 --- a/paimon-common/src/test/java/org/apache/paimon/utils/StringUtilsTest.java +++ b/paimon-common/src/test/java/org/apache/paimon/utils/StringUtilsTest.java @@ -259,6 +259,56 @@ void testNonEmptyStringBuilder() { } } + @Nested + class CommonsCompatibilityTests { + + @Test + void testIsBlank() { + assertThat(StringUtils.isBlank(null)).isTrue(); + assertThat(StringUtils.isBlank("")).isTrue(); + assertThat(StringUtils.isBlank(" \t")).isTrue(); + assertThat(StringUtils.isBlank("paimon")).isFalse(); + } + + @Test + void testEquals() { + assertThat(StringUtils.equals(null, null)).isTrue(); + assertThat(StringUtils.equals(null, "paimon")).isFalse(); + assertThat(StringUtils.equals("paimon", "paimon")).isTrue(); + assertThat(StringUtils.equals("paimon", "Paimon")).isFalse(); + } + + @Test + void testStartsWithAndEndsWith() { + assertThat(StringUtils.startsWith("manifest-1", "manifest")).isTrue(); + assertThat(StringUtils.startsWith(null, "manifest")).isFalse(); + assertThat(StringUtils.endsWith("part-0.parquet", ".parquet")).isTrue(); + assertThat(StringUtils.endsWith("part-0.orc", ".parquet")).isFalse(); + } + + @Test + void testSubstringBeforeAndAfterLast() { + assertThat(StringUtils.substringBeforeLast("a/b/c", "/")).isEqualTo("a/b"); + assertThat(StringUtils.substringBeforeLast("abc", "/")).isEqualTo("abc"); + assertThat(StringUtils.substringAfterLast("a/b/c", "/")).isEqualTo("c"); + assertThat(StringUtils.substringAfterLast("abc/", "/")).isEmpty(); + } + + @Test + void testStripEnd() { + assertThat(StringUtils.stripEnd("cpu\n", null)).isEqualTo("cpu"); + assertThat(StringUtils.stripEnd("abccc", "c")).isEqualTo("ab"); + assertThat(StringUtils.stripEnd("abc", "")).isEqualTo("abc"); + } + + @Test + void testTrimToNull() { + assertThat(StringUtils.trimToNull(null)).isNull(); + assertThat(StringUtils.trimToNull(" ")).isNull(); + assertThat(StringUtils.trimToNull(" paimon ")).isEqualTo("paimon"); + } + } + @Nested class RandomNumericStringTests { diff --git a/paimon-core/src/main/java/org/apache/paimon/catalog/TableQueryAuthResult.java b/paimon-core/src/main/java/org/apache/paimon/catalog/TableQueryAuthResult.java index 87910b5cc65a..b0bb9b1d520d 100644 --- a/paimon-core/src/main/java/org/apache/paimon/catalog/TableQueryAuthResult.java +++ b/paimon-core/src/main/java/org/apache/paimon/catalog/TableQueryAuthResult.java @@ -36,8 +36,7 @@ import org.apache.paimon.types.RowType; import org.apache.paimon.utils.InternalRowUtils; import org.apache.paimon.utils.JsonSerdeUtil; - -import org.apache.paimon.shade.org.apache.commons.lang3.StringUtils; +import org.apache.paimon.utils.StringUtils; import javax.annotation.Nullable; diff --git a/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java b/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java index 364cdb3cd591..e81e6c8e6108 100644 --- a/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java +++ b/paimon-core/src/main/java/org/apache/paimon/rest/RESTCatalog.java @@ -63,13 +63,12 @@ import org.apache.paimon.table.system.SystemTableLoader; import org.apache.paimon.utils.Pair; import org.apache.paimon.utils.SnapshotNotExistException; +import org.apache.paimon.utils.StringUtils; import org.apache.paimon.view.View; import org.apache.paimon.view.ViewChange; import org.apache.paimon.view.ViewImpl; import org.apache.paimon.view.ViewSchema; -import org.apache.paimon.shade.org.apache.commons.lang3.StringUtils; - import javax.annotation.Nullable; import java.io.IOException; diff --git a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogServer.java b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogServer.java index 5961101c3a55..41caed02637b 100644 --- a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogServer.java +++ b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogServer.java @@ -111,6 +111,7 @@ import org.apache.paimon.utils.LazyField; import org.apache.paimon.utils.Pair; import org.apache.paimon.utils.SnapshotManager; +import org.apache.paimon.utils.StringUtils; import org.apache.paimon.utils.TagManager; import org.apache.paimon.utils.TimeUtils; import org.apache.paimon.view.View; @@ -120,7 +121,6 @@ import org.apache.paimon.shade.guava30.com.google.common.collect.ImmutableMap; import org.apache.paimon.shade.jackson2.com.fasterxml.jackson.core.JsonProcessingException; -import org.apache.paimon.shade.org.apache.commons.lang3.StringUtils; import okhttp3.mockwebserver.Dispatcher; import okhttp3.mockwebserver.MockResponse; diff --git a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java index e70a11321aff..78d8cd8e00a4 100644 --- a/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java +++ b/paimon-core/src/test/java/org/apache/paimon/rest/RESTCatalogTest.java @@ -90,6 +90,7 @@ import org.apache.paimon.types.DataTypes; import org.apache.paimon.utils.SnapshotManager; import org.apache.paimon.utils.SnapshotNotExistException; +import org.apache.paimon.utils.StringUtils; import org.apache.paimon.view.View; import org.apache.paimon.view.ViewChange; @@ -97,7 +98,6 @@ import org.apache.paimon.shade.guava30.com.google.common.collect.ImmutableMap; import org.apache.paimon.shade.guava30.com.google.common.collect.Lists; import org.apache.paimon.shade.guava30.com.google.common.collect.Maps; -import org.apache.paimon.shade.org.apache.commons.lang3.StringUtils; import org.apache.commons.io.FileUtils; import org.junit.jupiter.api.Assertions; diff --git a/paimon-flink/paimon-flink-1.18/src/main/java/org/apache/paimon/flink/procedure/CreateBranchProcedure.java b/paimon-flink/paimon-flink-1.18/src/main/java/org/apache/paimon/flink/procedure/CreateBranchProcedure.java index a7a8fb995271..547cbfecd33d 100644 --- a/paimon-flink/paimon-flink-1.18/src/main/java/org/apache/paimon/flink/procedure/CreateBranchProcedure.java +++ b/paimon-flink/paimon-flink-1.18/src/main/java/org/apache/paimon/flink/procedure/CreateBranchProcedure.java @@ -21,8 +21,7 @@ import org.apache.paimon.catalog.Catalog; import org.apache.paimon.catalog.Identifier; import org.apache.paimon.table.Table; - -import org.apache.paimon.shade.org.apache.commons.lang3.StringUtils; +import org.apache.paimon.utils.StringUtils; import org.apache.flink.table.procedure.ProcedureContext; diff --git a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/CreateBranchAction.java b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/CreateBranchAction.java index 0d681cae73bb..9e65878c99e7 100644 --- a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/CreateBranchAction.java +++ b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/action/CreateBranchAction.java @@ -18,7 +18,7 @@ package org.apache.paimon.flink.action; -import org.apache.paimon.shade.org.apache.commons.lang3.StringUtils; +import org.apache.paimon.utils.StringUtils; import java.util.Map; diff --git a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/procedure/CreateBranchProcedure.java b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/procedure/CreateBranchProcedure.java index 90cb5f8cd9ac..d6287cff56a3 100644 --- a/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/procedure/CreateBranchProcedure.java +++ b/paimon-flink/paimon-flink-common/src/main/java/org/apache/paimon/flink/procedure/CreateBranchProcedure.java @@ -21,8 +21,7 @@ import org.apache.paimon.catalog.Catalog; import org.apache.paimon.catalog.Identifier; import org.apache.paimon.table.Table; - -import org.apache.paimon.shade.org.apache.commons.lang3.StringUtils; +import org.apache.paimon.utils.StringUtils; import org.apache.flink.table.annotation.ArgumentHint; import org.apache.flink.table.annotation.DataTypeHint; diff --git a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/BranchSqlITCase.java b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/BranchSqlITCase.java index 641efb733595..0fd5b81de43c 100644 --- a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/BranchSqlITCase.java +++ b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/BranchSqlITCase.java @@ -22,8 +22,7 @@ import org.apache.paimon.table.FileStoreTable; import org.apache.paimon.utils.BlockingIterator; import org.apache.paimon.utils.SnapshotManager; - -import org.apache.paimon.shade.org.apache.commons.lang3.StringUtils; +import org.apache.paimon.utils.StringUtils; import org.apache.flink.types.Row; import org.apache.flink.types.RowKind; diff --git a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/CatalogTableITCase.java b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/CatalogTableITCase.java index 0bea96f04630..7a82007870a1 100644 --- a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/CatalogTableITCase.java +++ b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/CatalogTableITCase.java @@ -20,8 +20,7 @@ import org.apache.paimon.catalog.Catalog; import org.apache.paimon.utils.BlockingIterator; - -import org.apache.paimon.shade.org.apache.commons.lang3.StringUtils; +import org.apache.paimon.utils.StringUtils; import org.apache.flink.table.catalog.CatalogPartition; import org.apache.flink.table.catalog.CatalogPartitionSpec; diff --git a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/ShowCreateUtil.java b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/ShowCreateUtil.java index 415135ae514d..50ed3bf532dd 100644 --- a/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/ShowCreateUtil.java +++ b/paimon-flink/paimon-flink-common/src/test/java/org/apache/paimon/flink/ShowCreateUtil.java @@ -18,7 +18,7 @@ package org.apache.paimon.flink; -import org.apache.paimon.shade.org.apache.commons.lang3.StringUtils; +import org.apache.paimon.utils.StringUtils; import org.apache.flink.table.api.TableException; import org.apache.flink.table.catalog.CatalogBaseTable; diff --git a/paimon-spark/paimon-spark-ut/src/test/java/org/apache/paimon/spark/SparkReadTestBase.java b/paimon-spark/paimon-spark-ut/src/test/java/org/apache/paimon/spark/SparkReadTestBase.java index 27a7557ab75a..918552fb06fa 100644 --- a/paimon-spark/paimon-spark-ut/src/test/java/org/apache/paimon/spark/SparkReadTestBase.java +++ b/paimon-spark/paimon-spark-ut/src/test/java/org/apache/paimon/spark/SparkReadTestBase.java @@ -34,8 +34,7 @@ import org.apache.paimon.table.sink.TableCommitImpl; import org.apache.paimon.types.DataField; import org.apache.paimon.types.RowKind; - -import org.apache.paimon.shade.org.apache.commons.lang3.StringUtils; +import org.apache.paimon.utils.StringUtils; import org.apache.spark.sql.Dataset; import org.apache.spark.sql.Row; diff --git a/paimon-spark/paimon-spark-ut/src/test/java/org/apache/paimon/spark/SparkSchemaEvolutionITCase.java b/paimon-spark/paimon-spark-ut/src/test/java/org/apache/paimon/spark/SparkSchemaEvolutionITCase.java index ea837960cc40..1cdf210d89d4 100644 --- a/paimon-spark/paimon-spark-ut/src/test/java/org/apache/paimon/spark/SparkSchemaEvolutionITCase.java +++ b/paimon-spark/paimon-spark-ut/src/test/java/org/apache/paimon/spark/SparkSchemaEvolutionITCase.java @@ -18,7 +18,7 @@ package org.apache.paimon.spark; -import org.apache.paimon.shade.org.apache.commons.lang3.StringUtils; +import org.apache.paimon.utils.StringUtils; import org.apache.spark.sql.AnalysisException; import org.apache.spark.sql.Dataset; diff --git a/tools/maven/checkstyle.xml b/tools/maven/checkstyle.xml index 998c56383f66..2e8334375f9f 100644 --- a/tools/maven/checkstyle.xml +++ b/tools/maven/checkstyle.xml @@ -189,12 +189,6 @@ This file is based on the checkstyle file of Apache Beam. - - - - - - @@ -276,6 +270,13 @@ This file is based on the checkstyle file of Apache Beam. + + + + + @@ -588,4 +589,3 @@ This file is based on the checkstyle file of Apache Beam. -