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