/* * Copyright 2017 OmniFaces * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ package org.omnifaces.util; import static org.omnifaces.util.Utils.isOneInstanceOf; import javax.el.ELException; import javax.faces.FacesException; import javax.servlet.ServletException; /** * <p> * Collection of general utility methods with respect to working with exceptions. So far there's only an unwrapper and * a type checker. * * <h3>Usage</h3> * <p> * Some examples: * <pre> * // Check if the caught exception has a ConstraintViolationException in its hierarchy. * catch (PersistenceException e) { * if (Exceptions.is(e, ConstraintViolationException.class)) { * // ... * } * } * </pre> * <pre> * // Unwrap the caught FacesException until a non-FacesException is found. * catch (FacesException e) { * Exception realRootCause = Exceptions.unwrap(e, FacesException.class); * // ... * } * </pre> * * @author Bauke Scholtz */ public final class Exceptions { // Constructors --------------------------------------------------------------------------------------------------- private Exceptions() { // Hide constructor. } // Utility -------------------------------------------------------------------------------------------------------- /** * Unwrap the nested causes of given exception as long as until it is not an instance of the given types and then * return it. If the given exception is already not an instance of the given types, then it will directly be * returned. Or if the exception, unwrapped or not, does not have a nested cause anymore, then it will be returned. * This is particularly useful if you want to unwrap the real root cause out of a nested hierarchy of * {@link ServletException} or {@link FacesException}. * @param exception The exception to be unwrapped. * @param types The types which need to be unwrapped. * @return The unwrapped root cause. */ @SafeVarargs public static Throwable unwrap(Throwable exception, Class<? extends Throwable>... types) { Throwable unwrappedException = exception; while (isOneInstanceOf(unwrappedException.getClass(), types) && unwrappedException.getCause() != null) { unwrappedException = unwrappedException.getCause(); } return unwrappedException; } /** * Unwrap the nested causes of given exception as long as until it is not an instance of {@link FacesException} * (Mojarra) or {@link ELException} (MyFaces) and then return it. If the given exception is already not an instance * of the mentioned types, then it will directly be returned. Or if the exception, unwrapped or not, does not have * a nested cause anymore, then it will be returned. * @param exception The exception to be unwrapped from {@link FacesException} and {@link ELException}. * @return The unwrapped root cause. * @since 1.4 */ public static Throwable unwrap(Throwable exception) { return unwrap(exception, FacesException.class, ELException.class); } /** * Returns <code>true</code> if the given exception or one of its nested causes is an instance of the given type. * @param <T> The generic throwable type. * @param exception The exception to be checked. * @param type The type to be compared to. * @return <code>true</code> if the given exception or one of its nested causes is an instance of the given type. */ public static <T extends Throwable> boolean is(Throwable exception, Class<T> type) { Throwable unwrappedException = exception; while (unwrappedException != null) { if (type.isInstance(unwrappedException)) { return true; } unwrappedException = unwrappedException.getCause(); } return false; } }