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

com.xceptance.common.lang.ThrowableUtils Maven / Gradle / Ivy

/*
 * Copyright (c) 2005-2022 Xceptance Software Technologies GmbH
 *
 * 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.xceptance.common.lang;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;

/**
 * Utility class for Throwables.
 */
public final class ThrowableUtils
{
    /**
     * The regular expression that matches the lines that appears in every failure stack trace, which can therefore be
     * used to cut off the non-interesting part of a stack trace.
     */
    private static final String CUT_OFF_REGEX = "((at (sun|(java\\.base/)?jdk\\.internal)\\.reflect\\.[^\n]+?\n\t)+"
                                                + "at (java\\.base/)?java\\.lang\\.reflect\\.[^\n]+?\n\t"
                                                + "at org\\.junit\\.runners\\.model\\.FrameworkMethod\\$1.runReflectiveCall"
                                                + ".+?)(Caused\\s+by|$)";

    /**
     * The pattern that finds the non-interesting part of a stack trace.
     */
    private static final Pattern CUT_OFF_PATTERN = Pattern.compile(CUT_OFF_REGEX, Pattern.DOTALL);

    /**
     * The regular expression string that finds dump directory information embedded in exception messages.
     */
    public static final String DIRECTORY_HINT_REGEX = " \\(user: '(.+)', output: '([0-9]+)'\\)";

    private static Field DETAIL_MESSAGE_FIELD;

    static
    {
        // HACK: make the private field "detailMessage" accessible
        try
        {
            DETAIL_MESSAGE_FIELD = Throwable.class.getDeclaredField("detailMessage");
            DETAIL_MESSAGE_FIELD.setAccessible(true);
        }
        catch (final Exception e)
        {
            DETAIL_MESSAGE_FIELD = null;
        }
    }

    /**
     * Sets the new message text at the given Throwable object.
     * 
     * @param t
     *            the throwable
     * @param message
     *            the message
     */
    public static void setMessage(final Throwable t, final String message)
    {
        if (DETAIL_MESSAGE_FIELD != null)
        {
            try
            {
                DETAIL_MESSAGE_FIELD.set(t, message);
            }
            catch (final Exception e)
            {
            }
        }
    }

    /**
     * Prefixes the message of a Throwable object with the given string.
     * 
     * @param t
     *            the throwable
     * @param messagePrefix
     *            the message prefix
     */
    public static void prefixMessage(final Throwable t, final String messagePrefix)
    {
        if (messagePrefix == null)
        {
            return;
        }

        final String originalMessage = getMessage(t);
        final String newMessage = (originalMessage == null) ? messagePrefix : messagePrefix + originalMessage;

        setMessage(t, newMessage);
    }

    /**
     * Constructor.
     */
    private ThrowableUtils()
    {
    }

    /**
     * Gets the detail message of the given throwable.
     * 
     * @param t
     *            the throwable
     * @return detail message of given throwable
     */
    public static String getMessage(final Throwable t)
    {
        if (DETAIL_MESSAGE_FIELD != null)
        {
            try
            {
                return (String) DETAIL_MESSAGE_FIELD.get(t);
            }
            catch (final Exception e)
            {
            }
        }

        return t.getMessage();
    }

    /**
     * Returns the stack trace of the given {@link Throwable} as string
     * 
     * @param t
     *            the {@link Throwable}
     * @return stack trace of given {@link Throwable}
     */
    public static String getStackTrace(final Throwable t)
    {
        final StringWriter sw = new StringWriter(400);
        final PrintWriter pw = new PrintWriter(sw);

        t.printStackTrace(pw);

        return sw.toString();
    }

    /**
     * Returns the minified (non-interesting parts cut-off) stacktrace of the given throwable.
     * 
     * @param t
     *            the throwable whose stacktrace should be minified
     * @return minified stacktrace of given throwable
     */
    public static String getMinifiedStackTrace(final Throwable t)
    {
        final String stackTrace = getStackTrace(t);

        // cut off the non-interesting part of the stack trace
        int startIdx = 0;
        final StringBuilder sb = new StringBuilder(1024);
        final Matcher matcher = CUT_OFF_PATTERN.matcher(stackTrace);
        while (matcher.find())
        {
            if (startIdx > 0)
            {
                sb.append(System.getProperty("line.separator", "\n"));
            }

            sb.append(stackTrace.substring(startIdx, matcher.start())).append("...");
            startIdx = matcher.end(1);
        }

        if (startIdx < stackTrace.length())
        {
            final String tail = stackTrace.substring(startIdx);
            if (StringUtils.isNotBlank(tail))
            {
                if (startIdx > 0)
                {
                    sb.append(System.getProperty("line.separator", "\n"));
                }

                sb.append(tail);
            }
        }

        return sb.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy