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 }