View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements. See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache license, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License. You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the license for the specific language governing permissions and
    15   * limitations under the license.
    16   */
    17  package org.apache.logging.log4j.core.util;
    18
    19  import java.io.IOException;
    20  import java.io.InterruptedIOException;
    21  import java.io.LineNumberReader;
    22  import java.io.PrintWriter;
    23  import java.io.StringReader;
    24  import java.io.StringWriter;
    25  import java.lang.reflect.InvocationTargetException;
    26  import java.lang.reflect.Method;
    27  import java.lang.reflect.UndeclaredThrowableException;
    28  import java.util.ArrayList;
    29  import java.util.List;
    30
    31  import org.apache.logging.log4j.status.StatusLogger;
    32
    33  /**
    34   * Helps with Throwable objects.
    35   */
    36  public final class Throwables {
    37
    38      private static final Method ADD_SUPPRESSED;
    39
    40      private static final Method GET_SUPPRESSED;
    41
    42      static {
    43          Method getSuppressed = null, addSuppressed = null;
    44          final Method[] methods = Throwable.class.getMethods();
    45          for (final Method method : methods) {
    46              if (method.getName().equals("getSuppressed")) {
    47                  getSuppressed = method;
    48              } else if (method.getName().equals("addSuppressed")) {
    49                  addSuppressed = method;
    50              }
    51          }
    52          GET_SUPPRESSED = getSuppressed;
    53          ADD_SUPPRESSED = addSuppressed;
    54      }
    55
    56      /**
    57       * Has no effect on Java 6 and below.
    58       *
    59       * @param throwable a Throwable
    60       * @param suppressedThrowable a suppressed Throwable
    61       * @see Throwable#addSuppressed(Throwable)
    62       * @deprecated If compiling on Java 7 and above use {@link Throwable#addSuppressed(Throwable)}. Marked as deprecated because Java 6 is
    63       *             deprecated.
    64       */
    65      @Deprecated
    66      public static void addSuppressed(final Throwable throwable, final Throwable suppressedThrowable) {
    67          if (ADD_SUPPRESSED != null) {
    68              try {
    69                  ADD_SUPPRESSED.invoke(throwable, suppressedThrowable);
    70              } catch (final IllegalAccessException e) {
    71                  // Only happens on Java >= 7 if this class has a bug.
    72                  StatusLogger.getLogger().error(e);
    73              } catch (final IllegalArgumentException e) {
    74                  // Only happens on Java >= 7 if this class has a bug.
    75                  StatusLogger.getLogger().error(e);
    76              } catch (final InvocationTargetException e) {
    77                  // Only happens on Java >= 7 if this class has a bug.
    78                  StatusLogger.getLogger().error(e);
    79              }
    80          }
    81
    82      }
    83
    84      /**
    85       * Has no effect on Java 6 and below.
    86       *
    87       * @param throwable a Throwable
    88       * @return see Java 7's {@link Throwable#getSuppressed()}
    89       * @see Throwable#getSuppressed()
    90       * @deprecated If compiling on Java 7 and above use {@link Throwable#getSuppressed()}. Marked as deprecated because Java 6 is
    91       *             deprecated.
    92       */
    93      @Deprecated
    94      public static Throwable[] getSuppressed(final Throwable throwable) {
    95          if (GET_SUPPRESSED != null) {
    96              try {
    97                  return (Throwable[]) GET_SUPPRESSED.invoke(throwable);
    98              } catch (final Exception e) {
    99                  // Only happens on Java >= 7 if this class has a bug.
    100                 StatusLogger.getLogger().error(e);
    101                 return null;
    102             }
    103         }
    104         return null;
    105     }
    106
    107     /**
    108      * Returns true if the getSuppressed method is available.
    109      *
    110      * @return True if getSuppressed is available.
    111      */
    112     public static boolean isGetSuppressedAvailable() {
    113         return GET_SUPPRESSED != null;
    114     }
    115
    116     /**
    117      * Converts a Throwable stack trace into a List of Strings
    118      *
    119      * @param throwable the Throwable
    120      * @return a List of Strings
    121      */
    122     public static List<String> toStringList(final Throwable throwable) {
    123         final StringWriter sw = new StringWriter();
    124         final PrintWriter pw = new PrintWriter(sw);
    125         try {
    126             throwable.printStackTrace(pw);
    127         } catch (final RuntimeException ex) {
    128             // Ignore any exceptions.
    129         }
    130         pw.flush();
    131         final List<String> lines = new ArrayList<String>();
    132         final LineNumberReader reader = new LineNumberReader(new StringReader(sw.toString()));
    133         try {
    134             String line = reader.readLine();
    135             while (line != null) {
    136                 lines.add(line);
    137                 line = reader.readLine();
    138             }
    139         } catch (final IOException ex) {
    140             if (ex instanceof InterruptedIOException) {
    141                 Thread.currentThread().interrupt();
    142             }
    143             lines.add(ex.toString());
    144         } finally {
    145             Closer.closeSilently(reader);
    146         }
    147         return lines;
    148     }
    149
    150     /**
    151      * Rethrows a {@link Throwable}, wrapping checked exceptions into an {@link UndeclaredThrowableException}.
    152      *
    153      * @param t the Throwable to throw.
    154      * @throws RuntimeException             if {@code t} is a RuntimeException
    155      * @throws Error                        if {@code t} is an Error
    156      * @throws UndeclaredThrowableException if {@code t} is a checked Exception
    157      * @since 2.1
    158      */
    159     public static void rethrow(final Throwable t) {
    160         if (t instanceof RuntimeException) {
    161             throw (RuntimeException) t;
    162         }
    163         if (t instanceof Error) {
    164             throw (Error) t;
    165         }
    166         throw new UndeclaredThrowableException(t);
    167     }
    168
    169     private Throwables() {
    170     }
    171
    172 }