Repository: googleapis/java-storage (java)

Issue:
NPE during upload with 1.113.12
com.google.cloud:libraries-bom:19.0.0 (com.google.cloud:google-cloud-storage:jar:1.113.12), we sometimes see:

```
com.google.cloud.storage.StorageException: java.lang.NullPointerException
	at com.google.cloud.storage.StorageException.translateAndThrow(StorageException.java:81)
	at com.google.cloud.storage.BlobWriteChannel.flushBuffer(BlobWriteChannel.java:209)
	at com.google.cloud.BaseWriteChannel.close(BaseWriteChannel.java:151)
	at com.google.cloud.storage.StorageImpl.createFrom(StorageImpl.java:265)
    ...snip...
Caused by: java.lang.NullPointerException: null
	at com.google.cloud.storage.spi.v1.StorageRpc$Option.get(StorageRpc.java:85)
	at com.google.cloud.storage.spi.v1.StorageRpc$Option.getString(StorageRpc.java:89)
	at com.google.cloud.storage.spi.v1.HttpStorageRpc.setEncryptionHeaders(HttpStorageRpc.java:242)
	at com.google.cloud.storage.spi.v1.HttpStorageRpc.getCall(HttpStorageRpc.java:439)
	at com.google.cloud.storage.spi.v1.HttpStorageRpc.get(HttpStorageRpc.java:455)
	at com.google.cloud.storage.BlobWriteChannel.getRemoteStorageObject(BlobWriteChannel.java:80)
	at com.google.cloud.storage.BlobWriteChannel.access$500(BlobWriteChannel.java:33)
	at com.google.cloud.storage.BlobWriteChannel$1.run(BlobWriteChannel.java:174)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
	at com.google.api.gax.retrying.DirectRetryingExecutor.submit(DirectRetryingExecutor.java:105)
	at com.google.cloud.RetryHelper.run(RetryHelper.java:76)
	at com.google.cloud.RetryHelper.runWithRetries(RetryHelper.java:50)
	at com.google.cloud.storage.BlobWriteChannel.flushBuffer(BlobWriteChannel.java:154)
	... 31 common frames omitted
```

Same call succeeds when retried.

Pull request:
fix: npe in createFrom
createFrom expects object metadata to be available once uploaded. If response metadata is not available a get object metadata request is made with a null Options parameter which causes an NPE. I tested the change by running IT with multiple uploads to validate failure no longer occurs. 

- [x] Ensure the tests and linter pass
- [x] Code coverage does not decrease (if any source code was changed)

Fixes #745 ☕️


Patch:
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java
index aa5c3a81..09bc1708 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobWriteChannel.java
@@ -25,6 +25,7 @@ import com.google.cloud.RestorableState;
 import com.google.cloud.RetryHelper;
 import com.google.cloud.WriteChannel;
 import com.google.cloud.storage.spi.v1.StorageRpc;
+import com.google.common.collect.Maps;
 import java.net.URL;
 import java.util.Map;
 import java.util.concurrent.Callable;
@@ -77,7 +78,9 @@ class BlobWriteChannel extends BaseWriteChannel<StorageOptions, BlobInfo> {
   }
 
   private StorageObject getRemoteStorageObject() {
-    return getOptions().getStorageRpcV1().get(getEntity().toPb(), null);
+    return getOptions()
+        .getStorageRpcV1()
+        .get(getEntity().toPb(), Maps.newEnumMap(StorageRpc.Option.class));
   }
 
   private StorageException unrecoverableState(


Test patch:
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java
index ba60a3c4..d74e87d6 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobWriteChannelTest.java
@@ -40,6 +40,7 @@ import com.google.cloud.WriteChannel;
 import com.google.cloud.storage.spi.StorageRpcFactory;
 import com.google.cloud.storage.spi.v1.StorageRpc;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
 import java.io.IOException;
 import java.math.BigInteger;
 import java.net.MalformedURLException;
@@ -333,9 +334,10 @@ public class BlobWriteChannelTest {
         .andThrow(socketClosedException);
     expect(storageRpcMock.getCurrentUploadOffset(eq(UPLOAD_ID))).andReturn(-1L);
     expect(storageRpcMock.getCurrentUploadOffset(eq(UPLOAD_ID))).andReturn(-1L);
-    expect(storageRpcMock.get(BLOB_INFO.toPb(), null)).andThrow(socketClosedException);
+    expect(storageRpcMock.get(BLOB_INFO.toPb(), Maps.newEnumMap(StorageRpc.Option.class)))
+        .andThrow(socketClosedException);
     expect(storageRpcMock.getCurrentUploadOffset(eq(UPLOAD_ID))).andReturn(-1L);
-    expect(storageRpcMock.get(BLOB_INFO.toPb(), null))
+    expect(storageRpcMock.get(BLOB_INFO.toPb(), Maps.newEnumMap(StorageRpc.Option.class)))
         .andReturn(BLOB_INFO.toPb().setSize(BigInteger.valueOf(MIN_CHUNK_SIZE)));
     replay(storageRpcMock);
     writer = new BlobWriteChannel(options, BLOB_INFO, EMPTY_RPC_OPTIONS);
@@ -485,7 +487,7 @@ public class BlobWriteChannelTest {
                 eq(true)))
         .andThrow(socketClosedException);
     expect(storageRpcMock.getCurrentUploadOffset(eq(UPLOAD_ID))).andReturn(-1L);
-    expect(storageRpcMock.get(BLOB_INFO.toPb(), null))
+    expect(storageRpcMock.get(BLOB_INFO.toPb(), Maps.newEnumMap(StorageRpc.Option.class)))
         .andReturn(BLOB_INFO.toPb().setSize(BigInteger.valueOf(MIN_CHUNK_SIZE)));
     replay(storageRpcMock);
     writer = new BlobWriteChannel(options, BLOB_INFO, EMPTY_RPC_OPTIONS);