com.codelanx.codelanxlib.util.exception.Exceptions.java Source code

Java tutorial

Introduction

Here is the source code for com.codelanx.codelanxlib.util.exception.Exceptions.java

Source

/*
 * Copyright (C) 2015 Codelanx, All Rights Reserved
 *
 * This work is licensed under a Creative Commons
 * Attribution-NonCommercial-NoDerivs 3.0 Unported License.
 *
 * This program is protected software: You are free to distrubute your
 * own use of this software under the terms of the Creative Commons BY-NC-ND
 * license as published by Creative Commons in the year 2015 or as published
 * by a later date. You may not provide the source files or provide a means
 * of running the software outside of those licensed to use it.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received a copy of the Creative Commons BY-NC-ND license
 * long with this program. If not, see <https://creativecommons.org/licenses/>.
 */
package com.codelanx.codelanxlib.util.exception;

import com.codelanx.codelanxlib.logging.Debugger;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;

/**
 * A utility class for throwing conditional exceptions, similar to Apache's
 * {@link org.apache.commons.lang.Validate Validate} class.
 *
 * @since 0.1.0
 * @author 1Rogue
 * @version 0.1.0
 */
public final class Exceptions {

    private Exceptions() {
    }

    /**
     * Throws an {@link IllegalArgumentException} if any of the passed arguments
     * are {@code null}
     * 
     * @since 0.1.0
     * @version 0.1.0
     * 
     * @param message The message to include in the exception
     * @param check The objects to check
     * @throws IllegalArgumentException if any checked passed argument is null
     */
    public static void allNotNull(String message, Object... check) {
        for (Object o : check) {
            if (o == null) {
                throw Exceptions.newException(IllegalArgumentException.class, message);
            }
        }
    }

    /**
     * Throws an {@link IllegalArgumentException} if any of the passed arguments
     * are {@code null}
     * 
     * @since 0.1.0
     * @version 0.1.0
     * 
     * @param check The objects to check
     * @throws IllegalArgumentException if any passed argument is null
     */
    public static void allNotNull(Object... check) {
        Exceptions.allNotNull(null, check);
    }

    /**
     * Throws an {@link IllegalStateException} if the value of the {@code state}
     * parameter is {@code false}
     *
     * @since 0.1.0
     * @version 0.1.0
     *
     * @param state The conditional to verify
     * @param message The message to include in an {@link IllegalStateException}
     * @throws IllegalStateException if {@code state} is {@code false}
     */
    public static void illegalState(boolean state, String message) {
        if (!state) {
            throw Exceptions.newException(IllegalStateException.class, message);
        }
    }

    /**
     * Throws an {@link IllegalStateException} if the value of the {@code state}
     * parameter is {@code false}
     *
     * @since 0.1.0
     * @version 0.1.0
     *
     * @param state The conditional to verify
     * @throws IllegalStateException if {@code state} is {@code false}
     */
    public static void illegalState(boolean state) {
        Exceptions.illegalState(state, null);
    }

    /**
     * Throws an {@link IllegalPluginAccessException} if the value of the
     * {@code state} parameter is {@code false}
     *
     * @since 0.1.0
     * @version 0.1.0
     *
     * @param state The conditional to verify
     * @param message The message to include in an
     * {@link IllegalPluginAccessException}
     * @throws IllegalPluginAccessException if {@code state} is {@code false}
     */
    public static void illegalPluginAccess(boolean state, String message) {
        if (!state) {
            throw Exceptions.newException(IllegalPluginAccessException.class, message);
        }
    }

    /**
     * Throws an {@link IllegalPluginAccessException} if the value of the
     * {@code state} parameter is {@code false}
     *
     * @since 0.1.0
     * @version 0.1.0
     *
     * @param state The conditional to verify
     * @throws IllegalPluginAccessException if {@code state} is {@code false}
     */
    public static void illegalPluginAccess(boolean state) {
        Exceptions.illegalPluginAccess(state, null);
    }

    /**
     * Throws an {@link UnsupportedOperationException} if the value of the
     * {@code state} parameter is {@code false}
     *
     * @since 0.1.0
     * @version 0.1.0
     *
     * @param state The conditional to verify
     * @param message The message to include in an
     *                {@link UnsupportedOperationException}
     * @throws UnsupportedOperationException if {@code state} is {@code false}
     */
    public static void unsupportedOperation(boolean state, String message) {
        if (!state) {
            throw Exceptions.newException(UnsupportedOperationException.class, message);
        }
    }

    /**
     * Throws an {@link UnsupportedOperationException} if the value of the
     * {@code state} parameter is {@code false}
     *
     * @since 0.1.0
     * @version 0.1.0
     *
     * @param state The conditional to verify
     * @throws UnsupportedOperationException if {@code state} is {@code false}
     */
    public static void unsupportedOperation(boolean state) {
        Exceptions.unsupportedOperation(state, null);
    }

