@@ -845,6 +845,82 @@ default <R> Task<R> transform(final Function1<Try<T>, Try<R>> func) {
845845 return transform ("transform: " + _taskDescriptor .getDescription (func .getClass ().getName ()), func );
846846 }
847847
848+ /**
849+ * Create a new task that will transform the result of this task.
850+ * Returned task will complete with value calculated by a task returned by the function.
851+ *
852+ * This is similar to {@link #transform(String, Function1)} except the transformation is done by executing the task returned
853+ * by the function.
854+ *
855+ * <blockquote><pre>
856+ * boolean writeToDB(String content) {...}
857+ *
858+ * Task{@code <String>} pictureBase64= ...
859+ *
860+ * // this task will complete with either complete successfully
861+ * // with uploadResult being true or false, or fail with MyLibException
862+ * Task{@code <Boolean>} uploadResult = pictureBase64.transformWith("transformUsingATask", t {@code ->} {
863+ * if (!t.isFailed()) {
864+ * return Task.blocking(() -> writeToDB(t.get()), executor));
865+ * }
866+ * return Task.failure(new MyLibException(t.getError());
867+ * });
868+ * <img src="doc-files/transformWith-1.png" height="90" width="296"/>
869+ *
870+ * @param desc description
871+ * @param func function to be applied to the result of this task which returns new task
872+ * to be executed
873+ * @param <R> value type of the returned task returned by function <code>func<</code>
874+ * @return a new task which will apply given function on result of either successful and failed completion of this task
875+ * to get instance of a task which will be executed next
876+ */
877+ default <R > Task <R > transformWith (final String desc , final Function1 <Try <T >, Task <R >> func ) {
878+ ArgumentUtil .requireNotNull (func , "function" );
879+ final Task <T > that = this ;
880+ Task <R > transformWithTask = async (desc , context -> {
881+ final SettablePromise <R > result = Promises .settable ();
882+ final Task <R > transform = async ("transform" , ctx -> {
883+ final SettablePromise <R > transformResult = Promises .settable ();
884+ if (that .isFailed () && (Exceptions .isCancellation (that .getError ()))) {
885+ //cancellations will not be propagated as other errors to the function to get the task to execute.
886+ transformResult .fail (that .getError ());
887+ }
888+ else {
889+ final Try <T > tryT = Promises .toTry (that );
890+ try {
891+ Task <R > r = func .apply (tryT );
892+ if (r == null ) {
893+ throw new RuntimeException (desc + " returned null" );
894+ }
895+ Promises .propagateResult (r , transformResult );
896+ ctx .run (r );
897+ } catch (Throwable t ) {
898+ transformResult .fail (t );
899+ }
900+ }
901+ return transformResult ;
902+ });
903+ transform .getShallowTraceBuilder ().setSystemHidden (true );
904+ transform .getShallowTraceBuilder ().setTaskType (TaskType .TRANSFORM .getName ());
905+ Promises .propagateResult (transform , result );
906+ context .after (that ).run (transform );
907+ context .run (that );
908+ return result ;
909+ });
910+ transformWithTask .getShallowTraceBuilder ().setTaskType (TaskType .WITH_TRANSFORM .getName ());
911+ return transformWithTask ;
912+
913+ }
914+
915+ /**
916+ * Equivalent to {@code transformWith("transformWith", func)}.
917+ * @see #transformWith(String, Function1)
918+ */
919+ default <R > Task <R > transformWith (final Function1 <Try <T >, Task <R >> func ) {
920+ return transformWith ("transform: " + _taskDescriptor .getDescription (func .getClass ().getName ()), func );
921+ }
922+
923+
848924 /**
849925 * Creates a new task that will handle failure of this task.
850926 * Early completion due to cancellation is not considered to be a failure so it will not be recovered.
0 commit comments