• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.testing;
18 
19 import com.google.common.annotations.GwtCompatible;
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.Collection;
23 import java.util.Collections;
24 
25 /**
26  * An {@link ClusterException} is a data structure that allows for some code to "throw multiple
27  * exceptions", or something close to it. The prototypical code that calls for this class is
28  * presented below:
29  *
30  * <pre>
31  * void runManyThings({@literal List<ThingToRun>} thingsToRun) {
32  *   for (ThingToRun thingToRun : thingsToRun) {
33  *     thingToRun.run(); // say this may throw an exception, but you want to
34  *                       // always run all thingsToRun
35  *   }
36  * }
37  * </pre>
38  *
39  * <p>This is what the code would become:
40  *
41  * <pre>
42  * void runManyThings({@literal List<ThingToRun>} thingsToRun) {
43  *   {@literal List<Exception>} exceptions = Lists.newArrayList();
44  *   for (ThingToRun thingToRun : thingsToRun) {
45  *     try {
46  *       thingToRun.run();
47  *     } catch (Exception e) {
48  *       exceptions.add(e);
49  *     }
50  *   }
51  *   if (exceptions.size() &gt; 0) {
52  *     throw ClusterException.create(exceptions);
53  *   }
54  * }
55  * </pre>
56  *
57  * <p>See semantic details at {@link #create(Collection)}.
58  *
59  * @author Luiz-Otavio Zorzella
60  */
61 @GwtCompatible
62 final class ClusterException extends RuntimeException {
63 
64   public final Collection<? extends Throwable> exceptions;
65 
ClusterException(Collection<? extends Throwable> exceptions)66   private ClusterException(Collection<? extends Throwable> exceptions) {
67     super(
68         exceptions.size() + " exceptions were thrown. The first exception is listed as a cause.",
69         exceptions.iterator().next());
70     ArrayList<Throwable> temp = new ArrayList<>(exceptions);
71     this.exceptions = Collections.unmodifiableCollection(temp);
72   }
73 
74   /** @see #create(Collection) */
create(Throwable... exceptions)75   public static RuntimeException create(Throwable... exceptions) {
76     ArrayList<Throwable> temp = new ArrayList<>(Arrays.asList(exceptions));
77     return create(temp);
78   }
79 
80   /**
81    * Given a collection of exceptions, returns a {@link RuntimeException}, with the following rules:
82    *
83    * <ul>
84    *   <li>If {@code exceptions} has a single exception and that exception is a {@link
85    *       RuntimeException}, return it
86    *   <li>If {@code exceptions} has a single exceptions and that exceptions is <em>not</em> a
87    *       {@link RuntimeException}, return a simple {@code RuntimeException} that wraps it
88    *   <li>Otherwise, return an instance of {@link ClusterException} that wraps the first exception
89    *       in the {@code exceptions} collection.
90    * </ul>
91    *
92    * <p>Though this method takes any {@link Collection}, it often makes most sense to pass a {@link
93    * java.util.List} or some other collection that preserves the order in which the exceptions got
94    * added.
95    *
96    * @throws NullPointerException if {@code exceptions} is null
97    * @throws IllegalArgumentException if {@code exceptions} is empty
98    */
create(Collection<? extends Throwable> exceptions)99   public static RuntimeException create(Collection<? extends Throwable> exceptions) {
100     if (exceptions.size() == 0) {
101       throw new IllegalArgumentException("Can't create an ExceptionCollection with no exceptions");
102     }
103     if (exceptions.size() == 1) {
104       Throwable temp = exceptions.iterator().next();
105       if (temp instanceof RuntimeException) {
106         return (RuntimeException) temp;
107       } else {
108         return new RuntimeException(temp);
109       }
110     }
111     return new ClusterException(exceptions);
112   }
113 }
114