    /**
     * Provides a null check, and throws a custom {@link RuntimeException} as
     * specified by the passed class parameter
     *
     * @since 0.1.0
     * @version 0.1.0
     *
     * @param <T> The exception type
     * @param obj The object to check for {@code null}
     * @param message The message to add to the exception if {@code obj} is null
     * @param ex The {@link RuntimeException} class to instantiate
     */
    public static <T extends RuntimeException> void notNull(Object obj, String message, Class<T> ex) {
        Exceptions.isTrue(obj != null, message, ex);
        if (obj == null) {
            throw Exceptions.newException(ex, message);
        }
    }

    /**
     * Provides a null check, and throws a custom {@link RuntimeException} as
     * specified by the passed class parameter
     *
     * @since 0.1.0
     * @version 0.1.0
     *
     * @param <T> The exception type
     * @param obj The object to check for {@code null}
     * @param ex The {@link RuntimeException} class to instantiate
     */
    public static <T extends RuntimeException> void notNull(Object obj, Class<T> ex) {
        Exceptions.notNull(obj, null, ex);
    }

    /**
     * Validates a statement is {@code true}, and throws a custom
     * {@link RuntimeException} as specified by the passed class parameter
     *
     * @since 0.1.0
     * @version 0.1.0
     *
     * @param <T> The exception type
     * @param validate The {@code boolean} to evaluate
     * @param message The message to add to the exception if {@code obj} is null
     * @param ex The {@link RuntimeException} class to instantiate
     */
    public static <T extends RuntimeException> void isTrue(boolean validate, String message, Class<T> ex) {
        if (!validate) {
            throw Exceptions.newException(ex, message);
        }
    }

    /**
     * Validates a statement is {@code true}, and throws a custom
     * {@link RuntimeException} as specified by the passed class parameter
     *
     * @since 0.1.0
     * @version 0.1.0
     *
     * @param <T> The exception type
     * @param validate The {@code boolean} to evaluate
     * @param ex The {@link RuntimeException} class to instantiate
     */
    public static <T extends RuntimeException> void isTrue(boolean validate, Class<T> ex) {
        Exceptions.isTrue(validate, null, ex);
    }

    /**
     * Dynamically constructs a new instance of a {@link RuntimeException}
     * either via a {@link RuntimeException#RuntimeException(String)}
     * constructor or a no-argument constructor
     *
     * @since 0.1.0
     * @version 0.1.0
     *
     * @param <T> The {@link RuntimeException} type
     * @param ex The exception class to instantiate
     * @param message The message to add, {@code null} if there is no message
     * @return The newly constructed {@link RuntimeException}
     */
    private static <T extends RuntimeException> T newException(Class<T> ex, String message) {
        if (message != null) {
            try {
                Constructor<T> c = ex.getConstructor(String.class);
                c.setAccessible(true);
                return c.newInstance(message);
            } catch (NoSuchMethodException e) {
                Debugger.print(Level.WARNING, String.format(
                        "Class '%s' does not have a String " + "message constructor! Using default constructor...",
                        ex.getName()));
            } catch (SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException
                    | InvocationTargetException e) {
                Debugger.error(e, "Error creating new exception instance");
            }
        }
        //Now try here if the previous failed or message wasn't null
        try {
            return ex.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            Debugger.error(e, "Error creating new exception instance");
        }
        throw new IllegalArgumentException(String.format(
                "Class '%s' does not have the " + "appropriate constructors to be instantiated", ex.getName()));
    }

    /**
     * Creates a readable stack trace from a passed {@link Throwable}. This
     * method will reproduce the same output that
     * {@link Throwable#printStackTrace()} would output
     *
     * @since 0.1.0
     * @version 0.1.0
     *
     * @param t The {@link Throwable} to make readable
     * @return A string representing the entire stack trace
     */
    public static String readableStackTrace(Throwable t) {
        StringBuilder sb = new StringBuilder();
        StackTraceElement[] trace = t.getStackTrace();
        for (StackTraceElement elem : trace) {
            sb.append("\tat ").append(elem).append('\n');
        }
        if (t.getCause() != null) {
            Exceptions.readableStackTraceAsCause(sb, t.getCause(), trace);
        }
        return sb.toString();
    }

    /**
     * Recursive method for appending {@link Throwable] causes that are appended
     * to a {@link Throwable}
     *
     * @since 0.1.0
     * @version 0.1.0
     *
     * @param sb The {@link StringBuilder} being appended to
     * @param t The {@link Throwable} root
     * @param causedTrace An array of already visited stack nodes
     */
    private static void readableStackTraceAsCause(StringBuilder sb, Throwable t, StackTraceElement[] causedTrace) {
        // Compute number of frames in common between previous and caused
        StackTraceElement[] trace = t.getStackTrace();
        int m = trace.length - 1;
        int n = causedTrace.length - 1;
        while (m >= 0 && n >= 0 && trace[m].equals(causedTrace[n])) {
            m--;
            n--;
        }
        int common = trace.length - 1 - m;

        sb.append("Caused by: ").append(t).append('\n');
        for (int i = 0; i <= m; i++) {
            sb.append("\tat ").append(trace[i]).append('\n');
        }
        if (common != 0) {
            sb.append("\t... ").append(common).append(" more\n");
        }
        if (t.getCause() != null) {
            Exceptions.readableStackTraceAsCause(sb, t.getCause(), trace);
        }
    }

}