|
1 | 1 | package com.jnape.palatable.lambda.adt;
|
2 | 2 |
|
3 | 3 | import com.jnape.palatable.lambda.adt.coproduct.CoProduct2;
|
| 4 | +import com.jnape.palatable.lambda.functions.specialized.checked.CheckedFn1; |
4 | 5 | import com.jnape.palatable.lambda.functions.specialized.checked.CheckedRunnable;
|
5 | 6 | import com.jnape.palatable.lambda.functions.specialized.checked.CheckedSupplier;
|
6 | 7 | import com.jnape.palatable.lambda.functor.Applicative;
|
|
15 | 16 | import static com.jnape.palatable.lambda.adt.Unit.UNIT;
|
16 | 17 | import static com.jnape.palatable.lambda.functions.builtin.fn1.Constantly.constantly;
|
17 | 18 | import static com.jnape.palatable.lambda.functions.builtin.fn1.Id.id;
|
| 19 | +import static com.jnape.palatable.lambda.functions.builtin.fn1.Upcast.upcast; |
18 | 20 | import static com.jnape.palatable.lambda.functions.builtin.fn2.Peek2.peek2;
|
19 | 21 |
|
20 | 22 | /**
|
@@ -246,6 +248,85 @@ public static <T extends Throwable> Try<T, Unit> trying(CheckedRunnable<T> runna
|
246 | 248 | });
|
247 | 249 | }
|
248 | 250 |
|
| 251 | + /** |
| 252 | + * Given a <code>{@link CheckedSupplier}<{@link AutoCloseable}></code> <code>aSupplier</code> and a |
| 253 | + * {@link Function} <code>fn</code>, apply <code>fn</code> to the result of <code>aSupplier</code>, ensuring |
| 254 | + * that the result has its {@link AutoCloseable#close() close} method invoked, regardless of the outcome. |
| 255 | + * <p> |
| 256 | + * If the resource creation process throws, the function body throws, or the |
| 257 | + * {@link AutoCloseable#close() close method} throws, the result is a failure. If both the function body and the |
| 258 | + * {@link AutoCloseable#close() close method} throw, the result is a failure over the function body |
| 259 | + * {@link Throwable} with the {@link AutoCloseable#close() close method} {@link Throwable} added as a |
| 260 | + * {@link Throwable#addSuppressed(Throwable) suppressed} {@link Throwable}. If only the |
| 261 | + * {@link AutoCloseable#close() close method} throws, the result is a failure over that {@link Throwable}. |
| 262 | + * <p> |
| 263 | + * Note that <code>withResources</code> calls can be nested, in which case all of the above specified exception |
| 264 | + * handling applies, where closing the previously created resource is considered part of the body of the next |
| 265 | + * <code>withResources</code> calls, and {@link Throwable Throwables} are considered suppressed in the same manner. |
| 266 | + * Additionally, {@link AutoCloseable#close() close methods} are invoked in the inverse order of resource creation. |
| 267 | + * <p> |
| 268 | + * This is {@link Try}'s equivalent of |
| 269 | + * <a href="https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html" target="_top"> |
| 270 | + * try-with-resources</a>, introduced in Java 7. |
| 271 | + * |
| 272 | + * @param aSupplier the resource supplier |
| 273 | + * @param fn the function body |
| 274 | + * @param <A> the resource type |
| 275 | + * @param <B> the function return type |
| 276 | + * @return a {@link Try} representing the result of the function's application to the resource |
| 277 | + */ |
| 278 | + public static <A extends AutoCloseable, B> Try<Exception, B> withResources( |
| 279 | + CheckedSupplier<? extends Exception, A> aSupplier, |
| 280 | + CheckedFn1<? extends Exception, ? super A, ? extends Try<? extends Exception, ? extends B>> fn) { |
| 281 | + return trying(() -> { |
| 282 | + try (A resource = aSupplier.get()) { |
| 283 | + return fn.apply(resource).<Exception, B>biMap(upcast(), upcast()); |
| 284 | + } |
| 285 | + }).flatMap(id()); |
| 286 | + } |
| 287 | + |
| 288 | + /** |
| 289 | + * Convenience overload of {@link Try#withResources(CheckedSupplier, CheckedFn1) withResources} that cascades |
| 290 | + * dependent resource creation via nested calls. |
| 291 | + * |
| 292 | + * @param aSupplier the first resource supplier |
| 293 | + * @param bFn the dependent resource function |
| 294 | + * @param fn the function body |
| 295 | + * @param <A> the first resource type |
| 296 | + * @param <B> the second resource type |
| 297 | + * @param <C> the function return type |
| 298 | + * @return a {@link Try} representing the result of the function's application to the dependent resource |
| 299 | + */ |
| 300 | + public static <A extends AutoCloseable, B extends AutoCloseable, C> Try<Exception, C> withResources( |
| 301 | + CheckedSupplier<? extends Exception, ? extends A> aSupplier, |
| 302 | + CheckedFn1<? extends Exception, ? super A, ? extends B> bFn, |
| 303 | + CheckedFn1<? extends Exception, ? super B, ? extends Try<? extends Exception, ? extends C>> fn) { |
| 304 | + return withResources(aSupplier, a -> withResources(() -> bFn.apply(a), fn::apply)); |
| 305 | + } |
| 306 | + |
| 307 | + /** |
| 308 | + * Convenience overload of {@link Try#withResources(CheckedSupplier, CheckedFn1, CheckedFn1) withResources} that |
| 309 | + * cascades |
| 310 | + * two dependent resource creations via nested calls. |
| 311 | + * |
| 312 | + * @param aSupplier the first resource supplier |
| 313 | + * @param bFn the second resource function |
| 314 | + * @param cFn the final resource function |
| 315 | + * @param fn the function body |
| 316 | + * @param <A> the first resource type |
| 317 | + * @param <B> the second resource type |
| 318 | + * @param <C> the final resource type |
| 319 | + * @param <D> the function return type |
| 320 | + * @return a {@link Try} representing the result of the function's application to the final dependent resource |
| 321 | + */ |
| 322 | + public static <A extends AutoCloseable, B extends AutoCloseable, C extends AutoCloseable, D> Try<Exception, D> withResources( |
| 323 | + CheckedSupplier<? extends Exception, ? extends A> aSupplier, |
| 324 | + CheckedFn1<? extends Exception, ? super A, ? extends B> bFn, |
| 325 | + CheckedFn1<? extends Exception, ? super B, ? extends C> cFn, |
| 326 | + CheckedFn1<? extends Exception, ? super C, ? extends Try<? extends Exception, ? extends D>> fn) { |
| 327 | + return withResources(aSupplier, bFn, b -> withResources(() -> cFn.apply(b), fn::apply)); |
| 328 | + } |
| 329 | + |
249 | 330 | private static final class Failure<T extends Throwable, A> extends Try<T, A> {
|
250 | 331 | private final T t;
|
251 | 332 |
|
|
0 commit comments