All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.landawn.abacus.util.ExceptionUtil Maven / Gradle / Ivy

Go to download

A general programming library in Java/Android. It's easy to learn and simple to use with concise and powerful APIs.

There is a newer version: 5.2.4
Show newest version
/*
 * Copyright (C) 2018 HaiYang Li
 *
 * 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 com.landawn.abacus.util;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.UndeclaredThrowableException;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;

import com.landawn.abacus.exception.UncheckedException;
import com.landawn.abacus.exception.UncheckedIOException;
import com.landawn.abacus.exception.UncheckedInterruptedException;
import com.landawn.abacus.exception.UncheckedParseException;
import com.landawn.abacus.exception.UncheckedReflectiveOperationException;
import com.landawn.abacus.exception.UncheckedSQLException;

/**
 * Note: This class contains the methods copied from Apache Commons and Google Guava under Apache License v2.
 *
 */
public final class ExceptionUtil {

    private ExceptionUtil() {
        // singleton
    }

    private static final Map, Function> toRuntimeExceptionFuncMap = new ConcurrentHashMap<>();

    static {
        toRuntimeExceptionFuncMap.put(RuntimeException.class, e -> (RuntimeException) e);

        toRuntimeExceptionFuncMap.put(Error.class, RuntimeException::new); // right or not?

        toRuntimeExceptionFuncMap.put(IOException.class, e -> new UncheckedIOException((IOException) e));

        toRuntimeExceptionFuncMap.put(SQLException.class, e -> new UncheckedSQLException((SQLException) e));

        toRuntimeExceptionFuncMap.put(ReflectiveOperationException.class, e -> new UncheckedReflectiveOperationException((ReflectiveOperationException) e));

        toRuntimeExceptionFuncMap.put(ParseException.class, e -> new UncheckedParseException((ParseException) e));

        toRuntimeExceptionFuncMap.put(InterruptedException.class, e -> new UncheckedInterruptedException((InterruptedException) e));

        toRuntimeExceptionFuncMap.put(ExecutionException.class, e -> e.getCause() == null ? new UncheckedException(e) : toRuntimeException(e.getCause()));

        toRuntimeExceptionFuncMap.put(InvocationTargetException.class,
                e -> e.getCause() == null ? new UncheckedException(e) : toRuntimeException(e.getCause()));

        toRuntimeExceptionFuncMap.put(UndeclaredThrowableException.class,
                e -> e.getCause() == null ? new UncheckedException(e) : toRuntimeException(e.getCause()));
    }

    private static final Function RUNTIME_FUNC = e -> (RuntimeException) e;

    private static final Function CHECKED_FUNC = UncheckedException::new;

    private static final String UncheckedSQLExceptionClassName = UncheckedSQLException.class.getSimpleName();

    private static final String UncheckedIOExceptionClassName = UncheckedIOException.class.getSimpleName();

    /**
     *
     * @param 
     * @param exceptionClass
     * @param runtimeExceptionMapper
     */
    public static  void registerRuntimeExceptionMapper(final Class exceptionClass,
            final Function runtimeExceptionMapper) {
        registerRuntimeExceptionMapper(exceptionClass, runtimeExceptionMapper, false);
    }

    /**
     *
     * @param 
     * @param exceptionClass
     * @param runtimeExceptionMapper
     * @param force
     */
    @SuppressWarnings("rawtypes")
    public static  void registerRuntimeExceptionMapper(final Class exceptionClass,
            final Function runtimeExceptionMapper, final boolean force) {
        N.checkArgNotNull(exceptionClass, "exceptionClass");
        N.checkArgNotNull(runtimeExceptionMapper, "runtimeExceptionMapper");

        if (toRuntimeExceptionFuncMap.containsKey(exceptionClass)) {
            if (!force) {
                throw new IllegalArgumentException("Exception class: " + ClassUtil.getCanonicalClassName(exceptionClass) + " has already been registered");
            } else if (exceptionClass.getPackage() != null && Strings.startsWithAny(exceptionClass.getPackage().getName(), "java.", "javax.")) {
                throw new IllegalArgumentException("Exception class: " + ClassUtil.getCanonicalClassName(exceptionClass)
                        + " has already been registered. Can't forcedly register class with package starting with \"java.\" or \"javax.\"");
            }
        }

        toRuntimeExceptionFuncMap.put((Class) exceptionClass, (Function) runtimeExceptionMapper);
    }

