[
https://issues.apache.org/jira/browse/GEODE-10547?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Jinwoo Hwang updated GEODE-10547:
---------------------------------
Fix Version/s: 2.1.0
> Migrate deprecated commons-lang3 methods with Java standard library
> equivalents
> -------------------------------------------------------------------------------
>
> Key: GEODE-10547
> URL: https://issues.apache.org/jira/browse/GEODE-10547
> Project: Geode
> Issue Type: Improvement
> Reporter: Jinwoo Hwang
> Assignee: Jinwoo Hwang
> Priority: Major
> Fix For: 2.1.0
>
>
> h1. Replace deprecated commons-lang3 methods with Java standard library
> equivalents
> h2. Summary
> Replace deprecated Apache Commons Lang3 utility methods with Java standard
> library equivalents to eliminate deprecation warnings and improve code
> maintainability.
> h2. Issue Type
> * *Type:* Technical Debt / Code Improvement
> * *Priority:* Medium
> * *Component:* Code Quality
> * *Related:* GEODE-10543 (commons-lang3 3.18.0 upgrade for CVE-2025-48924)
> h2. Description
> As part of upgrading to commons-lang3 3.18.0, several utility methods have
> been deprecated. These methods have direct equivalents in the Java standard
> library that provide the same functionality with better performance and no
> external dependencies.
> This task replaces all deprecated commons-lang3 method calls with their Java
> standard library equivalents across the Apache Geode codebase.
> h3. Deprecated Methods Being Replaced
> # {{StringUtils.startsWith(String, String)}} → {{String.startsWith(String)}}
> # {{StringUtils.containsIgnoreCase(String, String)}} →
> {{String.toLowerCase().contains(String.toLowerCase())}}
> # {{StringUtils.equals(String, String)}} → {{Objects.equals(Object, Object)}}
> # {{StringUtils.removeStart(String, String)}} → {{startsWith() +
> substring()}}
> # {{LineIterator.nextLine()}} → {{LineIterator.next()}}
> h2. Benefits
> * *Eliminates deprecation warnings* during compilation
> * *Reduces external dependencies* by using Java standard library
> * *Improves performance* - native Java methods are typically faster
> * *Better null safety* - {{Objects.equals()}} handles null properly
> * *Future-proof* - Java standard library methods won't be deprecated
> * *Cleaner code* - removes unnecessary utility wrapper calls
> h2. Implementation Details
> h3. Method Replacement Details
> h4. 1. StringUtils.startsWith() → String.startsWith()
> *Before:*
> {code:java}
> if (StringUtils.startsWith(url, "https")) {
> // ...
> }
> {code}
> *After:*
> {code:java}
> if (url.startsWith("https")) {
> // ...
> }
> {code}
> *Considerations:* String.startsWith() throws NullPointerException if the
> string is null. Ensure proper null checks exist.
> h4. 2. StringUtils.containsIgnoreCase() → toLowerCase().contains()
> *Before:*
> {code:java}
> if (StringUtils.containsIgnoreCase(query, "keyword")) {
> // ...
> }
> {code}
> *After:*
> {code:java}
> if (query.toLowerCase().contains("keyword".toLowerCase())) {
> // ...
> }
> {code}
> *Considerations:* Both strings need toLowerCase() for case-insensitive
> comparison. Requires null check on the source string.
> h4. 3. StringUtils.equals() → Objects.equals()
> *Before:*
> {code:java}
> if (StringUtils.equals(value1, value2)) {
> // ...
> }
> {code}
> *After:*
> {code:java}
> if (Objects.equals(value1, value2)) {
> // ...
> }
> {code}
> *Benefits:* {{Objects.equals()}} is null-safe and works for any object type,
> not just strings.
> h4. 4. StringUtils.removeStart() → startsWith() + substring()
> *Before:*
> {code:java}
> String result = StringUtils.removeStart(text, "prefix");
> {code}
> *After:*
> {code:java}
> String result = text.startsWith("prefix") ? text.substring("prefix".length())
> : text;
> {code}
> *Considerations:* Requires explicit logic to handle the case when prefix is
> not present.
> h4. 5. LineIterator.nextLine() → LineIterator.next()
> *Before:*
> {code:java}
> while (iterator.hasNext()) {
> String line = iterator.nextLine();
> }
> {code}
> *After:*
> {code:java}
> while (iterator.hasNext()) {
> String line = iterator.next();
> }
> {code}
> *Note:* {{nextLine()}} is deprecated in commons-io 2.18.0. Use {{next()}}
> which is the standard Iterator interface method.
> h3. Files Affected
> *geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/ConnectCommand.java*
> *
> ** Line ~126: {{StringUtils.startsWith()}} → {{String.startsWith()}}
> *geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/QueryCommand.java*
> *
> ** {{StringUtils.containsIgnoreCase()}} → {{toLowerCase().contains()}}
> *geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/CreateIndexCommand.java*
> *
> ** {{StringUtils.removeStart()}} → {{startsWith() + substring()}}
> *geode-management/src/main/java/org/apache/geode/management/configuration/Index.java*
> *
> ** {{StringUtils.removeStart()}} → {{startsWith() + substring()}}
> *geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/domain/FixedPartitionAttributesInfo.java*
> *
> ** {{StringUtils.equals()}} → {{Objects.equals()}}
> *geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/domain/RegionAttributesInfo.java*
> *
> ** {{StringUtils.equals()}} → {{Objects.equals()}}
> *geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/domain/PartitionAttributesInfo.java*
> *
> ** {{StringUtils.equals()}} → {{Objects.equals()}}
> *geode-assembly/src/acceptanceTest/java/org/apache/geode/management/internal/cli/commands/StartServerCommandAcceptanceTest.java*
> *
> ** {{LineIterator.nextLine()}} → {{LineIterator.next()}}
> h3. Required Imports
> Add these imports where needed:
> {code:java}
> import java.util.Objects; // For Objects.equals()
> {code}
> Remove if no longer used:
> {code:java}
> import org.apache.commons.lang3.StringUtils;
> {code}
> h2. Testing Strategy
> h3. Verification Steps
> *Compilation:* Ensure no deprecation warnings remain
> {code:bash}
> ./gradlew clean build -Werror
> {code}
> *Unit Tests:* All existing tests should pass
> {code:bash}
> ./gradlew test
> {code}
> *Functionality:* Verify behavior is identical
> *
> ** String comparisons work correctly
> ** Case-insensitive searches work
> ** Null handling is proper
> ** Edge cases are covered
> h3. Risk Assessment
> {panel:title=Low
> Risk|borderStyle=solid|borderColor=#cccccc|titleBGColor=#dff0d8|bgColor=#dff0d8}
> * *Low Risk:* These are straightforward method replacements with equivalent
> functionality
> * *Well-tested:* All modified code paths have existing unit tests
> * *Standard library:* Using well-tested Java standard library methods{panel}
> h4. Potential Issues
> * *Null handling:* {{String}} methods throw {{NullPointerException}} on
> null, while {{StringUtils}} returns false/empty
> ** *Mitigation:* Code analysis shows all call sites have proper null checks
> * *Case sensitivity:* Must ensure {{toLowerCase()}} is applied to both
> strings in comparisons
> ** *Mitigation:* Code review verified correct implementation
> h2. Acceptance Criteria
> * All deprecated commons-lang3 method calls replaced in production code
> * All deprecated commons-io method calls replaced in test code
> * No deprecation warnings during compilation
> * All unit tests pass without modification
> * Build succeeds with {{-Werror}} flag (warnings as errors)
> * Code review confirms correct null handling
> * No behavioral changes in functionality
> h2. Build Verification
> h4. Commands to Verify
> {code:bash}
> # Clean build with strict warnings
> export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)
> ./gradlew clean build -Werror
> # Verify no deprecation warnings
> ./gradlew compileJava 2>&1 | grep -i "deprecation"
> # Run full test suite
> ./gradlew test
> {code}
> h2. Related Changes
> * Part of GEODE-10543: commons-lang3 3.18.0 upgrade
> * Complements CVE-2025-48924 security fix
> * Coordinates with:
> ** commons-io 2.18.0 upgrade
> ** slf4j-api 1.7.36 upgrade
> ** Log4j 2.25.3 upgrade
> h2. Code Review Checklist
> * All {{StringUtils}} methods replaced with Java equivalents
> * Proper null checks exist before calling {{String}} instance methods
> * Case-insensitive comparisons use {{toLowerCase()}} on both sides
> * {{Objects.equals()}} imported and used correctly
> * {{LineIterator.next()}} used instead of {{nextLine()}}
> * No unused imports remaining
> * Code formatting follows project standards (spotless check passes)
> h2. Documentation
> h4. Migration Guide for Developers
> Future code should use:
> * {{String.startsWith()}} instead of {{StringUtils.startsWith()}}
> * {{String.toLowerCase().contains()}} instead of
> {{StringUtils.containsIgnoreCase()}}
> * {{Objects.equals()}} instead of {{StringUtils.equals()}}
> * Ternary with {{startsWith() + substring()}} instead of
> {{StringUtils.removeStart()}}
> * {{Iterator.next()}} instead of {{LineIterator.nextLine()}}
> h2. Estimated Effort
> * Analysis: 2 - 3 days
> * Implementation: 1 - 2 weeks
> * Testing: 2 - 3 days
>
--
This message was sent by Atlassian Jira
(v8.20.10#820010)