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;
024
025import java.util.Optional;
026import java.util.function.Function;
027import java.util.function.Supplier;
028import java.util.function.UnaryOperator;
029
030/**
031 * Represents an operation on a single operand that produces a result of the
032 * same type as its operand. This is a specialization of
033 * {@code FunctionWithException} for the case where the operand and result are
034 * of the same type.
035 * <p>
036 * As this interface must return the same type of the input, a lifted version
037 * which returns {@code Optional} is not possible.
038 * <h3>General contract</h3>
039 * <ul>
040 * <li><b>{@link #apply(Object) T apply(T t) throws E}</b>&nbsp;-&nbsp;The
041 * functional method.</li>
042 * <li><b>uncheck</b>&nbsp;-&nbsp;Return a {@code UnaryOperator<T>}</li>
043 * <li><b>lift</b>&nbsp;-&nbsp;Return a {@code Function<T,Optional<T>}</li>
044 * <li><b>ignore</b>&nbsp;-&nbsp;Return a {@code UnaryOperator<T>}</li>
045 * </ul>
046 *
047 * @see FunctionWithException
048 * @see UnaryOperator
049 * @param <T>
050 *            the type of the operand and result of the operator
051 */
052@FunctionalInterface
053public interface UnaryOperatorWithException<T, E extends Exception> extends FunctionWithException<T, T, E> {
054
055        /**
056         * Converts this {@code UnaryOperatorWithException} to a {@code UnaryOperator}
057         * that wraps exception to {@code RuntimeException}.
058         *
059         * @return the unchecked function
060         * @see #unchecked(FunctionWithException)
061         * @see #unchecked(FunctionWithException, Function)
062         */
063        @Override
064        default UnaryOperator<T> uncheck() {
065                return t -> ObjectReturnExceptionHandlerSupport.unchecked(() -> apply(t), throwingHandler());
066        }
067
068        /**
069         * Converts this {@code UnaryOperatorWithException} to a lifted
070         * {@code UnaryOperator} returning {@code null} in case of exception.
071         *
072         * @return the function that ignore error
073         * @see #ignored(FunctionWithException)
074         */
075        @Override
076        default UnaryOperator<T> ignore() {
077                return t -> ObjectReturnExceptionHandlerSupport.unchecked(() -> apply(t), e -> null);
078        }
079
080        @Override
081        default UnaryOperatorWithException<T, E> documented(Supplier<String> toString) {
082                return (UnaryOperatorWithException<T, E>) FunctionWithException.super.documented(toString);
083        }
084
085        /**
086         * Returns a unary operator that always returns its input argument.
087         *
088         * @param <T>
089         *            the type of the input and output of the operator
090         * @param <E>
091         *            the type of the potential exception
092         * @return a unary operator that always returns its input argument
093         * @see Function#identity()
094         */
095        static <T, E extends Exception> UnaryOperatorWithException<T, E> identity() {
096                return t -> t;
097        }
098
099        /**
100         * Returns a unary operator that always throw exception.
101         *
102         * @param exceptionBuilder
103         *            the supplier to create the exception
104         * @param <T>
105         *            the type of the input and output of the operator
106         * @param <E>
107         *            the type of the exception
108         * @return a function that always throw exception
109         */
110        static <T, E extends Exception> UnaryOperatorWithException<T, E> failing(Supplier<E> exceptionBuilder) {
111                return t -> {
112                        throw exceptionBuilder.get();
113                };
114        }
115
116        /**
117         * Converts a {@code UnaryOperatorWithException} to a {@code UnaryOperator} that
118         * wraps exception to {@code RuntimeException}.
119         *
120         * @param function
121         *            to be unchecked
122         * @param <T>
123         *            the type of the input and output of the operator
124         * @param <E>
125         *            the type of the potential exception
126         * @return the unchecked exception
127         * @see #uncheck()
128         * @see #unchecked(UnaryOperatorWithException, Function)
129         * @throws NullPointerException
130         *             if function is null
131         */
132        static <T, E extends Exception> UnaryOperator<T> unchecked(UnaryOperatorWithException<T, E> function) {
133                return verifyFunction(function).uncheck();
134        }
135
136        /**
137         * Converts a {@code UnaryOperatorWithException} to a {@code UnaryOperator} that
138         * wraps exception to {@code RuntimeException} by using the provided mapping
139         * function.
140         *
141         * @param function
142         *            the be unchecked
143         * @param exceptionMapper
144         *            a function to convert the exception to the runtime exception.
145         * @param <T>
146         *            the type of the input and output of the operator
147         * @param <E>
148         *            the type of the potential exception
149         * @return the unchecked exception
150         * @see #uncheck()
151         * @see #unchecked(UnaryOperatorWithException)
152         * @throws NullPointerException
153         *             if function or exceptionMapper is null
154         */
155        static <T, E extends Exception> UnaryOperator<T> unchecked(UnaryOperatorWithException<T, E> function,
156                        Function<Exception, RuntimeException> exceptionMapper) {
157                verifyFunction(function);
158                verifyExceptionMapper(exceptionMapper);
159                return new UnaryOperatorWithException<T, E>() {
160
161                        @Override
162                        public T apply(T t) throws E {
163                                return function.apply(t);
164                        }
165
166                        @Override
167                        public Function<Exception, RuntimeException> exceptionMapper() {
168                                return exceptionMapper;
169                        }
170
171                }.uncheck();
172        }
173
174        /**
175         * Converts a {@code UnaryOperatorWithException} to a lifted {@code Function}
176         * returning {@code Optional}.
177         *
178         * @param function
179         *            to be lifted
180         * @param <T>
181         *            the type of the input and output of the operator
182         * @param <E>
183         *            the type of the potential exception
184         * @return the lifted function
185         * @see #ignore()
186         * @throws NullPointerException
187         *             if function is null
188         */
189        static <T, E extends Exception> Function<T, Optional<T>> lifted(UnaryOperatorWithException<T, E> function) {
190                return verifyFunction(function).lift();
191        }
192
193        /**
194         * Converts a {@code UnaryOperatorWithException} to a lifted
195         * {@code UnaryOperator} returning {@code null} in case of exception.
196         *
197         * @param function
198         *            to be lifted
199         * @param <T>
200         *            the type of the input and output of the operator
201         * @param <E>
202         *            the type of the potential exception
203         * @return the lifted function
204         * @see #ignore()
205         * @throws NullPointerException
206         *             if function is null
207         */
208        static <T, E extends Exception> UnaryOperator<T> ignored(UnaryOperatorWithException<T, E> function) {
209                return verifyFunction(function).ignore();
210        }
211
212}