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.io.ObjectInputFilter; 026import java.io.ObjectInputFilter.FilterInfo; 027import java.io.ObjectInputFilter.Status; 028import java.io.ObjectInputStream; 029import java.util.Objects; 030import java.util.Optional; 031import java.util.concurrent.CompletionStage; 032import java.util.function.Function; 033import java.util.function.Supplier; 034 035/** 036 * Filter classes, array lengths, and graph metrics during deserialization that 037 * may throw exception. If set on an {@link ObjectInputStream}, the 038 * {@link #checkInput checkInput(FilterInfo)} method is called to validate 039 * classes, the length of each array, the number of objects being read from the 040 * stream, the depth of the graph, and the total number of bytes read from the 041 * stream. 042 * <h3>General contract</h3> 043 * <ul> 044 * <li><b>{@link #checkInput(FilterInfo) Status checkInput(FilterInfo 045 * filterInfo) throws E}</b> - The functional method.</li> 046 * <li><b>uncheck</b> - Return a {@code ObjectInputFilter}</li> 047 * <li><b>lift</b> - Return a 048 * {@code Function<FilterInfo, Optional<Status>>}</li> 049 * <li><b>ignore</b> - Return a {@code ObjectInputFilter}</li> 050 * </ul> 051 * 052 * @see ObjectInputFilter 053 * @param <E> 054 * the type of the potential exception of the function 055 * @since 2.0.0 056 */ 057@FunctionalInterface 058public interface ObjectInputFilterWithException<E extends Exception> extends 059 ObjectReturnExceptionHandlerSupport<ObjectInputFilter, Function<FilterInfo, Optional<Status>>, Function<FilterInfo, CompletionStage<Status>>, Status, ObjectInputFilterWithException<E>> { 060 061 /** 062 * Check the class, array length, number of object references, depth, stream 063 * size, and other available filtering information. Implementations of this 064 * method check the contents of the object graph being created during 065 * deserialization. The filter returns {@link Status#ALLOWED Status.ALLOWED}, 066 * {@link Status#REJECTED Status.REJECTED}, or {@link Status#UNDECIDED 067 * Status.UNDECIDED}. 068 * 069 * @param filterInfo 070 * provides information about the current object being deserialized, 071 * if any, and the status of the {@link ObjectInputStream} 072 * @return {@link Status#ALLOWED Status.ALLOWED} if accepted, 073 * {@link Status#REJECTED Status.REJECTED} if rejected, 074 * {@link Status#UNDECIDED Status.UNDECIDED} if undecided. 075 * @throws E 076 * any exception 077 * @see ObjectInputFilter#checkInput(java.io.ObjectInputFilter.FilterInfo) 078 */ 079 Status checkInput(FilterInfo filterInfo) throws E; 080 081 /** 082 * Converts this {@code ObjectInputFilterWithException} to a 083 * {@code ObjectInputFilter} that convert exception to {@code RuntimeException}. 084 * 085 * @return the unchecked ObjectInputFilter 086 * @see #unchecked(ObjectInputFilterWithException) 087 * @see #unchecked(ObjectInputFilterWithException, Function) 088 * @see ObjectInputFilter 089 */ 090 @Override 091 default ObjectInputFilter uncheck() { 092 return t -> ObjectReturnExceptionHandlerSupport.unchecked(() -> checkInput(t), throwingHandler()); 093 } 094 095 /** 096 * Converts this {@code ObjectInputFilterWithException} to a lifted 097 * {@code Function} using {@code Optional} as return value. 098 * 099 * @return the lifted function 100 * @see #lifted(ObjectInputFilterWithException) 101 * @see Function 102 */ 103 @Override 104 default Function<FilterInfo, Optional<Status>> lift() { 105 return t -> ObjectReturnExceptionHandlerSupport.unchecked(() -> Optional.ofNullable(checkInput(t)), 106 notThrowingHandler()); 107 } 108 109 @Override 110 default Status defaultValue() { 111 return Status.UNDECIDED; 112 } 113 114 /** 115 * Converts this {@code ObjectInputFilterWithException} to a lifted 116 * {@code ObjectInputFilter} returning {@link Status#UNDECIDED Status.UNDECIDED} 117 * (or the value redefined by the method {@link #defaultValue()}) in case of 118 * exception. 119 * 120 * @return the function that ignore error 121 * @see #ignored(ObjectInputFilterWithException) 122 * @see Function 123 */ 124 @Override 125 default ObjectInputFilter ignore() { 126 return t -> lift().apply(t).orElse(defaultValue()); 127 } 128 129 /** 130 * Convert this {@code ObjectInputFilterWithException} to a lifted 131 * {@code ObjectInputFilter} return {@code CompletionStage} as return value. 132 * 133 * @return the lifted function 134 * @see #staged(ObjectInputFilterWithException) 135 * @see CompletionStage 136 */ 137 @Override 138 default Function<FilterInfo, CompletionStage<Status>> stage() { 139 return t -> ObjectReturnExceptionHandlerSupport.staged(() -> checkInput(t)); 140 } 141 142 /** 143 * Returns a ObjectInputFilter that always throw exception. 144 * 145 * @param exceptionBuilder 146 * the supplier to create the ObjectInputFilter the type of the 147 * result of the function 148 * @param <E> 149 * the type of the exception 150 * @return a ObjectInputFilter that always throw exception 151 */ 152 static <E extends Exception> ObjectInputFilterWithException<E> failing(Supplier<E> exceptionBuilder) { 153 return t -> { 154 throw exceptionBuilder.get(); 155 }; 156 } 157 158 /** 159 * Converts a {@code ObjectInputFilterWithException} to a 160 * {@code ObjectInputFilter} that convert exception to {@code RuntimeException}. 161 * 162 * @param function 163 * to be unchecked 164 * @param <E> 165 * the type of the potential exception 166 * @return the unchecked exception 167 * @see #uncheck() 168 * @see #unchecked(ObjectInputFilterWithException, Function) 169 * @throws NullPointerException 170 * if function is null 171 */ 172 static <E extends Exception> ObjectInputFilter unchecked(ObjectInputFilterWithException<E> function) { 173 return verifyFunction(function).uncheck(); 174 } 175 176 /** 177 * Converts a {@code ObjectInputFilterWithException} to a 178 * {@code ObjectInputFilter} that wraps exception to {@code RuntimeException} by 179 * using the provided mapping function. 180 * 181 * @param function 182 * the be unchecked 183 * @param exceptionMapper 184 * a function to convert the exception to the runtime exception. 185 * @param <E> 186 * the type of the potential exception 187 * @return the unchecked exception 188 * @see #uncheck() 189 * @see #unchecked(ObjectInputFilterWithException) 190 * @throws NullPointerException 191 * if function or exceptionMapper is null 192 */ 193 static <E extends Exception> ObjectInputFilter unchecked(ObjectInputFilterWithException<E> function, 194 Function<Exception, RuntimeException> exceptionMapper) { 195 verifyFunction(function); 196 verifyExceptionMapper(exceptionMapper); 197 return new ObjectInputFilterWithException<E>() { 198 199 @Override 200 public Status checkInput(FilterInfo filterInfo) throws E { 201 return function.checkInput(filterInfo); 202 } 203 204 @Override 205 public Function<Exception, RuntimeException> exceptionMapper() { 206 return exceptionMapper; 207 } 208 209 }.uncheck(); 210 } 211 212 /** 213 * Converts a {@code ObjectInputFilterWithException} to a lifted 214 * {@code ObjectInputFilter} using {@code Optional} as return value. 215 * 216 * @param function 217 * to be lifted 218 * @param <E> 219 * the type of the potential exception 220 * @return the lifted function 221 * @see #lift() 222 * @throws NullPointerException 223 * if function is null 224 */ 225 static <E extends Exception> Function<FilterInfo, Optional<Status>> lifted( 226 ObjectInputFilterWithException<E> function) { 227 return verifyFunction(function).lift(); 228 } 229 230 /** 231 * Converts a {@code ObjectInputFilterWithException} to a lifted 232 * {@code ObjectInputFilter} returning {@link Status#UNDECIDED Status.UNDECIDED} 233 * in case of exception. 234 * 235 * @param function 236 * to be lifted 237 * @param <E> 238 * the type of the potential exception 239 * @return the lifted function 240 * @see #ignore() 241 * @throws NullPointerException 242 * if function is null 243 */ 244 static <E extends Exception> ObjectInputFilter ignored(ObjectInputFilterWithException<E> function) { 245 return verifyFunction(function).ignore(); 246 } 247 248 /** 249 * Converts a {@code ObjectInputFilterWithException} to a lifted 250 * {@code ObjectInputFilter} returning a default value in case of exception. 251 * 252 * @param function 253 * to be lifted 254 * @param defaultValue 255 * the default value in case of exception. <b>Can't be null</b>. 256 * @param <E> 257 * the type of the potential exception 258 * @return the lifted function 259 * @see #ignore() 260 * @see #ignored(ObjectInputFilterWithException) 261 * @throws NullPointerException 262 * if function or defaultValue is null 263 * @since 3.0.0 264 */ 265 static <E extends Exception> ObjectInputFilter ignored(ObjectInputFilterWithException<E> function, 266 Status defaultValue) { 267 verifyFunction(function); 268 Objects.requireNonNull(defaultValue, "defaultValue can't be null"); 269 return new ObjectInputFilterWithException<E>() { 270 271 @Override 272 public Status checkInput(FilterInfo filterInfo) throws E { 273 return function.checkInput(filterInfo); 274 } 275 276 @Override 277 public Status defaultValue() { 278 return defaultValue; 279 } 280 281 }.ignore(); 282 } 283 284 /** 285 * Convert this {@code ObjectInputFilterWithException} to a lifted 286 * {@code Function} return {@code CompletionStage} as return value. 287 * 288 * @param function 289 * to be lifted 290 * @param <E> 291 * the type of the potential exception 292 * @return the lifted function 293 * @see #stage() 294 * @throws NullPointerException 295 * if function is null 296 */ 297 static <E extends Exception> Function<FilterInfo, CompletionStage<Status>> staged( 298 ObjectInputFilterWithException<E> function) { 299 return verifyFunction(function).stage(); 300 } 301 302}