From b046e92c8fb566956faf6d035e21b7dc8f9f5833 Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Wed, 29 Jul 2026 10:30:04 -0400 Subject: [PATCH 01/11] feat(bigquery): add QueryResultsFormat and ArrowSerializationOptions configurations --- google-cloud-jar-parent/pom.xml | 2 +- .../bigquery/ArrowSerializationOptions.java | 118 ++++++++++++++++++ .../cloud/bigquery/QueryJobConfiguration.java | 47 ++++++- .../cloud/bigquery/QueryResultsFormat.java | 29 +++++ .../bigquery/QueryJobConfigurationTest.java | 29 +++++ 5 files changed, 220 insertions(+), 5 deletions(-) create mode 100644 java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java create mode 100644 java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryResultsFormat.java diff --git a/google-cloud-jar-parent/pom.xml b/google-cloud-jar-parent/pom.xml index b1e26861cab0..1f30f4f224e6 100644 --- a/google-cloud-jar-parent/pom.xml +++ b/google-cloud-jar-parent/pom.xml @@ -142,7 +142,7 @@ com.google.apis google-api-services-bigquery - v2-rev20260612-2.0.0 + v2-rev20260707-2.0.0 diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java new file mode 100644 index 000000000000..457ea4917daf --- /dev/null +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java @@ -0,0 +1,118 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.bigquery; + +import com.google.api.core.BetaApi; +import java.io.Serializable; +import java.util.Objects; + +/** Options specific to the Apache Arrow output format. */ +@BetaApi +public final class ArrowSerializationOptions implements Serializable { + + private static final long serialVersionUID = 1L; + + private final String bufferCompression; + private final String picosTimestampPrecision; + + private ArrowSerializationOptions(Builder builder) { + this.bufferCompression = builder.bufferCompression; + this.picosTimestampPrecision = builder.picosTimestampPrecision; + } + + public String getBufferCompression() { + return bufferCompression; + } + + public String getPicosTimestampPrecision() { + return picosTimestampPrecision; + } + + public static Builder newBuilder() { + return new Builder(); + } + + @Override + public String toString() { + return com.google.common.base.MoreObjects.toStringHelper(this) + .add("bufferCompression", bufferCompression) + .add("picosTimestampPrecision", picosTimestampPrecision) + .toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ArrowSerializationOptions that = (ArrowSerializationOptions) o; + return Objects.equals(bufferCompression, that.bufferCompression) + && Objects.equals(picosTimestampPrecision, that.picosTimestampPrecision); + } + + @Override + public int hashCode() { + return Objects.hash(bufferCompression, picosTimestampPrecision); + } + + com.google.api.services.bigquery.model.ArrowSerializationOptions toPb() { + com.google.api.services.bigquery.model.ArrowSerializationOptions optionsPb = + new com.google.api.services.bigquery.model.ArrowSerializationOptions(); + if (bufferCompression != null) { + optionsPb.setBufferCompression(bufferCompression); + } + if (picosTimestampPrecision != null) { + optionsPb.setPicosTimestampPrecision(picosTimestampPrecision); + } + return optionsPb; + } + + static ArrowSerializationOptions fromPb( + com.google.api.services.bigquery.model.ArrowSerializationOptions optionsPb) { + if (optionsPb == null) { + return null; + } + return newBuilder() + .setBufferCompression(optionsPb.getBufferCompression()) + .setPicosTimestampPrecision(optionsPb.getPicosTimestampPrecision()) + .build(); + } + + public static final class Builder { + private String bufferCompression; + private String picosTimestampPrecision; + + private Builder() {} + + public Builder setBufferCompression(String bufferCompression) { + this.bufferCompression = bufferCompression; + return this; + } + + public Builder setPicosTimestampPrecision(String picosTimestampPrecision) { + this.picosTimestampPrecision = picosTimestampPrecision; + return this; + } + + public ArrowSerializationOptions build() { + return new ArrowSerializationOptions(this); + } + } +} diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java index a62fbb5008d4..0d75d509d1a3 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java @@ -75,6 +75,8 @@ public final class QueryJobConfiguration extends JobConfiguration { private final Long maxResults; private final JobCreationMode jobCreationMode; private final String reservation; + private final QueryResultsFormat queryResultsFormat; + private final ArrowSerializationOptions arrowSerializationOptions; /** * Priority levels for a query. If not specified the priority is assumed to be {@link @@ -144,6 +146,8 @@ public static final class Builder private Long maxResults; private JobCreationMode jobCreationMode; private String reservation; + private QueryResultsFormat queryResultsFormat; + private ArrowSerializationOptions arrowSerializationOptions; private Builder() { super(Type.QUERY); @@ -181,6 +185,8 @@ private Builder(QueryJobConfiguration jobConfiguration) { this.maxResults = jobConfiguration.maxResults; this.jobCreationMode = jobConfiguration.jobCreationMode; this.reservation = jobConfiguration.reservation; + this.queryResultsFormat = jobConfiguration.queryResultsFormat; + this.arrowSerializationOptions = jobConfiguration.arrowSerializationOptions; } private Builder(com.google.api.services.bigquery.model.JobConfiguration configurationPb) { @@ -701,6 +707,17 @@ public Builder setReservation(String reservation) { return this; } + public Builder setQueryResultsFormat(QueryResultsFormat queryResultsFormat) { + this.queryResultsFormat = queryResultsFormat; + return this; + } + + public Builder setArrowSerializationOptions( + ArrowSerializationOptions arrowSerializationOptions) { + this.arrowSerializationOptions = arrowSerializationOptions; + return this; + } + public QueryJobConfiguration build() { return new QueryJobConfiguration(this); } @@ -747,6 +764,8 @@ private QueryJobConfiguration(Builder builder) { this.maxResults = builder.maxResults; this.jobCreationMode = builder.jobCreationMode; this.reservation = builder.reservation; + this.queryResultsFormat = builder.queryResultsFormat; + this.arrowSerializationOptions = builder.arrowSerializationOptions; } /** @@ -973,6 +992,14 @@ public Builder toBuilder() { return new Builder(this); } + public QueryResultsFormat getQueryResultsFormat() { + return queryResultsFormat; + } + + public ArrowSerializationOptions getArrowSerializationOptions() { + return arrowSerializationOptions; + } + @Override ToStringHelper toStringHelper() { return super.toStringHelper() @@ -1004,13 +1031,23 @@ ToStringHelper toStringHelper() { .add("rangePartitioning", rangePartitioning) .add("connectionProperties", connectionProperties) .add("jobCreationMode", jobCreationMode) - .add("reservation", reservation); + .add("reservation", reservation) + .add("queryResultsFormat", queryResultsFormat) + .add("arrowSerializationOptions", arrowSerializationOptions); } @Override public boolean equals(Object obj) { - return obj == this - || obj instanceof QueryJobConfiguration && baseEquals((QueryJobConfiguration) obj); + if (obj == this) { + return true; + } + if (obj == null || !(obj instanceof QueryJobConfiguration)) { + return false; + } + QueryJobConfiguration other = (QueryJobConfiguration) obj; + return baseEquals(other) + && Objects.equals(queryResultsFormat, other.queryResultsFormat) + && Objects.equals(arrowSerializationOptions, other.arrowSerializationOptions); } @Override @@ -1043,7 +1080,9 @@ public int hashCode() { labels, rangePartitioning, connectionProperties, - reservation); + reservation, + queryResultsFormat, + arrowSerializationOptions); } @Override diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryResultsFormat.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryResultsFormat.java new file mode 100644 index 000000000000..61c12d34e326 --- /dev/null +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryResultsFormat.java @@ -0,0 +1,29 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.bigquery; + +import com.google.api.core.BetaApi; + +/** The format of the query results. */ +@BetaApi +public enum QueryResultsFormat { + /** Serialized row data in Apache Arrow format. */ + ARROW, + + /** Default encoding of results as JSON struct array. */ + STRUCT_ENCODING +} diff --git a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java index 7fe41daa0608..1d60d904bfab 100644 --- a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java +++ b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java @@ -241,6 +241,35 @@ public void testJobCreationMode() { QUERY_JOB_CONFIGURATION_SET_JOB_CREATION_MODE.toBuilder().build()); } + @Test + public void testArrowConfigurations() { + QueryResultsFormat format = QueryResultsFormat.ARROW; + ArrowSerializationOptions options = + ArrowSerializationOptions.newBuilder() + .setBufferCompression("LZ4") + .setPicosTimestampPrecision("PRECISION_MILLIS") + .build(); + QueryJobConfiguration job = + QueryJobConfiguration.newBuilder(QUERY) + .setQueryResultsFormat(format) + .setArrowSerializationOptions(options) + .build(); + + assertEquals(format, job.getQueryResultsFormat()); + assertEquals(options, job.getArrowSerializationOptions()); + + // Test toBuilder + QueryJobConfiguration copiedJob = job.toBuilder().build(); + assertEquals(job, copiedJob); + assertEquals(format, copiedJob.getQueryResultsFormat()); + assertEquals(options, copiedJob.getArrowSerializationOptions()); + + // Test toPb/fromPb (not preserved) + QueryJobConfiguration jobFromPb = QueryJobConfiguration.fromPb(job.toPb()); + assertNull(jobFromPb.getQueryResultsFormat()); + assertNull(jobFromPb.getArrowSerializationOptions()); + } + private void compareQueryJobConfiguration( QueryJobConfiguration expected, QueryJobConfiguration value) { assertEquals(expected, value); From ebd2f508fafc25581863d1c20b78729a59e0a6f1 Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Fri, 7 Aug 2026 12:09:05 -0400 Subject: [PATCH 02/11] docs(bigquery): add prerequisite and behavior Javadoc for QueryResultsFormat setters --- .../cloud/bigquery/QueryJobConfiguration.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java index 0d75d509d1a3..414dae6d3ab4 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java @@ -707,11 +707,34 @@ public Builder setReservation(String reservation) { return this; } + /** + * Sets the query results response format. Defaults to {@link + * QueryResultsFormat#STRUCT_ENCODING}. + * + *

When set to {@link QueryResultsFormat#ARROW}, query results are returned in binary Apache + * Arrow format, utilizing gRPC Storage Read streams for subsequent pages. + * + *

Prerequisite: Requires the BigQuery Storage Read API ({@code + * bigquerystorage.googleapis.com}) to be enabled on your GCP project and your credentials to + * have Storage Read permissions (e.g. {@code bigquery.readsessions.create}). + * + * @param queryResultsFormat the format for query result payloads + * @return the Builder + */ public Builder setQueryResultsFormat(QueryResultsFormat queryResultsFormat) { this.queryResultsFormat = queryResultsFormat; return this; } + /** + * Sets Arrow serialization options. Defaults to null. + * + *

Note: Only applied in the request payload when {@code queryResultsFormat} is {@code + * ARROW}. + * + * @param arrowSerializationOptions the Arrow serialization options to set + * @return the Builder + */ public Builder setArrowSerializationOptions( ArrowSerializationOptions arrowSerializationOptions) { this.arrowSerializationOptions = arrowSerializationOptions; From 2a63d1f0ccb57fbe83ff16ff8f1a1bd2faf08cd4 Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Fri, 7 Aug 2026 15:48:16 -0400 Subject: [PATCH 03/11] refactor(bigquery): replace fully qualified MoreObjects path with simple import --- .../com/google/cloud/bigquery/ArrowSerializationOptions.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java index 457ea4917daf..3eb611564877 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java @@ -17,6 +17,7 @@ package com.google.cloud.bigquery; import com.google.api.core.BetaApi; +import com.google.common.base.MoreObjects; import java.io.Serializable; import java.util.Objects; @@ -48,7 +49,7 @@ public static Builder newBuilder() { @Override public String toString() { - return com.google.common.base.MoreObjects.toStringHelper(this) + return MoreObjects.toStringHelper(this) .add("bufferCompression", bufferCompression) .add("picosTimestampPrecision", picosTimestampPrecision) .toString(); From 785079ca4b9323ce4be9c66fd319a2564dbed7a3 Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Fri, 7 Aug 2026 15:53:32 -0400 Subject: [PATCH 04/11] refactor(bigquery): eliminate FQCN in ArrowSerializationOptions via converter helper --- .../bigquery/ArrowSerializationOptions.java | 20 ++------ .../ArrowSerializationOptionsConverter.java | 50 +++++++++++++++++++ 2 files changed, 53 insertions(+), 17 deletions(-) create mode 100644 java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptionsConverter.java diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java index 3eb611564877..812ec12e7e30 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java @@ -73,27 +73,13 @@ public int hashCode() { return Objects.hash(bufferCompression, picosTimestampPrecision); } - com.google.api.services.bigquery.model.ArrowSerializationOptions toPb() { - com.google.api.services.bigquery.model.ArrowSerializationOptions optionsPb = - new com.google.api.services.bigquery.model.ArrowSerializationOptions(); - if (bufferCompression != null) { - optionsPb.setBufferCompression(bufferCompression); - } - if (picosTimestampPrecision != null) { - optionsPb.setPicosTimestampPrecision(picosTimestampPrecision); - } - return optionsPb; + Object toPb() { + return ArrowSerializationOptionsConverter.toPb(this); } static ArrowSerializationOptions fromPb( com.google.api.services.bigquery.model.ArrowSerializationOptions optionsPb) { - if (optionsPb == null) { - return null; - } - return newBuilder() - .setBufferCompression(optionsPb.getBufferCompression()) - .setPicosTimestampPrecision(optionsPb.getPicosTimestampPrecision()) - .build(); + return ArrowSerializationOptionsConverter.fromPb(optionsPb); } public static final class Builder { diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptionsConverter.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptionsConverter.java new file mode 100644 index 000000000000..6b827acd96c6 --- /dev/null +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptionsConverter.java @@ -0,0 +1,50 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.bigquery; + +import com.google.api.services.bigquery.model.ArrowSerializationOptions; + +final class ArrowSerializationOptionsConverter { + + private ArrowSerializationOptionsConverter() {} + + static ArrowSerializationOptions toPb( + com.google.cloud.bigquery.ArrowSerializationOptions options) { + if (options == null) { + return null; + } + ArrowSerializationOptions optionsPb = new ArrowSerializationOptions(); + if (options.getBufferCompression() != null) { + optionsPb.setBufferCompression(options.getBufferCompression()); + } + if (options.getPicosTimestampPrecision() != null) { + optionsPb.setPicosTimestampPrecision(options.getPicosTimestampPrecision()); + } + return optionsPb; + } + + static com.google.cloud.bigquery.ArrowSerializationOptions fromPb( + ArrowSerializationOptions optionsPb) { + if (optionsPb == null) { + return null; + } + return com.google.cloud.bigquery.ArrowSerializationOptions.newBuilder() + .setBufferCompression(optionsPb.getBufferCompression()) + .setPicosTimestampPrecision(optionsPb.getPicosTimestampPrecision()) + .build(); + } +} From 44d36f71956bc8497d91383a10ea120a1125535f Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Fri, 7 Aug 2026 15:58:00 -0400 Subject: [PATCH 05/11] refactor(bigquery): return model ArrowSerializationOptions in toPb --- .../com/google/cloud/bigquery/ArrowSerializationOptions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java index 812ec12e7e30..1ad88f8de84b 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java @@ -73,7 +73,7 @@ public int hashCode() { return Objects.hash(bufferCompression, picosTimestampPrecision); } - Object toPb() { + com.google.api.services.bigquery.model.ArrowSerializationOptions toPb() { return ArrowSerializationOptionsConverter.toPb(this); } From 8a10d3bc12629a1a21fa4a7b17181bbf8d74ff99 Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Fri, 7 Aug 2026 16:26:13 -0400 Subject: [PATCH 06/11] refactor(bigquery): eliminate FQCN in ArrowSerializationOptions and ArrowSerializationOptionsConverter --- .../ArrowSerializationOptionsConverter.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptionsConverter.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptionsConverter.java index 6b827acd96c6..fc7b4bb1d419 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptionsConverter.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptionsConverter.java @@ -16,18 +16,17 @@ package com.google.cloud.bigquery; -import com.google.api.services.bigquery.model.ArrowSerializationOptions; - final class ArrowSerializationOptionsConverter { private ArrowSerializationOptionsConverter() {} - static ArrowSerializationOptions toPb( - com.google.cloud.bigquery.ArrowSerializationOptions options) { + static com.google.api.services.bigquery.model.ArrowSerializationOptions toPb( + ArrowSerializationOptions options) { if (options == null) { return null; } - ArrowSerializationOptions optionsPb = new ArrowSerializationOptions(); + com.google.api.services.bigquery.model.ArrowSerializationOptions optionsPb = + new com.google.api.services.bigquery.model.ArrowSerializationOptions(); if (options.getBufferCompression() != null) { optionsPb.setBufferCompression(options.getBufferCompression()); } @@ -37,12 +36,13 @@ static ArrowSerializationOptions toPb( return optionsPb; } - static com.google.cloud.bigquery.ArrowSerializationOptions fromPb( - ArrowSerializationOptions optionsPb) { - if (optionsPb == null) { + static ArrowSerializationOptions fromPb(Object optionsPbObj) { + if (optionsPbObj == null) { return null; } - return com.google.cloud.bigquery.ArrowSerializationOptions.newBuilder() + com.google.api.services.bigquery.model.ArrowSerializationOptions optionsPb = + (com.google.api.services.bigquery.model.ArrowSerializationOptions) optionsPbObj; + return ArrowSerializationOptions.newBuilder() .setBufferCompression(optionsPb.getBufferCompression()) .setPicosTimestampPrecision(optionsPb.getPicosTimestampPrecision()) .build(); From 05953ecfbd38a8314b1faf9dd2b6fbe718e93084 Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Mon, 10 Aug 2026 11:25:06 -0400 Subject: [PATCH 07/11] docs(bigquery): add @BetaApi annotations and [Beta] Javadoc callouts --- .../bigquery/ArrowSerializationOptions.java | 20 ++++++++++++++++++- .../cloud/bigquery/QueryJobConfiguration.java | 14 +++++++++---- .../cloud/bigquery/QueryResultsFormat.java | 2 +- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java index 1ad88f8de84b..4a995c9bc135 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java @@ -21,7 +21,7 @@ import java.io.Serializable; import java.util.Objects; -/** Options specific to the Apache Arrow output format. */ +/** [Beta] Options specific to the Apache Arrow output format. */ @BetaApi public final class ArrowSerializationOptions implements Serializable { @@ -35,14 +35,22 @@ private ArrowSerializationOptions(Builder builder) { this.picosTimestampPrecision = builder.picosTimestampPrecision; } + /** + * [Beta] Returns the buffer compression algorithm (e.g., LZ4_FRAME, ZSTD, UNCOMPRESSED). + */ + @BetaApi public String getBufferCompression() { return bufferCompression; } + /** [Beta] Returns the timestamp precision for Arrow timestamp types. */ + @BetaApi public String getPicosTimestampPrecision() { return picosTimestampPrecision; } + /** [Beta] Returns a new builder for {@link ArrowSerializationOptions}. */ + @BetaApi public static Builder newBuilder() { return new Builder(); } @@ -82,22 +90,32 @@ static ArrowSerializationOptions fromPb( return ArrowSerializationOptionsConverter.fromPb(optionsPb); } + /** [Beta] Builder for {@link ArrowSerializationOptions}. */ + @BetaApi public static final class Builder { private String bufferCompression; private String picosTimestampPrecision; private Builder() {} + /** + * [Beta] Sets the buffer compression algorithm (e.g., LZ4_FRAME, ZSTD, UNCOMPRESSED). + */ + @BetaApi public Builder setBufferCompression(String bufferCompression) { this.bufferCompression = bufferCompression; return this; } + /** [Beta] Sets the timestamp precision for Arrow timestamp types. */ + @BetaApi public Builder setPicosTimestampPrecision(String picosTimestampPrecision) { this.picosTimestampPrecision = picosTimestampPrecision; return this; } + /** [Beta] Builds a new instance of {@link ArrowSerializationOptions}. */ + @BetaApi public ArrowSerializationOptions build() { return new ArrowSerializationOptions(this); } diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java index 414dae6d3ab4..7b6d1d00b23c 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java @@ -20,6 +20,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Strings.isNullOrEmpty; +import com.google.api.core.BetaApi; import com.google.api.services.bigquery.model.JobConfigurationQuery; import com.google.api.services.bigquery.model.QueryParameter; import com.google.cloud.bigquery.JobInfo.CreateDisposition; @@ -708,26 +709,26 @@ public Builder setReservation(String reservation) { } /** - * Sets the query results response format. Defaults to {@link + * [Beta] Sets the query results response format. Defaults to {@link * QueryResultsFormat#STRUCT_ENCODING}. * *

When set to {@link QueryResultsFormat#ARROW}, query results are returned in binary Apache * Arrow format, utilizing gRPC Storage Read streams for subsequent pages. * *

Prerequisite: Requires the BigQuery Storage Read API ({@code - * bigquerystorage.googleapis.com}) to be enabled on your GCP project and your credentials to - * have Storage Read permissions (e.g. {@code bigquery.readsessions.create}). + * bigquerystorage.googleapis.com}) to be enabled on your GCP project. * * @param queryResultsFormat the format for query result payloads * @return the Builder */ + @BetaApi public Builder setQueryResultsFormat(QueryResultsFormat queryResultsFormat) { this.queryResultsFormat = queryResultsFormat; return this; } /** - * Sets Arrow serialization options. Defaults to null. + * [Beta] Sets Arrow serialization options. Defaults to null. * *

Note: Only applied in the request payload when {@code queryResultsFormat} is {@code * ARROW}. @@ -735,6 +736,7 @@ public Builder setQueryResultsFormat(QueryResultsFormat queryResultsFormat) { * @param arrowSerializationOptions the Arrow serialization options to set * @return the Builder */ + @BetaApi public Builder setArrowSerializationOptions( ArrowSerializationOptions arrowSerializationOptions) { this.arrowSerializationOptions = arrowSerializationOptions; @@ -1015,10 +1017,14 @@ public Builder toBuilder() { return new Builder(this); } + /** [Beta] Returns the query results response format. */ + @BetaApi public QueryResultsFormat getQueryResultsFormat() { return queryResultsFormat; } + /** [Beta] Returns Arrow serialization options, or null if unset. */ + @BetaApi public ArrowSerializationOptions getArrowSerializationOptions() { return arrowSerializationOptions; } diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryResultsFormat.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryResultsFormat.java index 61c12d34e326..26a8c43bba45 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryResultsFormat.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryResultsFormat.java @@ -18,7 +18,7 @@ import com.google.api.core.BetaApi; -/** The format of the query results. */ +/** [Beta] The format of the query results. */ @BetaApi public enum QueryResultsFormat { /** Serialized row data in Apache Arrow format. */ From d35e97fef771506aa339570a0fd9da92efd33cc0 Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Mon, 10 Aug 2026 15:11:01 -0400 Subject: [PATCH 08/11] feat(bigquery): add JSpecify @NullMarked and @Nullable annotations to Arrow configuration classes --- java-bigquery/google-cloud-bigquery/pom.xml | 4 ++++ .../bigquery/ArrowSerializationOptions.java | 21 +++++++++++-------- .../ArrowSerializationOptionsConverter.java | 10 ++++++--- .../cloud/bigquery/QueryResultsFormat.java | 2 ++ 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/java-bigquery/google-cloud-bigquery/pom.xml b/java-bigquery/google-cloud-bigquery/pom.xml index 2c5fc8df4e8d..6716595c1995 100644 --- a/java-bigquery/google-cloud-bigquery/pom.xml +++ b/java-bigquery/google-cloud-bigquery/pom.xml @@ -204,6 +204,10 @@ test 1.102.0-SNAPSHOT + + org.jspecify + jspecify + io.opentelemetry diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java index 4a995c9bc135..c709d0147408 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java @@ -20,15 +20,18 @@ import com.google.common.base.MoreObjects; import java.io.Serializable; import java.util.Objects; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; /** [Beta] Options specific to the Apache Arrow output format. */ @BetaApi +@NullMarked public final class ArrowSerializationOptions implements Serializable { private static final long serialVersionUID = 1L; - private final String bufferCompression; - private final String picosTimestampPrecision; + private final @Nullable String bufferCompression; + private final @Nullable String picosTimestampPrecision; private ArrowSerializationOptions(Builder builder) { this.bufferCompression = builder.bufferCompression; @@ -39,13 +42,13 @@ private ArrowSerializationOptions(Builder builder) { * [Beta] Returns the buffer compression algorithm (e.g., LZ4_FRAME, ZSTD, UNCOMPRESSED). */ @BetaApi - public String getBufferCompression() { + public @Nullable String getBufferCompression() { return bufferCompression; } /** [Beta] Returns the timestamp precision for Arrow timestamp types. */ @BetaApi - public String getPicosTimestampPrecision() { + public @Nullable String getPicosTimestampPrecision() { return picosTimestampPrecision; } @@ -64,7 +67,7 @@ public String toString() { } @Override - public boolean equals(Object o) { + public boolean equals(@Nullable Object o) { if (this == o) { return true; } @@ -93,8 +96,8 @@ static ArrowSerializationOptions fromPb( /** [Beta] Builder for {@link ArrowSerializationOptions}. */ @BetaApi public static final class Builder { - private String bufferCompression; - private String picosTimestampPrecision; + private @Nullable String bufferCompression; + private @Nullable String picosTimestampPrecision; private Builder() {} @@ -102,14 +105,14 @@ private Builder() {} * [Beta] Sets the buffer compression algorithm (e.g., LZ4_FRAME, ZSTD, UNCOMPRESSED). */ @BetaApi - public Builder setBufferCompression(String bufferCompression) { + public Builder setBufferCompression(@Nullable String bufferCompression) { this.bufferCompression = bufferCompression; return this; } /** [Beta] Sets the timestamp precision for Arrow timestamp types. */ @BetaApi - public Builder setPicosTimestampPrecision(String picosTimestampPrecision) { + public Builder setPicosTimestampPrecision(@Nullable String picosTimestampPrecision) { this.picosTimestampPrecision = picosTimestampPrecision; return this; } diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptionsConverter.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptionsConverter.java index fc7b4bb1d419..4e8aaa6e617a 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptionsConverter.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptionsConverter.java @@ -16,12 +16,16 @@ package com.google.cloud.bigquery; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked final class ArrowSerializationOptionsConverter { private ArrowSerializationOptionsConverter() {} - static com.google.api.services.bigquery.model.ArrowSerializationOptions toPb( - ArrowSerializationOptions options) { + static com.google.api.services.bigquery.model.@Nullable ArrowSerializationOptions toPb( + @Nullable ArrowSerializationOptions options) { if (options == null) { return null; } @@ -36,7 +40,7 @@ static com.google.api.services.bigquery.model.ArrowSerializationOptions toPb( return optionsPb; } - static ArrowSerializationOptions fromPb(Object optionsPbObj) { + static @Nullable ArrowSerializationOptions fromPb(@Nullable Object optionsPbObj) { if (optionsPbObj == null) { return null; } diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryResultsFormat.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryResultsFormat.java index 26a8c43bba45..5507286e880d 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryResultsFormat.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryResultsFormat.java @@ -17,9 +17,11 @@ package com.google.cloud.bigquery; import com.google.api.core.BetaApi; +import org.jspecify.annotations.NullMarked; /** [Beta] The format of the query results. */ @BetaApi +@NullMarked public enum QueryResultsFormat { /** Serialized row data in Apache Arrow format. */ ARROW, From dd0e11dceeb7e26cf73732bfbe5120c6101cd956 Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Mon, 10 Aug 2026 15:20:17 -0400 Subject: [PATCH 09/11] feat(bigquery): enforce non-null parameters in ArrowSerializationOptions.Builder and clarify Javadocs --- .../bigquery/ArrowSerializationOptions.java | 29 +++++++++++++++---- .../cloud/bigquery/QueryJobConfiguration.java | 4 ++- .../bigquery/QueryJobConfigurationTest.java | 16 ++++++++++ 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java index c709d0147408..284c43917603 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java @@ -16,6 +16,8 @@ package com.google.cloud.bigquery; +import static com.google.common.base.Preconditions.checkNotNull; + import com.google.api.core.BetaApi; import com.google.common.base.MoreObjects; import java.io.Serializable; @@ -46,7 +48,14 @@ private ArrowSerializationOptions(Builder builder) { return bufferCompression; } - /** [Beta] Returns the timestamp precision for Arrow timestamp types. */ + /** + * [Beta] Returns the timestamp precision for Arrow timestamp types. + * + *

Note: Only applies when {@link QueryResultsFormat#ARROW} is enabled. For Arrow result + * streams, this precision setting governs binary Arrow timestamp column types and takes + * precedence over {@link DataFormatOptions.TimestampFormatOptions}, which applies to default + * {@link QueryResultsFormat#STRUCT_ENCODING} JSON results. + */ @BetaApi public @Nullable String getPicosTimestampPrecision() { return picosTimestampPrecision; @@ -105,15 +114,23 @@ private Builder() {} * [Beta] Sets the buffer compression algorithm (e.g., LZ4_FRAME, ZSTD, UNCOMPRESSED). */ @BetaApi - public Builder setBufferCompression(@Nullable String bufferCompression) { - this.bufferCompression = bufferCompression; + public Builder setBufferCompression(String bufferCompression) { + this.bufferCompression = checkNotNull(bufferCompression, "bufferCompression cannot be null"); return this; } - /** [Beta] Sets the timestamp precision for Arrow timestamp types. */ + /** + * [Beta] Sets the timestamp precision for Arrow timestamp types. + * + *

Note: Only applies when {@link QueryResultsFormat#ARROW} is enabled. For Arrow result + * streams, this precision setting governs binary Arrow timestamp column types and takes + * precedence over {@link DataFormatOptions.TimestampFormatOptions}, which applies to default + * {@link QueryResultsFormat#STRUCT_ENCODING} JSON results. + */ @BetaApi - public Builder setPicosTimestampPrecision(@Nullable String picosTimestampPrecision) { - this.picosTimestampPrecision = picosTimestampPrecision; + public Builder setPicosTimestampPrecision(String picosTimestampPrecision) { + this.picosTimestampPrecision = + checkNotNull(picosTimestampPrecision, "picosTimestampPrecision cannot be null"); return this; } diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java index 7b6d1d00b23c..067cd078eee8 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java @@ -716,7 +716,9 @@ public Builder setReservation(String reservation) { * Arrow format, utilizing gRPC Storage Read streams for subsequent pages. * *

Prerequisite: Requires the BigQuery Storage Read API ({@code - * bigquerystorage.googleapis.com}) to be enabled on your GCP project. + * bigquerystorage.googleapis.com}) to be enabled on your GCP project. See the Google Cloud + * Enabling APIs Guide. * * @param queryResultsFormat the format for query result payloads * @return the Builder diff --git a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java index 1d60d904bfab..82c35c44bb36 100644 --- a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java +++ b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java @@ -19,6 +19,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import com.google.cloud.bigquery.JobInfo.CreateDisposition; import com.google.cloud.bigquery.JobInfo.SchemaUpdateOption; @@ -270,6 +271,21 @@ public void testArrowConfigurations() { assertNull(jobFromPb.getArrowSerializationOptions()); } + @Test + public void testArrowSerializationOptionsNullChecks() { + ArrowSerializationOptions.Builder builder = ArrowSerializationOptions.newBuilder(); + assertNull(builder.build().getBufferCompression()); + assertNull(builder.build().getPicosTimestampPrecision()); + + NullPointerException ex1 = + assertThrows(NullPointerException.class, () -> builder.setBufferCompression(null)); + assertEquals("bufferCompression cannot be null", ex1.getMessage()); + + NullPointerException ex2 = + assertThrows(NullPointerException.class, () -> builder.setPicosTimestampPrecision(null)); + assertEquals("picosTimestampPrecision cannot be null", ex2.getMessage()); + } + private void compareQueryJobConfiguration( QueryJobConfiguration expected, QueryJobConfiguration value) { assertEquals(expected, value); From 44e8fad195ab7f759f2d2708b5dc1a1b23e75641 Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Tue, 11 Aug 2026 12:11:29 -0400 Subject: [PATCH 10/11] feat(bigquery): wrap Arrow options in enums and enforce non-null parameters --- .../bigquery/ArrowSerializationOptions.java | 71 ++++++++++++++++--- .../ArrowSerializationOptionsConverter.java | 32 ++++++--- .../cloud/bigquery/QueryJobConfiguration.java | 6 +- .../bigquery/QueryJobConfigurationTest.java | 26 +++++-- 4 files changed, 108 insertions(+), 27 deletions(-) diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java index 284c43917603..22792c7e80c6 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java @@ -32,8 +32,55 @@ public final class ArrowSerializationOptions implements Serializable { private static final long serialVersionUID = 1L; - private final @Nullable String bufferCompression; - private final @Nullable String picosTimestampPrecision; + /** [Beta] Buffer compression codec for Apache Arrow record batches. */ + @BetaApi + public enum CompressionCodec { + UNCOMPRESSED("UNCOMPRESSED"), + LZ4_FRAME("LZ4_FRAME"), + ZSTD("ZSTD"); + + private final String value; + + CompressionCodec(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return value; + } + } + + /** [Beta] Timestamp precision for Apache Arrow timestamp types. */ + @BetaApi + public enum TimestampPrecision { + PRECISION_MILLIS("PRECISION_MILLIS"), + PRECISION_MICROS("PRECISION_MICROS"), + PRECISION_NANOS("PRECISION_NANOS"), + PRECISION_PICOS("PRECISION_PICOS"); + + private final String value; + + TimestampPrecision(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return value; + } + } + + private final CompressionCodec bufferCompression; + private final TimestampPrecision picosTimestampPrecision; private ArrowSerializationOptions(Builder builder) { this.bufferCompression = builder.bufferCompression; @@ -42,14 +89,16 @@ private ArrowSerializationOptions(Builder builder) { /** * [Beta] Returns the buffer compression algorithm (e.g., LZ4_FRAME, ZSTD, UNCOMPRESSED). + * Defaults to {@link CompressionCodec#UNCOMPRESSED}. */ @BetaApi - public @Nullable String getBufferCompression() { + public CompressionCodec getBufferCompression() { return bufferCompression; } /** - * [Beta] Returns the timestamp precision for Arrow timestamp types. + * [Beta] Returns the timestamp precision for Arrow timestamp types. Defaults to {@link + * TimestampPrecision#PRECISION_MICROS}. * *

Note: Only applies when {@link QueryResultsFormat#ARROW} is enabled. For Arrow result * streams, this precision setting governs binary Arrow timestamp column types and takes @@ -57,7 +106,7 @@ private ArrowSerializationOptions(Builder builder) { * {@link QueryResultsFormat#STRUCT_ENCODING} JSON results. */ @BetaApi - public @Nullable String getPicosTimestampPrecision() { + public TimestampPrecision getPicosTimestampPrecision() { return picosTimestampPrecision; } @@ -84,8 +133,8 @@ public boolean equals(@Nullable Object o) { return false; } ArrowSerializationOptions that = (ArrowSerializationOptions) o; - return Objects.equals(bufferCompression, that.bufferCompression) - && Objects.equals(picosTimestampPrecision, that.picosTimestampPrecision); + return bufferCompression == that.bufferCompression + && picosTimestampPrecision == that.picosTimestampPrecision; } @Override @@ -105,8 +154,8 @@ static ArrowSerializationOptions fromPb( /** [Beta] Builder for {@link ArrowSerializationOptions}. */ @BetaApi public static final class Builder { - private @Nullable String bufferCompression; - private @Nullable String picosTimestampPrecision; + private CompressionCodec bufferCompression = CompressionCodec.UNCOMPRESSED; + private TimestampPrecision picosTimestampPrecision = TimestampPrecision.PRECISION_MICROS; private Builder() {} @@ -114,7 +163,7 @@ private Builder() {} * [Beta] Sets the buffer compression algorithm (e.g., LZ4_FRAME, ZSTD, UNCOMPRESSED). */ @BetaApi - public Builder setBufferCompression(String bufferCompression) { + public Builder setBufferCompression(CompressionCodec bufferCompression) { this.bufferCompression = checkNotNull(bufferCompression, "bufferCompression cannot be null"); return this; } @@ -128,7 +177,7 @@ public Builder setBufferCompression(String bufferCompression) { * {@link QueryResultsFormat#STRUCT_ENCODING} JSON results. */ @BetaApi - public Builder setPicosTimestampPrecision(String picosTimestampPrecision) { + public Builder setPicosTimestampPrecision(TimestampPrecision picosTimestampPrecision) { this.picosTimestampPrecision = checkNotNull(picosTimestampPrecision, "picosTimestampPrecision cannot be null"); return this; diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptionsConverter.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptionsConverter.java index 4e8aaa6e617a..07ef882ae9a1 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptionsConverter.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptionsConverter.java @@ -31,12 +31,8 @@ private ArrowSerializationOptionsConverter() {} } com.google.api.services.bigquery.model.ArrowSerializationOptions optionsPb = new com.google.api.services.bigquery.model.ArrowSerializationOptions(); - if (options.getBufferCompression() != null) { - optionsPb.setBufferCompression(options.getBufferCompression()); - } - if (options.getPicosTimestampPrecision() != null) { - optionsPb.setPicosTimestampPrecision(options.getPicosTimestampPrecision()); - } + optionsPb.setBufferCompression(options.getBufferCompression().getValue()); + optionsPb.setPicosTimestampPrecision(options.getPicosTimestampPrecision().getValue()); return optionsPb; } @@ -46,9 +42,25 @@ private ArrowSerializationOptionsConverter() {} } com.google.api.services.bigquery.model.ArrowSerializationOptions optionsPb = (com.google.api.services.bigquery.model.ArrowSerializationOptions) optionsPbObj; - return ArrowSerializationOptions.newBuilder() - .setBufferCompression(optionsPb.getBufferCompression()) - .setPicosTimestampPrecision(optionsPb.getPicosTimestampPrecision()) - .build(); + ArrowSerializationOptions.Builder builder = ArrowSerializationOptions.newBuilder(); + if (optionsPb.getBufferCompression() != null) { + for (ArrowSerializationOptions.CompressionCodec codec : + ArrowSerializationOptions.CompressionCodec.values()) { + if (codec.getValue().equalsIgnoreCase(optionsPb.getBufferCompression())) { + builder.setBufferCompression(codec); + break; + } + } + } + if (optionsPb.getPicosTimestampPrecision() != null) { + for (ArrowSerializationOptions.TimestampPrecision precision : + ArrowSerializationOptions.TimestampPrecision.values()) { + if (precision.getValue().equalsIgnoreCase(optionsPb.getPicosTimestampPrecision())) { + builder.setPicosTimestampPrecision(precision); + break; + } + } + } + return builder.build(); } } diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java index 067cd078eee8..c2044222d637 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java @@ -725,7 +725,8 @@ public Builder setReservation(String reservation) { */ @BetaApi public Builder setQueryResultsFormat(QueryResultsFormat queryResultsFormat) { - this.queryResultsFormat = queryResultsFormat; + this.queryResultsFormat = + checkNotNull(queryResultsFormat, "queryResultsFormat cannot be null"); return this; } @@ -741,7 +742,8 @@ public Builder setQueryResultsFormat(QueryResultsFormat queryResultsFormat) { @BetaApi public Builder setArrowSerializationOptions( ArrowSerializationOptions arrowSerializationOptions) { - this.arrowSerializationOptions = arrowSerializationOptions; + this.arrowSerializationOptions = + checkNotNull(arrowSerializationOptions, "arrowSerializationOptions cannot be null"); return this; } diff --git a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java index 82c35c44bb36..11bea803dbd9 100644 --- a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java +++ b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java @@ -247,8 +247,9 @@ public void testArrowConfigurations() { QueryResultsFormat format = QueryResultsFormat.ARROW; ArrowSerializationOptions options = ArrowSerializationOptions.newBuilder() - .setBufferCompression("LZ4") - .setPicosTimestampPrecision("PRECISION_MILLIS") + .setBufferCompression(ArrowSerializationOptions.CompressionCodec.LZ4_FRAME) + .setPicosTimestampPrecision( + ArrowSerializationOptions.TimestampPrecision.PRECISION_MILLIS) .build(); QueryJobConfiguration job = QueryJobConfiguration.newBuilder(QUERY) @@ -274,8 +275,12 @@ public void testArrowConfigurations() { @Test public void testArrowSerializationOptionsNullChecks() { ArrowSerializationOptions.Builder builder = ArrowSerializationOptions.newBuilder(); - assertNull(builder.build().getBufferCompression()); - assertNull(builder.build().getPicosTimestampPrecision()); + assertEquals( + ArrowSerializationOptions.CompressionCodec.UNCOMPRESSED, + builder.build().getBufferCompression()); + assertEquals( + ArrowSerializationOptions.TimestampPrecision.PRECISION_MICROS, + builder.build().getPicosTimestampPrecision()); NullPointerException ex1 = assertThrows(NullPointerException.class, () -> builder.setBufferCompression(null)); @@ -286,6 +291,19 @@ public void testArrowSerializationOptionsNullChecks() { assertEquals("picosTimestampPrecision cannot be null", ex2.getMessage()); } + @Test + public void testQueryJobConfigurationArrowNullChecks() { + QueryJobConfiguration.Builder builder = QueryJobConfiguration.newBuilder(QUERY); + + NullPointerException ex1 = + assertThrows(NullPointerException.class, () -> builder.setQueryResultsFormat(null)); + assertEquals("queryResultsFormat cannot be null", ex1.getMessage()); + + NullPointerException ex2 = + assertThrows(NullPointerException.class, () -> builder.setArrowSerializationOptions(null)); + assertEquals("arrowSerializationOptions cannot be null", ex2.getMessage()); + } + private void compareQueryJobConfiguration( QueryJobConfiguration expected, QueryJobConfiguration value) { assertEquals(expected, value); From 7791a38c9d6c11f8aac912350e6a83253f053a59 Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Tue, 11 Aug 2026 15:42:02 -0400 Subject: [PATCH 11/11] feat(bigquery): update Arrow serialization options with enums and defaults --- .../bigquery/ArrowSerializationOptions.java | 9 ++--- .../cloud/bigquery/QueryJobConfiguration.java | 2 +- .../bigquery/QueryJobConfigurationTest.java | 39 +++++++++++++++++-- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java index 22792c7e80c6..138f9495cf27 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ArrowSerializationOptions.java @@ -58,10 +58,9 @@ public String toString() { /** [Beta] Timestamp precision for Apache Arrow timestamp types. */ @BetaApi public enum TimestampPrecision { - PRECISION_MILLIS("PRECISION_MILLIS"), - PRECISION_MICROS("PRECISION_MICROS"), - PRECISION_NANOS("PRECISION_NANOS"), - PRECISION_PICOS("PRECISION_PICOS"); + MICROS("PRECISION_MICROS"), + NANOS("PRECISION_NANOS"), + PICOS("PRECISION_PICOS"); private final String value; @@ -155,7 +154,7 @@ static ArrowSerializationOptions fromPb( @BetaApi public static final class Builder { private CompressionCodec bufferCompression = CompressionCodec.UNCOMPRESSED; - private TimestampPrecision picosTimestampPrecision = TimestampPrecision.PRECISION_MICROS; + private TimestampPrecision picosTimestampPrecision = TimestampPrecision.MICROS; private Builder() {} diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java index c2044222d637..8fc78b3edc73 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/QueryJobConfiguration.java @@ -147,7 +147,7 @@ public static final class Builder private Long maxResults; private JobCreationMode jobCreationMode; private String reservation; - private QueryResultsFormat queryResultsFormat; + private QueryResultsFormat queryResultsFormat = QueryResultsFormat.STRUCT_ENCODING; private ArrowSerializationOptions arrowSerializationOptions; private Builder() { diff --git a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java index 11bea803dbd9..4c4f847e9a96 100644 --- a/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java +++ b/java-bigquery/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/QueryJobConfigurationTest.java @@ -248,8 +248,7 @@ public void testArrowConfigurations() { ArrowSerializationOptions options = ArrowSerializationOptions.newBuilder() .setBufferCompression(ArrowSerializationOptions.CompressionCodec.LZ4_FRAME) - .setPicosTimestampPrecision( - ArrowSerializationOptions.TimestampPrecision.PRECISION_MILLIS) + .setPicosTimestampPrecision(ArrowSerializationOptions.TimestampPrecision.NANOS) .build(); QueryJobConfiguration job = QueryJobConfiguration.newBuilder(QUERY) @@ -268,7 +267,7 @@ public void testArrowConfigurations() { // Test toPb/fromPb (not preserved) QueryJobConfiguration jobFromPb = QueryJobConfiguration.fromPb(job.toPb()); - assertNull(jobFromPb.getQueryResultsFormat()); + assertEquals(QueryResultsFormat.STRUCT_ENCODING, jobFromPb.getQueryResultsFormat()); assertNull(jobFromPb.getArrowSerializationOptions()); } @@ -279,7 +278,7 @@ public void testArrowSerializationOptionsNullChecks() { ArrowSerializationOptions.CompressionCodec.UNCOMPRESSED, builder.build().getBufferCompression()); assertEquals( - ArrowSerializationOptions.TimestampPrecision.PRECISION_MICROS, + ArrowSerializationOptions.TimestampPrecision.MICROS, builder.build().getPicosTimestampPrecision()); NullPointerException ex1 = @@ -291,6 +290,36 @@ public void testArrowSerializationOptionsNullChecks() { assertEquals("picosTimestampPrecision cannot be null", ex2.getMessage()); } + @Test + public void testQueryJobConfigurationDefaults() { + QueryJobConfiguration defaultJob = QueryJobConfiguration.newBuilder(QUERY).build(); + + // Default query format is STRUCT_ENCODING; Arrow options are null by default + assertEquals(QueryResultsFormat.STRUCT_ENCODING, defaultJob.getQueryResultsFormat()); + assertNull(defaultJob.getArrowSerializationOptions()); + + // Verify toBuilder preserves defaults + QueryJobConfiguration copiedJob = defaultJob.toBuilder().build(); + assertEquals(QueryResultsFormat.STRUCT_ENCODING, copiedJob.getQueryResultsFormat()); + assertNull(copiedJob.getArrowSerializationOptions()); + } + + @Test + public void testArrowFormatWithNullSerializationOptions() { + QueryJobConfiguration job = + QueryJobConfiguration.newBuilder(QUERY) + .setQueryResultsFormat(QueryResultsFormat.ARROW) + .build(); + + assertEquals(QueryResultsFormat.ARROW, job.getQueryResultsFormat()); + assertNull(job.getArrowSerializationOptions()); + + // Verify toBuilder preserves ARROW format with null options + QueryJobConfiguration copiedJob = job.toBuilder().build(); + assertEquals(QueryResultsFormat.ARROW, copiedJob.getQueryResultsFormat()); + assertNull(copiedJob.getArrowSerializationOptions()); + } + @Test public void testQueryJobConfigurationArrowNullChecks() { QueryJobConfiguration.Builder builder = QueryJobConfiguration.newBuilder(QUERY); @@ -338,5 +367,7 @@ private void compareQueryJobConfiguration( assertEquals(expected.getPositionalParameters(), value.getPositionalParameters()); assertEquals(expected.getNamedParameters(), value.getNamedParameters()); assertEquals(expected.getReservation(), value.getReservation()); + assertEquals(expected.getQueryResultsFormat(), value.getQueryResultsFormat()); + assertEquals(expected.getArrowSerializationOptions(), value.getArrowSerializationOptions()); } }