1818
1919import static com .google .cloud .spanner .SpannerException .DoNotConstructDirectly ;
2020
21+ import com .google .api .gax .grpc .GrpcStatusCode ;
22+ import com .google .api .gax .rpc .ApiException ;
2123import com .google .common .base .MoreObjects ;
2224import com .google .common .base .Predicate ;
2325import io .grpc .Context ;
@@ -48,6 +50,28 @@ public static SpannerException propagateInterrupt(InterruptedException e) {
4850 return SpannerExceptionFactory .newSpannerException (ErrorCode .CANCELLED , "Interrupted" , e );
4951 }
5052
53+ /**
54+ * Transforms a {@code TimeoutException} to a {@code SpannerException}.
55+ *
56+ * <pre>
57+ * <code>
58+ * try {
59+ * Spanner spanner = SpannerOptions.getDefaultInstance();
60+ * spanner
61+ * .getDatabaseAdminClient()
62+ * .createDatabase("[INSTANCE_ID]", "[DATABASE_ID]", [STATEMENTS])
63+ * .get();
64+ * } catch (TimeoutException e) {
65+ * propagateTimeout(e);
66+ * }
67+ * </code>
68+ * </pre>
69+ */
70+ public static SpannerException propagateTimeout (TimeoutException e ) {
71+ return SpannerExceptionFactory .newSpannerException (
72+ ErrorCode .DEADLINE_EXCEEDED , "Operation did not complete in the given time" , e );
73+ }
74+
5175 /**
5276 * Creates a new exception based on {@code cause}.
5377 *
@@ -71,6 +95,8 @@ public static SpannerException newSpannerException(@Nullable Context context, Th
7195 return newSpannerExceptionPreformatted (e .getErrorCode (), e .getMessage (), e );
7296 } else if (cause instanceof CancellationException ) {
7397 return newSpannerExceptionForCancellation (context , cause );
98+ } else if (cause instanceof ApiException ) {
99+ return fromApiException ((ApiException ) cause );
74100 }
75101 // Extract gRPC status. This will produce "UNKNOWN" for non-gRPC exceptions.
76102 Status status = Status .fromThrowable (cause );
@@ -120,6 +146,17 @@ private static SpannerException newSpannerExceptionPreformatted(
120146 }
121147 }
122148
149+ private static SpannerException fromApiException (ApiException exception ) {
150+ Status .Code code = ((GrpcStatusCode ) exception .getStatusCode ()).getTransportCode ();
151+ ErrorCode errorCode = ErrorCode .fromGrpcStatus (Status .fromCode (code ));
152+ if (exception .getCause () != null ) {
153+ return SpannerExceptionFactory .newSpannerException (
154+ errorCode , exception .getMessage (), exception .getCause ());
155+ } else {
156+ return SpannerExceptionFactory .newSpannerException (errorCode , exception .getMessage ());
157+ }
158+ }
159+
123160 private static boolean isRetryable (ErrorCode code , @ Nullable Throwable cause ) {
124161 switch (code ) {
125162 case INTERNAL :
0 commit comments