    /**
     *
     * @param e
     * @return
     */
    public static RuntimeException toRuntimeException(final Exception e) {
        final Class cls = (Class) e.getClass();
        Function func = toRuntimeExceptionFuncMap.get(cls);

        if (func == null) {
            for (Class key : toRuntimeExceptionFuncMap.keySet()) { //NOSONAR
                if (key.isAssignableFrom(cls)) {
                    func = toRuntimeExceptionFuncMap.get(key);
                    break;
                }
            }

            if (func == null) {
                if (e instanceof RuntimeException) {
                    func = RUNTIME_FUNC;
                } else {
                    func = CHECKED_FUNC;
                }
            }

            toRuntimeExceptionFuncMap.put(cls, func);
        }

        return func.apply(e);
    }

    /**
     * Converts the specified {@code Throwable} to a {@code RuntimeException} if it's a checked {@code exception} or an {@code Error}, otherwise returns itself.
     *
     * @param e
     * @return
     * @see #registerRuntimeExceptionMapper(Class, Function)
     */
    public static RuntimeException toRuntimeException(final Throwable e) {
        return toRuntimeException(e, false);
    }

    /**
     * Converts the specified {@code Throwable} to a {@code RuntimeException} if it's a checked {@code exception}, or throw it if it's an {@code Error}. Otherwise returns itself.
     *
     * @param e
     * @param throwIfItIsError
     * @return
     */
    public static RuntimeException toRuntimeException(final Throwable e, final boolean throwIfItIsError) {
        if (throwIfItIsError && e instanceof Error) {
            throw (Error) e;
        }

        final Class cls = (Class) e.getClass();
        Function func = toRuntimeExceptionFuncMap.get(cls);

        if (func == null) {
            for (Class key : toRuntimeExceptionFuncMap.keySet()) { //NOSONAR
                if (key.isAssignableFrom(cls)) {
                    func = toRuntimeExceptionFuncMap.get(key);
                    break;
                }
            }

            if (func == null) {
                if (e instanceof RuntimeException) {
                    func = RUNTIME_FUNC;
                } else {
                    func = CHECKED_FUNC;
                }
            }

            toRuntimeExceptionFuncMap.put(cls, func);
        }

        return func.apply(e);
    }

    static final java.util.function.Predicate uncheckedExceptionNameTester = Pattern.compile("Unchecked[a-zA-Z0-9]*Exception").asPredicate();
    static final Map, Class> runtimeToCheckedExceptionClassMap = new ConcurrentHashMap<>();

    /**
     * 
     *
     * @param e 
     * @return 
     */
    public static Exception tryToGetOriginalCheckedException(final Exception e) {
        if (e instanceof RuntimeException && e.getCause() != null && (!(e.getCause() instanceof RuntimeException) && (e.getCause() instanceof Exception))) {
            if (e instanceof UncheckedException //
                    || (uncheckedExceptionNameTester.test(ClassUtil.getSimpleClassName(e.getClass())))) {
                return (Exception) e.getCause();
            }

            final Throwable cause = e.getCause();

            if (runtimeToCheckedExceptionClassMap.containsKey(e.getClass()) && runtimeToCheckedExceptionClassMap.get(e.getClass()).equals(cause.getClass())) {
                return (Exception) cause;
            }

            if (toRuntimeExceptionFuncMap.containsKey(cause.getClass())
                    && toRuntimeExceptionFuncMap.get(cause.getClass()).apply(cause).getClass().equals(e.getClass())) {

                runtimeToCheckedExceptionClassMap.put(e.getClass(), cause.getClass());

                return (Exception) cause;
            }
        } else if (e.getCause() instanceof Exception && (e instanceof InvocationTargetException || e instanceof ExecutionException)) {
            return tryToGetOriginalCheckedException((Exception) e.getCause());
        }

        return e;
    }

