1 /*
2  * Copyright (C) 2014 The Dagger 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 dagger.producers;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 
21 import com.google.common.base.Objects;
22 import com.google.errorprone.annotations.CheckReturnValue;
23 import dagger.internal.Beta;
24 import java.util.concurrent.ExecutionException;
25 import org.checkerframework.checker.nullness.compatqual.NullableDecl;
26 
27 /**
28  * An interface that represents the result of a {@linkplain Producer production} of type {@code T},
29  * or an exception that was thrown during that production. For any type {@code T} that can be
30  * injected, you can also inject {@code Produced<T>}, which enables handling of any exceptions that
31  * were thrown during the production of {@code T}.
32  *
33  * <p>For example: <pre><code>
34  *   {@literal @}Produces Html getResponse(
35  *       UserInfo criticalInfo, {@literal Produced<ExtraInfo>} noncriticalInfo) {
36  *     try {
37  *       return new Html(criticalInfo, noncriticalInfo.get());
38  *     } catch (ExecutionException e) {
39  *       logger.warning(e, "Noncritical info");
40  *       return new Html(criticalInfo);
41  *     }
42  *   }
43  * </code></pre>
44  *
45  * @since 2.0
46  */
47 @Beta
48 @CheckReturnValue
49 public abstract class Produced<T> {
50   /**
51    * Returns the result of a production.
52    *
53    * @throws ExecutionException if the production threw an exception
54    */
get()55   public abstract T get() throws ExecutionException;
56 
57   /**
58    * Two {@code Produced} objects compare equal if both are successful with equal values, or both
59    * are failed with equal exceptions.
60    */
61   @Override
equals(Object o)62   public abstract boolean equals(Object o);
63 
64   /** Returns an appropriate hash code to match {@link #equals(Object)}. */
65   @Override
hashCode()66   public abstract int hashCode();
67 
68   /** Returns a successful {@code Produced}, whose {@link #get} will return the given value. */
successful(@ullableDecl T value)69   public static <T> Produced<T> successful(@NullableDecl T value) {
70     return new Successful<T>(value);
71   }
72 
73   /**
74    * Returns a failed {@code Produced}, whose {@link #get} will throw an
75    * {@code ExecutionException} with the given cause.
76    */
failed(Throwable throwable)77   public static <T> Produced<T> failed(Throwable throwable) {
78     return new Failed<T>(checkNotNull(throwable));
79   }
80 
81   private static final class Successful<T> extends Produced<T> {
82     @NullableDecl private final T value;
83 
Successful(@ullableDecl T value)84     private Successful(@NullableDecl T value) {
85       this.value = value;
86     }
87 
88     @Override
89     @NullableDecl
get()90     public T get() {
91       return value;
92     }
93 
94     @Override
equals(Object o)95     public boolean equals(Object o) {
96       if (o == this) {
97         return true;
98       } else if (o instanceof Successful) {
99         Successful<?> that = (Successful<?>) o;
100         return Objects.equal(this.value, that.value);
101       } else {
102         return false;
103       }
104     }
105 
106     @Override
hashCode()107     public int hashCode() {
108       return value == null ? 0 : value.hashCode();
109     }
110 
111     @Override
toString()112     public String toString() {
113       return "Produced[" + value + "]";
114     }
115   }
116 
117   private static final class Failed<T> extends Produced<T> {
118     private final Throwable throwable;
119 
Failed(Throwable throwable)120     private Failed(Throwable throwable) {
121       this.throwable = checkNotNull(throwable);
122     }
123 
124     @Override
get()125     public T get() throws ExecutionException {
126       throw new ExecutionException(throwable);
127     }
128 
129     @Override
equals(Object o)130     public boolean equals(Object o) {
131       if (o == this) {
132         return true;
133       } else if (o instanceof Failed) {
134         Failed<?> that = (Failed<?>) o;
135         return this.throwable.equals(that.throwable);
136       } else {
137         return false;
138       }
139     }
140 
141     @Override
hashCode()142     public int hashCode() {
143       return throwable.hashCode();
144     }
145 
146     @Override
toString()147     public String toString() {
148       return "Produced[failed with " + throwable.getClass().getCanonicalName() + "]";
149     }
150   }
151 
Produced()152   private Produced() {}
153 }
154