001/**
002 * Powerunit - A JDK1.8 test framework
003 * Copyright (C) 2014 Mathieu Boretti.
004 *
005 * This file is part of Powerunit
006 *
007 * Powerunit is free software: you can redistribute it and/or modify
008 * it under the terms of the GNU General Public License as published by
009 * the Free Software Foundation, either version 3 of the License, or
010 * (at your option) any later version.
011 *
012 * Powerunit is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015 * GNU General Public License for more details.
016 *
017 * You should have received a copy of the GNU General Public License
018 * along with Powerunit. If not, see <http://www.gnu.org/licenses/>.
019 */
020package ch.powerunit.extensions.exceptions;
021
022import static ch.powerunit.extensions.exceptions.Constants.verifyExceptionMapper;
023import static ch.powerunit.extensions.exceptions.Constants.verifyFunction;
024import static java.util.Objects.requireNonNull;
025
026import java.util.Optional;
027import java.util.concurrent.Callable;
028import java.util.concurrent.CompletionStage;
029import java.util.function.Function;
030import java.util.function.Supplier;
031
032/**
033 * Represents a function that accepts one argument, may throw exception and
034 * produces a result.
035 * <h3>General contract</h3>
036 * <ul>
037 * <li><b>{@link #apply(Object) R apply(T t) throws E}</b>&nbsp;-&nbsp;The
038 * functional method.</li>
039 * <li><b>uncheck</b>&nbsp;-&nbsp;Return a {@code Function<T, R>}</li>
040 * <li><b>lift</b>&nbsp;-&nbsp;Return a {@code Function<T, Optional<R>>}</li>
041 * <li><b>ignore</b>&nbsp;-&nbsp;Return a {@code Function<T, R>}</li>
042 * </ul>
043 *
044 * @see Function
045 * @param <T>
046 *            the type of the input to the function
047 * @param <R>
048 *            the type of the result of the function
049 * @param <E>
050 *            the type of the potential exception of the function
051 */
052@FunctionalInterface
053public interface FunctionWithException<T, R, E extends Exception> extends
054                ObjectReturnExceptionHandlerSupport<Function<T, R>, Function<T, Optional<R>>, Function<T, CompletionStage<R>>, R, FunctionWithException<T, R, E>> {
055
056        /**
057         * Applies this function to the given argument.
058         *
059         * @param t
060         *            the function argument
061         * @return the function result
062         * @throws E
063         *             any exception
064         * @see Function#apply(Object)
065         */
066        R apply(T t) throws E;
067
068        /**
069         * Converts this {@code FunctionWithException} to a {@code Function} that
070         * convert exception to {@code RuntimeException}.
071         *
072         * @return the unchecked function
073         * @see #unchecked(FunctionWithException)
074         * @see #unchecked(FunctionWithException, Function)
075         * @see Function
076         */
077        @Override
078        default Function<T, R> uncheck() {
079                return t -> ObjectReturnExceptionHandlerSupport.unchecked(() -> apply(t), throwingHandler());
080        }
081
082        /**
083         * Converts this {@code FunctionWithException} to a lifted {@code Function}
084         * using {@code Optional} as return value.
085         *
086         * @return the lifted function
087         * @see #lifted(FunctionWithException)
088         * @see Function
089         */
090        @Override
091        default Function<T, Optional<R>> lift() {
092                return t -> ObjectReturnExceptionHandlerSupport.unchecked(() -> Optional.ofNullable(apply(t)),
093                                notThrowingHandler());
094        }
095
096        /**
097         * Converts this {@code FunctionWithException} to a lifted {@code Function}
098         * returning {@code null} (or the value redefined by the method
099         * {@link #defaultValue()}) in case of exception.
100         *
101         * @return the function that ignore error
102         * @see #ignored(FunctionWithException)
103         * @see Function
104         */
105        @Override
106        default Function<T, R> ignore() {
107                return lift().andThen(o -> o.orElse(defaultValue()));
108        }
109
110        /**
111         * Convert this {@code FunctionWithException} to a lifted {@code Function}
112         * return {@code CompletionStage} as return value.
113         *
114         * @return the lifted function
115         * @see #staged(FunctionWithException)
116         * @see CompletionStage
117         */
118        @Override
119        default Function<T, CompletionStage<R>> stage() {
120                return t -> ObjectReturnExceptionHandlerSupport.staged(() -> apply(t));
121        }
122
123        /**
124         * Returns a composed function that first applies the {@code before} function to
125         * its input, and then applies this function to the result. If evaluation of
126         * either function throws an exception, it is relayed to the caller of the
127         * composed function.
128         *
129         * @param <V>
130         *            the type of input to the {@code before} function, and to the
131         *            composed function
132         * @param before
133         *            the function to apply before this function is applied
134         * @return a composed function that first applies the {@code before} function
135         *         and then applies this function
136         * @throws NullPointerException
137         *             if before is null
138         *
139         * @see #andThen(FunctionWithException)
140         * @see Function#compose(Function)
141         */
142        default <V> FunctionWithException<V, R, E> compose(
143                        FunctionWithException<? super V, ? extends T, ? extends E> before) {
144                requireNonNull(before);
145                return (V v) -> apply(before.apply(v));
146        }
147
148        /**
149         * Returns a composed function that first applies this function to its input,
150         * and then applies the {@code after} function to the result. If evaluation of
151         * either function throws an exception, it is relayed to the caller of the
152         * composed function.
153         *
154         * @param <V>
155         *            the type of output of the {@code after} function, and of the
156         *            composed function
157         * @param after
158         *            the function to apply after this function is applied
159         * @return a composed function that first applies this function and then applies
160         *         the {@code after} function
161         * @throws NullPointerException
162         *             if after is null *
163         * @see #compose(FunctionWithException)
164         * @see Function#andThen(Function)
165         */
166        default <V> FunctionWithException<T, V, E> andThen(
167                        FunctionWithException<? super R, ? extends V, ? extends E> after) {
168                requireNonNull(after);
169                return (T t) -> after.apply(apply(t));
170        }
171
172        /**
173         * Returns a function that always returns its input argument.
174         *
175         * @param <T>
176         *            the type of the input and output objects to the function
177         * @param <E>
178         *            the type of the potential exception
179         * @return a function that always returns its input argument
180         * @see Function#identity()
181         */
182        static <T, E extends Exception> FunctionWithException<T, T, E> identity() {
183                return t -> t;
184        }
185
186        /**
187         * Returns a function that always throw exception.
188         *
189         * @param exceptionBuilder
190         *            the supplier to create the exception
191         * @param <T>
192         *            the type of the input to the function
193         * @param <R>
194         *            the type of the result of the function
195         * @param <E>
196         *            the type of the exception
197         * @return a function that always throw exception
198         */
199        static <T, R, E extends Exception> FunctionWithException<T, R, E> failing(Supplier<E> exceptionBuilder) {
200                return t -> {
201                        throw exceptionBuilder.get();
202                };
203        }
204
205        /**
206         * Converts a {@code FunctionWithException} to a {@code Function} that convert
207         * exception to {@code RuntimeException}.
208         *
209         * @param function
210         *            to be unchecked
211         * @param <T>
212         *            the type of the input to the function
213         * @param <R>
214         *            the type of the result of the function
215         * @param <E>
216         *            the type of the potential exception
217         * @return the unchecked exception
218         * @see #uncheck()
219         * @see #unchecked(FunctionWithException, Function)
220         * @throws NullPointerException
221         *             if function is null
222         */
223        static <T, R, E extends Exception> Function<T, R> unchecked(FunctionWithException<T, R, E> function) {
224                return verifyFunction(function).uncheck();
225        }
226
227        /**
228         * Converts a {@code FunctionWithException} to a {@code Function} that wraps
229         * exception to {@code RuntimeException} by using the provided mapping function.
230         *
231         * @param function
232         *            the be unchecked
233         * @param exceptionMapper
234         *            a function to convert the exception to the runtime exception.
235         * @param <T>
236         *            the type of the input to the function
237         * @param <R>
238         *            the type of the result of the function
239         * @param <E>
240         *            the type of the potential exception
241         * @return the unchecked exception
242         * @see #uncheck()
243         * @see #unchecked(FunctionWithException)
244         * @throws NullPointerException
245         *             if function or exceptionMapper is null
246         */
247        static <T, R, E extends Exception> Function<T, R> unchecked(FunctionWithException<T, R, E> function,
248                        Function<Exception, RuntimeException> exceptionMapper) {
249                verifyFunction(function);
250                verifyExceptionMapper(exceptionMapper);
251                return new FunctionWithException<T, R, E>() {
252
253                        @Override
254                        public R apply(T t) throws E {
255                                return function.apply(t);
256                        }
257
258                        @Override
259                        public Function<Exception, RuntimeException> exceptionMapper() {
260                                return exceptionMapper;
261                        }
262
263                }.uncheck();
264        }
265
266        /**
267         * Converts a {@code FunctionWithException} to a lifted {@code Function} using
268         * {@code Optional} as return value.
269         *
270         * @param function
271         *            to be lifted
272         * @param <T>
273         *            the type of the input to the function
274         * @param <R>
275         *            the type of the result of the function
276         * @param <E>
277         *            the type of the potential exception
278         * @return the lifted function
279         * @see #lift()
280         * @throws NullPointerException
281         *             if function is null
282         */
283        static <T, R, E extends Exception> Function<T, Optional<R>> lifted(FunctionWithException<T, R, E> function) {
284                return verifyFunction(function).lift();
285        }
286
287        /**
288         * Converts a {@code FunctionWithException} to a lifted {@code Function}
289         * returning {@code null} in case of exception.
290         *
291         * @param function
292         *            to be lifted
293         * @param <T>
294         *            the type of the input to the function
295         * @param <R>
296         *            the type of the result of the function
297         * @param <E>
298         *            the type of the potential exception
299         * @return the lifted function
300         * @see #ignore()
301         * @throws NullPointerException
302         *             if function is null
303         */
304        static <T, R, E extends Exception> Function<T, R> ignored(FunctionWithException<T, R, E> function) {
305                return verifyFunction(function).ignore();
306        }
307
308        /**
309         * Converts a {@code FunctionWithException} to a lifted {@code Function}
310         * returning a default value in case of exception.
311         *
312         * @param function
313         *            to be lifted
314         * @param defaultValue
315         *            the value to be returned in case of exception.
316         * @param <T>
317         *            the type of the input to the function
318         * @param <R>
319         *            the type of the result of the function
320         * @param <E>
321         *            the type of the potential exception
322         * @return the lifted function
323         * @see #ignore()
324         * @see #ignored(FunctionWithException)
325         * @throws NullPointerException
326         *             if function is null
327         * @since 3.0.0
328         */
329        static <T, R, E extends Exception> Function<T, R> ignored(FunctionWithException<T, R, E> function, R defaultValue) {
330                verifyFunction(function);
331                return new FunctionWithException<T, R, E>() {
332
333                        @Override
334                        public R apply(T t) throws E {
335                                return function.apply(t);
336                        }
337
338                        @Override
339                        public R defaultValue() {
340                                return defaultValue;
341                        }
342
343                }.ignore();
344        }
345
346        /**
347         * Convert this {@code FunctionWithException} to a lifted {@code Function}
348         * return {@code CompletionStage} as return value.
349         *
350         * @param function
351         *            to be lifted
352         * @param <T>
353         *            the type of the input to the function
354         * @param <R>
355         *            the type of the result of the function
356         * @param <E>
357         *            the type of the potential exception
358         * @return the lifted function
359         * @see #stage()
360         * @throws NullPointerException
361         *             if function is null
362         */
363        static <T, R, E extends Exception> Function<T, CompletionStage<R>> staged(FunctionWithException<T, R, E> function) {
364                return verifyFunction(function).stage();
365        }
366
367        /**
368         * Converts a {@code FunctionWithException} to a {@code ConsumerWithException}.
369         *
370         * @param function
371         *            to be converter
372         * @param <T>
373         *            the type of the input to the function
374         * @param <R>
375         *            the type of the result of the function
376         * @param <E>
377         *            the type of the potential exception
378         * @return the consumer
379         * @throws NullPointerException
380         *             if function is null
381         * @since 1.2.0
382         */
383        static <T, R, E extends Exception> ConsumerWithException<T, E> asConsumer(FunctionWithException<T, R, E> function) {
384                return verifyFunction(function).asConsumer();
385        }
386
387        /**
388         * Converts a {@code FunctionWithException} to a {@code ConsumerWithException}.
389         *
390         * @return the consumer
391         * @since 1.2.0
392         */
393        default ConsumerWithException<T, E> asConsumer() {
394                return this::apply;
395        }
396
397        /**
398         * Converts a {@code FunctionWithException} to a
399         * {@code BiFunctionWithException}.
400         *
401         * @param function
402         *            to be converter
403         * @param <T>
404         *            the type of the input to the function
405         * @param <U>
406         *            the type of the second input to the function
407         * @param <R>
408         *            the type of the result of the function
409         * @param <E>
410         *            the type of the potential exception
411         * @return the function
412         * @throws NullPointerException
413         *             if function is null
414         * @since 1.2.0
415         */
416        static <T, U, R, E extends Exception> BiFunctionWithException<T, U, R, E> asBiFunction(
417                        FunctionWithException<T, R, E> function) {
418                return verifyFunction(function).asBiFunction();
419        }
420
421        /**
422         * Converts a {@code FunctionWithException} to a
423         * {@code BiFunctionWithException}.
424         *
425         * @param <U>
426         *            the type of the second input to the function
427         *
428         * @return the function
429         * @since 1.2.0
430         */
431        default <U> BiFunctionWithException<T, U, R, E> asBiFunction() {
432                return (t, u) -> apply(t);
433        }
434
435        /**
436         * Converts a {@code FunctionWithException} to a {@code SupplierWithException}.
437         *
438         * @param function
439         *            to be converter
440         * @param t
441         *            The input to the function.
442         * @param <T>
443         *            the type of the input to the function
444         * @param <R>
445         *            the type of the result of the function
446         * @param <E>
447         *            the type of the potential exception
448         * @return the supplier
449         * @throws NullPointerException
450         *             if function is null
451         * @since 1.2.0
452         */
453        static <T, R, E extends Exception> SupplierWithException<R, E> asSupplier(FunctionWithException<T, R, E> function,
454                        T t) {
455                return verifyFunction(function).asSupplier(t);
456        }
457
458        /**
459         * Converts a {@code FunctionWithException} to a {@code SupplierWithException}.
460         *
461         * @param t
462         *            The input to the function.
463         *
464         * @return the supplier
465         * @since 1.2.0
466         */
467        default SupplierWithException<R, E> asSupplier(T t) {
468                return () -> apply(t);
469        }
470
471        /**
472         * Converts a {@code FunctionWithException} to a {@code Callable}.
473         *
474         * @param function
475         *            to be converter
476         * @param t
477         *            The input to the function.
478         * @param <T>
479         *            the type of the input to the function
480         * @param <R>
481         *            the type of the result of the function
482         * @param <E>
483         *            the type of the potential exception
484         * @return the callable
485         * @throws NullPointerException
486         *             if function is null
487         * @since 1.2.0
488         */
489        static <T, R, E extends Exception> Callable<R> asCallable(FunctionWithException<T, R, E> function, T t) {
490                return verifyFunction(function).asCallable(t);
491        }
492
493        /**
494         * Converts a {@code FunctionWithException} to a {@code Callable}.
495         *
496         * @param t
497         *            The input to the function.
498         *
499         * @return the callable
500         * @since 1.2.0
501         */
502        default Callable<R> asCallable(T t) {
503                return () -> apply(t);
504        }
505
506        /**
507         * Converts a {@code FunctionWithException} to a {@code RunnableWithException}.
508         *
509         * @param function
510         *            to be converter
511         * @param t
512         *            The input to the function.
513         * @param <T>
514         *            the type of the input to the function
515         * @param <R>
516         *            the type of the result of the function
517         * @param <E>
518         *            the type of the potential exception
519         * @return the Runnable
520         * @throws NullPointerException
521         *             if function is null
522         * @since 1.2.0
523         */
524        static <T, R, E extends Exception> RunnableWithException<E> asRunnable(FunctionWithException<T, R, E> function,
525                        T t) {
526                return verifyFunction(function).asRunnable(t);
527        }
528
529        /**
530         * Converts a {@code FunctionWithException} to a {@code RunnableWithException}.
531         *
532         * @param t
533         *            The input to the function.
534         *
535         * @return the Runnable
536         * @since 1.2.0
537         */
538        default RunnableWithException<E> asRunnable(T t) {
539                return () -> apply(t);
540        }
541
542}