    /**
     * 
     *
     * @param throwable 
     * @param targetExceptionType 
     * @return 
     */
    public static boolean hasCause(Throwable throwable, final Class targetExceptionType) {
        while (throwable != null) {
            if (targetExceptionType.isAssignableFrom(throwable.getClass())) {
                return true;
            }

            throwable = throwable.getCause();
        }

        return false;
    }

    /**
     * 
     *
     * @param throwable 
     * @param targetExceptionTester 
     * @return 
     */
    public static boolean hasCause(Throwable throwable, final Predicate targetExceptionTester) {
        while (throwable != null) {
            if (targetExceptionTester.test(throwable)) {
                return true;
            }

            throwable = throwable.getCause();
        }

        return false;
    }

    /**
     * 
     *
     * @param throwable 
     * @return 
     */
    public static boolean hasSQLCause(Throwable throwable) {
        while (throwable != null) {
            if (throwable instanceof SQLException || UncheckedSQLExceptionClassName.equals(throwable.getClass().getSimpleName())) {
                return true;
            }

            throwable = throwable.getCause();
        }

        return false;
    }

    /**
     * 
     *
     * @param throwable 
     * @return 
     */
    public static boolean hasIOCause(Throwable throwable) {
        while (throwable != null) {
            if (throwable instanceof IOException || UncheckedIOExceptionClassName.equals(throwable.getClass().getSimpleName())) {
                return true;
            }

            throwable = throwable.getCause();
        }

        return false;
    }

    /**
     * 
     *
     * @param throwable 
     * @return 
     */
    public static List listCause(Throwable throwable) {
        final List list = new ArrayList<>();

        while (throwable != null && !list.contains(throwable)) {
            list.add(throwable);
            throwable = throwable.getCause();
        }

        return list;
    }

    /**
     * Returns the specified {@code throwable} if there is no cause found in it ({@code throwable.getCause() == null}).
     *
     * @param throwable
     * @return
     */
    public static Throwable firstCause(final Throwable throwable) {
        Throwable result = throwable;

        while (result.getCause() != null) {
            result = result.getCause();
        }

        return result;
    }

    //-----------------------------------------------------------------------
    /**
     * 

Gets the stack trace from a Throwable as a String.

* *

The result of this method vary by JDK version as this method * uses {@link Throwable#printStackTrace(java.io.PrintWriter)}. * On JDK1.3 and earlier, the cause exception will not be shown * unless the specified throwable alters printStackTrace.

* * @param throwable the Throwable to be examined * @return * printStackTrace(PrintWriter) method */ public static String getStackTrace(final Throwable throwable) { final StringWriter sw = new StringWriter(); final PrintWriter pw = new PrintWriter(sw, true); throwable.printStackTrace(pw); return sw.getBuffer().toString(); } // /** // * Gets the error msg. // * // * @param e // * @return // * @deprecated replaced by {@link #getErrorMessage(Throwable, true)} // */ // @Deprecated // @Internal // public static String getMessage(Throwable e) { // return getErrorMessage(e, true); // } /** * * * @param e * @return */ public static String getErrorMessage(final Throwable e) { return getErrorMessage(e, false); } /** * * * @param e * @param withExceptionClassName * @return */ public static String getErrorMessage(final Throwable e, final boolean withExceptionClassName) { String msg = e.getMessage(); if (N.isNullOrEmpty(msg) && e.getCause() != null) { Throwable cause = e.getCause(); do { msg = cause.getMessage(); if (N.notNullOrEmpty(msg)) { break; } } while ((cause = e.getCause()) != null); } if (N.isNullOrEmpty(msg)) { msg = e.getClass().getCanonicalName(); } if (withExceptionClassName) { if (e instanceof SQLException) { return e.getClass().getSimpleName() + "|" + ((SQLException) e).getErrorCode() + "|" + msg; } else { return e.getClass().getSimpleName() + "|" + msg; } } else { if (e instanceof SQLException) { return ((SQLException) e).getErrorCode() + "|" + msg; } else { return msg; } } } // ---------------------------------------------------------------------------------------------> }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy