feature: #98 | Ability to recover from specific exceptions#100
feature: #98 | Ability to recover from specific exceptions#100ShivamNagpal merged 1 commit intoZeplinko:developfrom
Conversation
WalkthroughAdded exception-type-specific overloads for recover and onFailure (single-type and varargs), adjusted compose to use observable state in its conditional path, and expanded unit tests to cover the new behaviors and edge cases. Changes
Sequence Diagram(s)sequenceDiagram
participant Caller
participant TryObj as Try<T>
participant Cond as Predicate<Try<T>>
participant Success as successMapper
participant Failure as failureMapper
participant Result as Try<U>
Caller->>TryObj: compose(condition, successMapper, failureMapper)
TryObj->>Cond: evaluate condition(TryObj)
alt condition true
TryObj->>Success: apply successMapper (uses isSuccess()/getData())
Success-->>Result: mapped Try<U>
else condition false
TryObj->>Failure: apply failureMapper (uses isSuccess()/getError())
Failure-->>Result: mapped Try<U>
end
Result-->>Caller: return Try<U>
sequenceDiagram
participant Caller
participant TryObj as Try<T>
participant Err as Exception
participant Matcher as type-matcher (Arrays filter)
participant RecoverMap as failureMapper
participant Result as Try<T>
Caller->>TryObj: recover(exceptionType(s), failureMapper)
TryObj->>Err: obtain current error (if any)
TryObj->>Matcher: check Err against provided exceptionType(s)
alt match found
TryObj->>RecoverMap: invoke failureMapper(Exception) -> Try<T>
RecoverMap-->>Result: mapped Try<T>
else no match or no error
TryObj-->>Result: unchanged Try<T>
end
Result-->>Caller: return Try<T>
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related issues
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
🧰 Additional context used🧬 Code graph analysis (1)src/test/java/org/zeplinko/commons/lang/ext/core/TryTest.java (1)
🔇 Additional comments (10)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/main/java/org/zeplinko/commons/lang/ext/core/Try.java(5 hunks)src/test/java/org/zeplinko/commons/lang/ext/core/TryTest.java(4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/test/java/org/zeplinko/commons/lang/ext/core/TryTest.java (2)
src/main/java/org/zeplinko/commons/lang/ext/core/Try.java (1)
Try(74-645)src/main/java/org/zeplinko/commons/lang/ext/core/AbstractOutcome.java (1)
SuppressWarnings(44-186)
🔇 Additional comments (12)
src/test/java/org/zeplinko/commons/lang/ext/core/TryTest.java (5)
320-407: LGTM! Comprehensive test coverage for conditional compose.The tests thoroughly validate the new
compose(Predicate, Function, Function)method with excellent coverage of null parameter handling, both condition outcomes, custom business logic conditions, and failure propagation scenarios.
438-497: LGTM! Thorough coverage of type-specific recovery.The tests effectively validate the single-exception-type
recovermethod, including proper null handling, exception type matching (exact and subclass), and recovery function application only when conditions are met.
600-701: LGTM! Excellent test coverage for type-specific failure handling.The tests comprehensively validate the single-exception-type
onFailuremethod, including proper chaining behavior and real-world scenarios like combining specific handlers with catch-all error handling.
703-936: LGTM! Outstanding test coverage for varargs onFailure.The tests provide comprehensive validation of the varargs
onFailuremethod, with excellent coverage of edge cases (empty arrays, null elements), multiple exception type scenarios, and real-world patterns like logging and chaining different exception groups.
957-1177: LGTM! Comprehensive test coverage for varargs recover.The tests thoroughly validate the varargs
recovermethod with excellent coverage of edge cases, multiple exception type scenarios, and chaining patterns. The test structure mirrors the varargsonFailuretests, maintaining consistency across the test suite.src/main/java/org/zeplinko/commons/lang/ext/core/Try.java (7)
5-5: LGTM! Necessary imports for new functionality.The
ArraysandPredicateimports are required for the varargs exception handling and conditional composition features respectively.Also applies to: 11-11
187-192: LGTM! Clean refactoring to eliminate duplication.The delegation to the conditional
composemethod maintains backward compatibility while eliminating code duplication. UsingTry::isSuccessas the condition preserves the original behavior.
194-257: LGTM! Well-designed conditional composition with excellent documentation.The new conditional
composemethod provides powerful flexibility for custom branching logic. The javadoc is clear with practical examples, and the implementation correctly applies the appropriate mapper based on the condition evaluation.
286-330: LGTM! Type-specific recovery with correct matching logic.The single-exception-type
recovermethod correctly implements exception type matching usingisInstance, properly handles success cases and non-matching exceptions, and delegates cleanly to the conditionalcomposemethod.
332-409: LGTM! Varargs recover enables clean multi-exception handling.Aside from the stray semicolon on line 401, the implementation correctly handles multiple exception types with a single recovery function. The null element filtering and exception type matching logic work as documented.
473-530: LGTM! Type-specific failure handling with clean implementation.The single-exception-type
onFailuremethod provides a clean way to handle specific exceptions differently (e.g., logging at different levels). The implementation correctly executes the consumer only when the Try is a failure and the exception type matches, and properly returnsthisfor chaining.
532-608: LGTM! Varargs onFailure completes the exception handling toolkit.The varargs
onFailuremethod provides a convenient way to handle multiple exception types with a single consumer. The implementation correctly filters null elements, matches exception types usinganyMatch, and maintains proper chaining behavior.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/main/java/org/zeplinko/commons/lang/ext/core/Try.java (3)
319-330: Consider clarifying the unused lambda parameter.On line 327, the lambda
currentTry -> thisreceives the success data but ignores it in favor of returning the original Try instance. While functionally correct, the parameter namecurrentTryis misleading since it receivesT(the data), notTry<T>.Consider renaming for clarity:
return compose( aTry -> aTry.isSuccess() || !exceptionType.isInstance(aTry.getError()), - currentTry -> this, + data -> this, failureMapper );This makes it clearer that the data parameter is intentionally unused.
395-408: Consider clarifying the unused lambda parameter.Similar to the single-type recover, line 405 has a lambda
currentTry -> thiswhere the parameter name is misleading.return compose( aTry -> aTry.isSuccess() || Arrays.stream(exceptionTypes) .filter(Objects::nonNull) .noneMatch(exceptionType -> exceptionType.isInstance(this.getError())), - currentTry -> this, + data -> this, failureMapper );
319-321: Note: Parameter ordering inconsistency between single-type and varargs methods.The parameter ordering differs between single-type and varargs variants:
- Single-type:
recover(Class, Function)andonFailure(Class, Consumer)- Varargs:
recover(Function, Class...)andonFailure(Consumer, Class...)While this is intentional to avoid Java overload ambiguity (as noted in the PR description), it may slightly impact API intuitiveness. Consider whether method name differentiation (e.g.,
recoverAny,onFailureAny) might provide better ergonomics by allowing consistent parameter ordering across all variants.This is noted as a design consideration rather than a required change, given the thoughtful rationale in the PR description.
Also applies to: 395-397, 519-521, 593-595
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/main/java/org/zeplinko/commons/lang/ext/core/Try.java(5 hunks)
🔇 Additional comments (5)
src/main/java/org/zeplinko/commons/lang/ext/core/Try.java (5)
5-5: LGTM!The new imports are appropriately added for the enhanced functionality.
Also applies to: 11-11
187-192: LGTM!The delegation to the new conditional compose method maintains backward compatibility while reducing code duplication.
519-529: LGTM!The implementation correctly checks the exception type and executes the consumer only when appropriate, maintaining proper null safety and method chaining.
593-607: LGTM!The varargs implementation correctly handles multiple exception types with proper null filtering and appropriate use of
anyMatchfor the matching logic.
248-257: The compose method is functioning as designed; the review comment mischaracterizes architectural flexibility as a bug.The
composemethod with customPredicate<Try<T>>is intentionally designed to allow sophisticated, caller-controlled conditions beyond simple success checks. This is not a defect:
Safe default API exists: The simple
compose(Function, Function)overload (lines 187–192) usesTry::isSuccessas the condition, ensuring alignment and eliminating null risks for standard use cases.Contract is documented: The javadoc (lines 194–247) explicitly states, "The condition has access to the entire Try instance, not just the success / failure state. This enables sophisticated branching logic beyond simple success checks." It demonstrates proper usage with conditions like
aTry -> aTry.isSuccess() && aTry.getData() > 0.Internal consistency: All internal uses within the class—
recovermethods at lines 325–329 and 401–407—pair conditions with aligned mappers (e.g., conditions checkingisSuccess()before invoking success logic).Intentional design:
getData()andgetError()returnnullwhen not applicable (success stores data with error=null, failure stores error with data=null). This is by design, not oversight.Callers invoking the condition-based overload are expected to ensure condition and mapper alignment, as documented. Violating this contract is misuse, not a platform defect.
Likely an incorrect or invalid review comment.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
@ShivamNagpal What you are about to read is entirely from LLM. I wasted some time reading this to make sure it correct wrt to the change. You also spend some time reading this 😉
Thoughts on this? Really need this exception specific recovered and handlers.
Add Exception-Type Filtering to
recover()andonFailure()MethodsSummary
This PR enhances the
Tryclass with exception-type filtering capabilities for both recovery and error handling operations. Users can now handle multiple exception types with a single handler, making error handling more concise and maintainable.Changes
1. Varargs
recover()MethodAdded a new
recovermethod that accepts multiple exception types:Example Usage:
2. Type-Specific
onFailure()MethodsAdded two new onFailure overloads for conditional side effects:
Single Exception Type:
Multiple Exception Types:
Example Usage:
Design Decisions
Parameter Ordering
The methods use different parameter orders to avoid method overloading ambiguity:
This design prevents Java compiler ambiguity while optimizing ergonomics for the most common case (single exception type).
Why Varargs for recover?
Before:
After:
This eliminates repetitive chaining when multiple exception types need the same recovery logic.
Why Type-Specific onFailure?
The onFailure methods are for side effects (logging, metrics, cleanup), not transformation. Type filtering enables:
Alternatives Considered
1. Predicate-Based onHandle()
Rejected approach:
Why rejected:
Users needing custom conditions can use the existing single-consumer onHandle():
2. Removing Single Exception recover() Method
Rejected approach: Only keep the varargs version
Why rejected:
3. Reverse Parameter Order in Single Exception recover()
Rejected approach: Make single exception match varargs order: recover(Function, Class)
Why rejected:
Breaking Changes
None. All changes are additive - existing API remains unchanged.
Questions for Reviewers
Thoughts?
Summary by CodeRabbit
New Features
Tests
Documentation