diff --git a/.github/release-please.yml b/.github/release-please.yml
index 615a27f0bf..1000ca6ad0 100644
--- a/.github/release-please.yml
+++ b/.github/release-please.yml
@@ -38,3 +38,8 @@ branches:
handleGHRelease: true
releaseType: java-backport
branch: 3.15.x
+ - bumpMinorPreMajor: true
+ handleGHRelease: true
+ releaseType: java-yoshi
+ branch: protobuf-4.x-rc
+ manifest: true
diff --git a/.github/workflows/hermetic_library_generation.yaml b/.github/workflows/hermetic_library_generation.yaml
index 31a38fbb06..8c3df5194a 100644
--- a/.github/workflows/hermetic_library_generation.yaml
+++ b/.github/workflows/hermetic_library_generation.yaml
@@ -37,7 +37,7 @@ jobs:
with:
fetch-depth: 0
token: ${{ secrets.CLOUD_JAVA_BOT_TOKEN }}
- - uses: googleapis/sdk-platform-java/.github/scripts@v2.64.1
+ - uses: googleapis/sdk-platform-java/.github/scripts@v2.64.2
if: env.SHOULD_RUN == 'true'
with:
base_ref: ${{ github.base_ref }}
diff --git a/.github/workflows/unmanaged_dependency_check.yaml b/.github/workflows/unmanaged_dependency_check.yaml
index fc7f576f62..3f124637eb 100644
--- a/.github/workflows/unmanaged_dependency_check.yaml
+++ b/.github/workflows/unmanaged_dependency_check.yaml
@@ -17,6 +17,6 @@ jobs:
# repository
.kokoro/build.sh
- name: Unmanaged dependency check
- uses: googleapis/sdk-platform-java/java-shared-dependencies/unmanaged-dependency-check@google-cloud-shared-dependencies/v3.54.1
+ uses: googleapis/sdk-platform-java/java-shared-dependencies/unmanaged-dependency-check@google-cloud-shared-dependencies/v3.54.2
with:
bom-path: google-cloud-bigquerystorage-bom/pom.xml
diff --git a/.kokoro/continuous/graalvm-native-a.cfg b/.kokoro/continuous/graalvm-native-a.cfg
index b772eac66c..406018c48a 100644
--- a/.kokoro/continuous/graalvm-native-a.cfg
+++ b/.kokoro/continuous/graalvm-native-a.cfg
@@ -3,7 +3,7 @@
# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
- value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_a:3.54.1" # {x-version-update:google-cloud-shared-dependencies:current}
+ value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_a:3.54.2" # {x-version-update:google-cloud-shared-dependencies:current}
}
env_vars: {
diff --git a/.kokoro/continuous/graalvm-native-b.cfg b/.kokoro/continuous/graalvm-native-b.cfg
index baf136cf82..60c82d4bf4 100644
--- a/.kokoro/continuous/graalvm-native-b.cfg
+++ b/.kokoro/continuous/graalvm-native-b.cfg
@@ -3,7 +3,7 @@
# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
- value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_b:3.54.1" # {x-version-update:google-cloud-shared-dependencies:current}
+ value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_b:3.54.2" # {x-version-update:google-cloud-shared-dependencies:current}
}
env_vars: {
diff --git a/.kokoro/continuous/graalvm-native-c.cfg b/.kokoro/continuous/graalvm-native-c.cfg
index 2fb2fc87c4..60982adf5a 100644
--- a/.kokoro/continuous/graalvm-native-c.cfg
+++ b/.kokoro/continuous/graalvm-native-c.cfg
@@ -3,7 +3,7 @@
# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
- value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_c:3.54.1" # {x-version-update:google-cloud-shared-dependencies:current}
+ value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_c:3.54.2" # {x-version-update:google-cloud-shared-dependencies:current}
}
env_vars: {
diff --git a/.kokoro/presubmit/graalvm-native-a.cfg b/.kokoro/presubmit/graalvm-native-a.cfg
index 0d98de5094..20c0ac4a52 100644
--- a/.kokoro/presubmit/graalvm-native-a.cfg
+++ b/.kokoro/presubmit/graalvm-native-a.cfg
@@ -3,7 +3,7 @@
# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
- value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_a:3.54.1"
+ value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_a:3.54.2"
}
env_vars: {
diff --git a/.kokoro/presubmit/graalvm-native-b.cfg b/.kokoro/presubmit/graalvm-native-b.cfg
index c270bff717..3b7b14a650 100644
--- a/.kokoro/presubmit/graalvm-native-b.cfg
+++ b/.kokoro/presubmit/graalvm-native-b.cfg
@@ -3,7 +3,7 @@
# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
- value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_b:3.54.1"
+ value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_b:3.54.2"
}
env_vars: {
diff --git a/.kokoro/presubmit/graalvm-native-c.cfg b/.kokoro/presubmit/graalvm-native-c.cfg
index 720f8bcfaf..a41d88c092 100644
--- a/.kokoro/presubmit/graalvm-native-c.cfg
+++ b/.kokoro/presubmit/graalvm-native-c.cfg
@@ -3,7 +3,7 @@
# Configure the docker image for kokoro-trampoline.
env_vars: {
key: "TRAMPOLINE_IMAGE"
- value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_c:3.54.1"
+ value: "gcr.io/cloud-devrel-public-resources/graalvm_sdk_platform_c:3.54.2"
}
env_vars: {
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f64defd9d1..4ae63b098f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,18 @@
# Changelog
+## [3.19.0](https://github.com/googleapis/java-bigquerystorage/compare/v3.18.0...v3.19.0) (2025-12-12)
+
+
+### Features
+
+* Add picosecond timestamp support for Json to Proto converter ([#3131](https://github.com/googleapis/java-bigquerystorage/issues/3131)) ([ea1bcc5](https://github.com/googleapis/java-bigquerystorage/commit/ea1bcc509b7c430f92c5764cc4121aaa282255bf))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:sdk-platform-java-config to v3.54.2 ([#3137](https://github.com/googleapis/java-bigquerystorage/issues/3137)) ([2dc42c7](https://github.com/googleapis/java-bigquerystorage/commit/2dc42c7a6a15c4b86f7012a0cd211ca09ffd9a0e))
+* Update googleapis/sdk-platform-java action to v2.64.2 ([#3138](https://github.com/googleapis/java-bigquerystorage/issues/3138)) ([28cbdd9](https://github.com/googleapis/java-bigquerystorage/commit/28cbdd9f5ab36e9d7d0aa8142260dc760e50a3fb))
+
## [3.18.0](https://github.com/googleapis/java-bigquerystorage/compare/v3.17.3...v3.18.0) (2025-11-13)
diff --git a/README.md b/README.md
index 51ff85e255..50ca189af9 100644
--- a/README.md
+++ b/README.md
@@ -63,13 +63,13 @@ implementation 'com.google.cloud:google-cloud-bigquerystorage'
If you are using Gradle without BOM, add this to your dependencies:
```Groovy
-implementation 'com.google.cloud:google-cloud-bigquerystorage:3.18.0'
+implementation 'com.google.cloud:google-cloud-bigquerystorage:3.19.0'
```
If you are using SBT, add this to your dependencies:
```Scala
-libraryDependencies += "com.google.cloud" % "google-cloud-bigquerystorage" % "3.18.0"
+libraryDependencies += "com.google.cloud" % "google-cloud-bigquerystorage" % "3.19.0"
```
## Authentication
@@ -257,7 +257,7 @@ Java is a registered trademark of Oracle and/or its affiliates.
[kokoro-badge-link-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-bigquerystorage/java11.html
[stability-image]: https://img.shields.io/badge/stability-stable-green
[maven-version-image]: https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-bigquerystorage.svg
-[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-bigquerystorage/3.18.0
+[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-bigquerystorage/3.19.0
[authentication]: https://github.com/googleapis/google-cloud-java#authentication
[auth-scopes]: https://developers.google.com/identity/protocols/oauth2/scopes
[predefined-iam-roles]: https://cloud.google.com/iam/docs/understanding-roles#predefined_roles
diff --git a/google-cloud-bigquerystorage-bom/pom.xml b/google-cloud-bigquerystorage-bom/pom.xml
index 0ad7de64cd..fc22de0e34 100644
--- a/google-cloud-bigquerystorage-bom/pom.xml
+++ b/google-cloud-bigquerystorage-bom/pom.xml
@@ -3,12 +3,12 @@
4.0.0
com.google.cloud
google-cloud-bigquerystorage-bom
- 3.18.1-rc1-SNAPSHOT
+ 3.19.1-SNAPSHOT
pom
com.google.cloud
sdk-platform-java-config
- 3.54.1
+ 3.54.2
Google Cloud bigquerystorage BOM
@@ -52,57 +52,57 @@
com.google.cloud
google-cloud-bigquerystorage
- 3.18.1-rc1-SNAPSHOT
+ 3.19.1-SNAPSHOT
com.google.api.grpc
grpc-google-cloud-bigquerystorage-v1beta1
- 0.190.1-rc1-SNAPSHOT
+ 0.191.1-SNAPSHOT
com.google.api.grpc
grpc-google-cloud-bigquerystorage-v1beta2
- 0.190.1-rc1-SNAPSHOT
+ 0.191.1-SNAPSHOT
com.google.api.grpc
grpc-google-cloud-bigquerystorage-v1
- 3.18.1-rc1-SNAPSHOT
+ 3.19.1-SNAPSHOT
com.google.api.grpc
grpc-google-cloud-bigquerystorage-v1alpha
- 3.18.1-rc1-SNAPSHOT
+ 3.19.1-SNAPSHOT
com.google.api.grpc
grpc-google-cloud-bigquerystorage-v1beta
- 3.18.1-rc1-SNAPSHOT
+ 3.19.1-SNAPSHOT
com.google.api.grpc
proto-google-cloud-bigquerystorage-v1beta1
- 0.190.1-rc1-SNAPSHOT
+ 0.191.1-SNAPSHOT
com.google.api.grpc
proto-google-cloud-bigquerystorage-v1beta2
- 0.190.1-rc1-SNAPSHOT
+ 0.191.1-SNAPSHOT
com.google.api.grpc
proto-google-cloud-bigquerystorage-v1
- 3.18.1-rc1-SNAPSHOT
+ 3.19.1-SNAPSHOT
com.google.api.grpc
proto-google-cloud-bigquerystorage-v1alpha
- 3.18.1-rc1-SNAPSHOT
+ 3.19.1-SNAPSHOT
com.google.api.grpc
proto-google-cloud-bigquerystorage-v1beta
- 3.18.1-rc1-SNAPSHOT
+ 3.19.1-SNAPSHOT
diff --git a/google-cloud-bigquerystorage/pom.xml b/google-cloud-bigquerystorage/pom.xml
index 0f23a2e8de..581129ad59 100644
--- a/google-cloud-bigquerystorage/pom.xml
+++ b/google-cloud-bigquerystorage/pom.xml
@@ -3,7 +3,7 @@
4.0.0
com.google.cloud
google-cloud-bigquerystorage
- 3.18.1-rc1-SNAPSHOT
+ 3.19.1-SNAPSHOT
jar
BigQuery Storage
https://github.com/googleapis/java-bigquerystorage
@@ -11,7 +11,7 @@
com.google.cloud
google-cloud-bigquerystorage-parent
- 3.18.1-rc1-SNAPSHOT
+ 3.19.1-SNAPSHOT
google-cloud-bigquerystorage
diff --git a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1/BQTableSchemaToProtoDescriptor.java b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1/BQTableSchemaToProtoDescriptor.java
index 60bb739b23..5842f6d068 100644
--- a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1/BQTableSchemaToProtoDescriptor.java
+++ b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1/BQTableSchemaToProtoDescriptor.java
@@ -30,6 +30,8 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
/**
* Converts a BQ table schema to protobuf descriptor. All field names will be converted to lowercase
@@ -37,15 +39,18 @@
* shown in the ImmutableMaps below.
*/
public class BQTableSchemaToProtoDescriptor {
- private static ImmutableMap
- BQTableSchemaModeMap =
- ImmutableMap.of(
- TableFieldSchema.Mode.NULLABLE, FieldDescriptorProto.Label.LABEL_OPTIONAL,
- TableFieldSchema.Mode.REPEATED, FieldDescriptorProto.Label.LABEL_REPEATED,
- TableFieldSchema.Mode.REQUIRED, FieldDescriptorProto.Label.LABEL_REQUIRED);
- private static ImmutableMap
- BQTableSchemaTypeMap =
+ private static final Logger LOG =
+ Logger.getLogger(BQTableSchemaToProtoDescriptor.class.getName());
+
+ private static Map DEFAULT_BQ_TABLE_SCHEMA_MODE_MAP =
+ ImmutableMap.of(
+ TableFieldSchema.Mode.NULLABLE, FieldDescriptorProto.Label.LABEL_OPTIONAL,
+ TableFieldSchema.Mode.REPEATED, FieldDescriptorProto.Label.LABEL_REPEATED,
+ TableFieldSchema.Mode.REQUIRED, FieldDescriptorProto.Label.LABEL_REQUIRED);
+
+ private static Map
+ DEFAULT_BQ_TABLE_SCHEMA_TYPE_MAP =
new ImmutableMap.Builder()
.put(TableFieldSchema.Type.BOOL, FieldDescriptorProto.Type.TYPE_BOOL)
.put(TableFieldSchema.Type.BYTES, FieldDescriptorProto.Type.TYPE_BYTES)
@@ -142,11 +147,13 @@ private static Descriptor convertBQTableSchemaToProtoDescriptorImpl(
.setType(BQTableField.getRangeElementType().getType())
.setName("start")
.setMode(Mode.NULLABLE)
+ .setTimestampPrecision(BQTableField.getTimestampPrecision())
.build(),
TableFieldSchema.newBuilder()
.setType(BQTableField.getRangeElementType().getType())
.setName("end")
.setMode(Mode.NULLABLE)
+ .setTimestampPrecision(BQTableField.getTimestampPrecision())
.build());
if (dependencyMap.containsKey(rangeFields)) {
@@ -189,7 +196,7 @@ private static Descriptor convertBQTableSchemaToProtoDescriptorImpl(
* @param index Index for protobuf fields.
* @param scope used to name descriptors
*/
- private static FieldDescriptorProto convertBQTableFieldToProtoField(
+ static FieldDescriptorProto convertBQTableFieldToProtoField(
TableFieldSchema BQTableField, int index, String scope) {
TableFieldSchema.Mode mode = BQTableField.getMode();
String fieldName = BQTableField.getName().toLowerCase();
@@ -198,7 +205,7 @@ private static FieldDescriptorProto convertBQTableFieldToProtoField(
FieldDescriptorProto.newBuilder()
.setName(fieldName)
.setNumber(index)
- .setLabel((FieldDescriptorProto.Label) BQTableSchemaModeMap.get(mode));
+ .setLabel((FieldDescriptorProto.Label) DEFAULT_BQ_TABLE_SCHEMA_MODE_MAP.get(mode));
switch (BQTableField.getType()) {
case STRUCT:
@@ -206,12 +213,37 @@ private static FieldDescriptorProto convertBQTableFieldToProtoField(
break;
case RANGE:
fieldDescriptor.setType(
- (FieldDescriptorProto.Type) BQTableSchemaTypeMap.get(BQTableField.getType()));
+ (FieldDescriptorProto.Type)
+ DEFAULT_BQ_TABLE_SCHEMA_TYPE_MAP.get(BQTableField.getType()));
fieldDescriptor.setTypeName(scope);
break;
+ case TIMESTAMP:
+ // Can map to either int64 or string based on the BQ Field's timestamp precision
+ // Default: microsecond (6) maps to int64 and picosecond (12) maps to string.
+ long timestampPrecision = BQTableField.getTimestampPrecision().getValue();
+ if (timestampPrecision == 12L) {
+ fieldDescriptor.setType(
+ (FieldDescriptorProto.Type) FieldDescriptorProto.Type.TYPE_STRING);
+ break;
+ }
+ // This should never happen as this is a server response issue. If this is the case,
+ // warn the user and use INT64 as the default is microsecond precision.
+ if (timestampPrecision != 6L && timestampPrecision != 0L) {
+ LOG.warning(
+ "BigQuery Timestamp field "
+ + BQTableField.getName()
+ + " has timestamp precision that is not 6 or 12. Defaulting to microsecond"
+ + " precision and mapping to INT64 protobuf type.");
+ }
+ // If the timestampPrecision value comes back as a null result from the server,
+ // timestampPrecision has a value of 0L. Use the INT64 to map to the type used
+ // for the default precision (microsecond).
+ fieldDescriptor.setType((FieldDescriptorProto.Type) FieldDescriptorProto.Type.TYPE_INT64);
+ break;
default:
fieldDescriptor.setType(
- (FieldDescriptorProto.Type) BQTableSchemaTypeMap.get(BQTableField.getType()));
+ (FieldDescriptorProto.Type)
+ DEFAULT_BQ_TABLE_SCHEMA_TYPE_MAP.get(BQTableField.getType()));
break;
}
diff --git a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1/JsonToProtoMessage.java b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1/JsonToProtoMessage.java
index 9a4fecf780..6e5643f002 100644
--- a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1/JsonToProtoMessage.java
+++ b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1/JsonToProtoMessage.java
@@ -15,8 +15,14 @@
*/
package com.google.cloud.bigquery.storage.v1;
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+
import com.google.api.pathtemplate.ValidationException;
import com.google.cloud.bigquery.storage.v1.Exceptions.RowIndexToErrorException;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.primitives.Doubles;
@@ -26,15 +32,18 @@
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.DynamicMessage;
+import com.google.protobuf.Timestamp;
import com.google.protobuf.UninitializedMessageException;
import java.math.BigDecimal;
import java.math.RoundingMode;
+import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.DateTimeParseException;
import java.time.format.TextStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
@@ -42,6 +51,8 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -63,7 +74,31 @@ public class JsonToProtoMessage implements ToProtoConverter