diff --git a/google-cloud-spanner/clirr-ignored-differences.xml b/google-cloud-spanner/clirr-ignored-differences.xml
index 94bb5870f81..46a11518dbb 100644
--- a/google-cloud-spanner/clirr-ignored-differences.xml
+++ b/google-cloud-spanner/clirr-ignored-differences.xml
@@ -1008,4 +1008,24 @@
com/google/cloud/spanner/TransactionManager
com.google.cloud.spanner.TransactionContext begin(com.google.cloud.spanner.AbortedException)
+
+ 7012
+ com/google/cloud/spanner/StructReader
+ java.lang.Object getOrNull(int, java.util.function.BiFunction)
+
+
+ 7012
+ com/google/cloud/spanner/StructReader
+ java.lang.Object getOrNull(java.lang.String, java.util.function.BiFunction)
+
+
+ 7012
+ com/google/cloud/spanner/StructReader
+ java.lang.Object getOrDefault(int, java.util.function.BiFunction, java.lang.Object)
+
+
+ 7012
+ com/google/cloud/spanner/StructReader
+ java.lang.Object getOrDefault(java.lang.String, java.util.function.BiFunction, java.lang.Object)
+
diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/StructReader.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/StructReader.java
index f690011f389..ab645588bf1 100644
--- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/StructReader.java
+++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/StructReader.java
@@ -24,6 +24,7 @@
import java.math.BigDecimal;
import java.util.List;
import java.util.UUID;
+import java.util.function.BiFunction;
import java.util.function.Function;
/**
@@ -176,6 +177,60 @@ default float getFloat(String columnName) {
*/
String getString(String columnName);
+ /**
+ * @param columnIndex index of the column
+ * @return the value of a column with type T or null if the column contains a null value
+ *
Example
+ *
{@code
+ * Struct row = ...
+ * String name = row.getOrNull(1, StructReader::getString)
+ * }
+ */
+ default T getOrNull(int columnIndex, BiFunction function) {
+ return isNull(columnIndex) ? null : function.apply(this, columnIndex);
+ }
+
+ /**
+ * @param columnName index of the column
+ * @return the value of a column with type T or null if the column contains a null value
+ * Example
+ *
{@code
+ * Struct row = ...
+ * String name = row.getOrNull("name", StructReader::getString)
+ * }
+ */
+ default T getOrNull(String columnName, BiFunction function) {
+ return isNull(columnName) ? null : function.apply(this, columnName);
+ }
+
+ /**
+ * @param columnIndex index of the column
+ * @return the value of a column with type T, or the given default if the column value is null
+ * Example
+ *
{@code
+ * Struct row = ...
+ * String name = row.getOrDefault(1, StructReader::getString, "")
+ * }
+ */
+ default T getOrDefault(
+ int columnIndex, BiFunction function, T defaultValue) {
+ return isNull(columnIndex) ? defaultValue : function.apply(this, columnIndex);
+ }
+
+ /**
+ * @param columnName name of the column
+ * @return the value of a column with type T, or the given default if the column value is null
+ * Example
+ *
{@code
+ * Struct row = ...
+ * String name = row.getOrDefault("name", StructReader::getString, "")
+ * }
+ */
+ default T getOrDefault(
+ String columnName, BiFunction function, T defaultValue) {
+ return isNull(columnName) ? defaultValue : function.apply(this, columnName);
+ }
+
/**
* @param columnIndex index of the column
* @return the value of a non-{@code NULL} column with type {@link Type#json()}.
diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/StructTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/StructTest.java
index d357a14f9d0..55d066e165e 100644
--- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/StructTest.java
+++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/StructTest.java
@@ -57,6 +57,48 @@ public void builder() {
assertThat(struct.getLong(1)).isEqualTo(2);
}
+ @Test
+ public void getOrNullTests() {
+ Struct struct =
+ Struct.newBuilder()
+ .set("f1")
+ .to("x")
+ .set("f2")
+ .to(2)
+ .set("f3")
+ .to(Value.bool(null))
+ .build();
+ String column1 = struct.getOrNull(0, StructReader::getString);
+ assertThat(column1).isEqualTo("x");
+
+ Long column2 = struct.getOrNull(1, StructReader::getLong);
+ assertThat(column2).isEqualTo(2);
+
+ String column3 = struct.getOrNull("f3", StructReader::getString);
+ assertThat(column3).isNull();
+ }
+
+ @Test
+ public void getOrDefaultTests() {
+ Struct struct =
+ Struct.newBuilder()
+ .set("f1")
+ .to("x")
+ .set("f2")
+ .to(2)
+ .set("f3")
+ .to(Value.bool(null))
+ .build();
+ String column1 = struct.getOrDefault(0, StructReader::getString, "");
+ assertThat(column1).isEqualTo("x");
+
+ Long column2 = struct.getOrDefault("f2", StructReader::getLong, -1L);
+ assertThat(column2).isEqualTo(2);
+
+ String column3 = struct.getOrDefault(2, StructReader::getString, "");
+ assertThat(column3).isEqualTo("");
+ }
+
@Test
public void duplicateFields() {
// Duplicate fields are allowed - some SQL queries produce this type of value.