diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dc44cd87f..f825c02298 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [1.3.0](https://www.github.com/googleapis/java-bigquerystorage/compare/v1.2.1...v1.3.0) (2020-07-21) + + +### Features + +* Adding JsonToProtoMessage.java ([#400](https://www.github.com/googleapis/java-bigquerystorage/issues/400)) ([200da6d](https://www.github.com/googleapis/java-bigquerystorage/commit/200da6d66e82eaabceeae56e4ff3d1b8e112bd8d)) +* re-generated to pick up changes from googleapis. ([#435](https://www.github.com/googleapis/java-bigquerystorage/issues/435)) ([bdf35e0](https://www.github.com/googleapis/java-bigquerystorage/commit/bdf35e08987ffdf49f7545131cd0dba56ff72bd9)), closes [#436](https://www.github.com/googleapis/java-bigquerystorage/issues/436) + ### [1.2.1](https://www.github.com/googleapis/java-bigquerystorage/compare/v1.2.0...v1.2.1) (2020-07-20) diff --git a/README.md b/README.md index e7b83c7ac1..57e2a654dd 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ If you are using Maven without BOM, add this to your dependencies: com.google.cloud google-cloud-bigquerystorage - 1.1.1 + 1.2.0 ``` @@ -47,11 +47,11 @@ If you are using Maven without BOM, add this to your dependencies: If you are using Gradle, add this to your dependencies ```Groovy -compile 'com.google.cloud:google-cloud-bigquerystorage:1.2.1' +compile 'com.google.cloud:google-cloud-bigquerystorage:1.3.0' ``` If you are using SBT, add this to your dependencies ```Scala -libraryDependencies += "com.google.cloud" % "google-cloud-bigquerystorage" % "1.2.1" +libraryDependencies += "com.google.cloud" % "google-cloud-bigquerystorage" % "1.3.0" ``` [//]: # ({x-version-update-end}) diff --git a/google-cloud-bigquerystorage-bom/pom.xml b/google-cloud-bigquerystorage-bom/pom.xml index 58436d5113..e46ee2fe7c 100644 --- a/google-cloud-bigquerystorage-bom/pom.xml +++ b/google-cloud-bigquerystorage-bom/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.google.cloud google-cloud-bigquerystorage-bom - 1.2.1 + 1.3.0 pom com.google.cloud @@ -63,48 +63,48 @@ com.google.api.grpc proto-google-cloud-bigquerystorage-v1alpha2 - 0.102.1 + 0.103.0 com.google.api.grpc proto-google-cloud-bigquerystorage-v1beta1 - 0.102.1 + 0.103.0 com.google.api.grpc proto-google-cloud-bigquerystorage-v1beta2 - 0.102.1 + 0.103.0 com.google.api.grpc proto-google-cloud-bigquerystorage-v1 - 1.2.1 + 1.3.0 com.google.api.grpc grpc-google-cloud-bigquerystorage-v1alpha2 - 0.102.1 + 0.103.0 com.google.api.grpc grpc-google-cloud-bigquerystorage-v1beta1 - 0.102.1 + 0.103.0 com.google.api.grpc grpc-google-cloud-bigquerystorage-v1beta2 - 0.102.1 + 0.103.0 com.google.api.grpc grpc-google-cloud-bigquerystorage-v1 - 1.2.1 + 1.3.0 com.google.cloud google-cloud-bigquerystorage - 1.2.1 + 1.3.0 diff --git a/google-cloud-bigquerystorage/pom.xml b/google-cloud-bigquerystorage/pom.xml index 9ba98ec314..63df2bcaff 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 - 1.2.1 + 1.3.0 jar BigQuery Storage https://github.com/googleapis/java-bigquerystorage @@ -11,7 +11,7 @@ com.google.cloud google-cloud-bigquerystorage-parent - 1.2.1 + 1.3.0 google-cloud-bigquerystorage @@ -108,6 +108,11 @@ org.apache.commons commons-lang3 + + org.json + json + + diff --git a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/BQTableSchemaToProtoDescriptor.java b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/BQTableSchemaToProtoDescriptor.java index 96f84fa960..2b105bcbaf 100644 --- a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/BQTableSchemaToProtoDescriptor.java +++ b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/BQTableSchemaToProtoDescriptor.java @@ -15,6 +15,7 @@ */ package com.google.cloud.bigquery.storage.v1alpha2; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.protobuf.DescriptorProtos.DescriptorProto; @@ -65,6 +66,7 @@ public class BQTableSchemaToProtoDescriptor { */ public static Descriptor convertBQTableSchemaToProtoDescriptor(Table.TableSchema BQTableSchema) throws Descriptors.DescriptorValidationException { + Preconditions.checkNotNull(BQTableSchema, "BQTableSchema is null."); return convertBQTableSchemaToProtoDescriptorImpl( BQTableSchema, "root", new HashMap, Descriptor>()); } diff --git a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/DirectWriter.java b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/DirectWriter.java index 3e1a57c715..06afee8b58 100644 --- a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/DirectWriter.java +++ b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/DirectWriter.java @@ -21,6 +21,7 @@ import com.google.cloud.bigquery.storage.v1alpha2.ProtoBufProto.ProtoRows; import com.google.cloud.bigquery.storage.v1alpha2.Storage.AppendRowsRequest; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.Descriptors; import com.google.protobuf.Message; @@ -60,6 +61,9 @@ public class DirectWriter { */ public static ApiFuture append(String tableName, List protoRows) throws IOException, InterruptedException, InvalidArgumentException { + Preconditions.checkNotNull(tableName, "TableName is null."); + Preconditions.checkNotNull(protoRows, "ProtoRows is null."); + if (protoRows.isEmpty()) { throw new InvalidArgumentException( new Exception("Empty rows are not allowed"), diff --git a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/JsonToProtoMessage.java b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/JsonToProtoMessage.java new file mode 100644 index 0000000000..c6aced9f17 --- /dev/null +++ b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/JsonToProtoMessage.java @@ -0,0 +1,323 @@ +/* + * Copyright 2020 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.storage.v1alpha2; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.DynamicMessage; +import com.google.protobuf.Message; +import com.google.protobuf.UninitializedMessageException; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Converts Json data to protocol buffer messages given the protocol buffer descriptor. The protobuf + * descriptor must have all fields lowercased. + */ +public class JsonToProtoMessage { + private static ImmutableMap FieldTypeToDebugMessage = + new ImmutableMap.Builder() + .put(FieldDescriptor.Type.BOOL, "boolean") + .put(FieldDescriptor.Type.BYTES, "string") + .put(FieldDescriptor.Type.INT32, "int32") + .put(FieldDescriptor.Type.DOUBLE, "double") + .put(FieldDescriptor.Type.INT64, "int64") + .put(FieldDescriptor.Type.STRING, "string") + .put(FieldDescriptor.Type.MESSAGE, "object") + .build(); + + /** + * Converts Json data to protocol buffer messages given the protocol buffer descriptor. + * + * @param protoSchema + * @param json + * @param allowUnknownFields Ignores unknown JSON fields. + * @throws IllegalArgumentException when JSON data is not compatible with proto descriptor. + */ + public static DynamicMessage convertJsonToProtoMessage( + Descriptor protoSchema, JSONObject json, boolean allowUnknownFields) + throws IllegalArgumentException { + Preconditions.checkNotNull(json, "JSONObject is null."); + Preconditions.checkNotNull(protoSchema, "Protobuf descriptor is null."); + Preconditions.checkState(json.length() != 0, "JSONObject is empty."); + + return convertJsonToProtoMessageImpl( + protoSchema, json, "root", /*topLevel=*/ true, allowUnknownFields); + } + + /** + * Converts Json data to protocol buffer messages given the protocol buffer descriptor. + * + * @param protoSchema + * @param json + * @param jsonScope Debugging purposes + * @param allowUnknownFields Ignores unknown JSON fields. + * @param topLevel checks if root level has any matching fields. + * @throws IllegalArgumentException when JSON data is not compatible with proto descriptor. + */ + private static DynamicMessage convertJsonToProtoMessageImpl( + Descriptor protoSchema, + JSONObject json, + String jsonScope, + boolean topLevel, + boolean allowUnknownFields) + throws IllegalArgumentException { + + DynamicMessage.Builder protoMsg = DynamicMessage.newBuilder(protoSchema); + String[] jsonNames = JSONObject.getNames(json); + if (jsonNames == null) { + return protoMsg.build(); + } + int matchedFields = 0; + for (int i = 0; i < jsonNames.length; i++) { + String jsonName = jsonNames[i]; + // We want lowercase here to support case-insensitive data writes. + // The protobuf descriptor that is used is assumed to have all lowercased fields + String jsonLowercaseName = jsonName.toLowerCase(); + String currentScope = jsonScope + "." + jsonName; + FieldDescriptor field = protoSchema.findFieldByName(jsonLowercaseName); + if (field == null) { + if (!allowUnknownFields) { + throw new IllegalArgumentException( + String.format( + "JSONObject has fields unknown to BigQuery: %s. Set allowUnknownFields to True to allow unknown fields.", + currentScope)); + } else { + continue; + } + } + matchedFields++; + if (!field.isRepeated()) { + fillField(protoMsg, field, json, jsonName, currentScope, allowUnknownFields); + } else { + fillRepeatedField(protoMsg, field, json, jsonName, currentScope, allowUnknownFields); + } + } + + if (matchedFields == 0 && topLevel) { + throw new IllegalArgumentException( + "There are no matching fields found for the JSONObject and the protocol buffer descriptor."); + } + DynamicMessage msg; + try { + msg = protoMsg.build(); + } catch (UninitializedMessageException e) { + String errorMsg = e.getMessage(); + int idxOfColon = errorMsg.indexOf(":"); + String missingFieldName = errorMsg.substring(idxOfColon + 2); + throw new IllegalArgumentException( + String.format( + "JSONObject does not have the required field %s.%s.", jsonScope, missingFieldName)); + } + if (topLevel && msg.getSerializedSize() == 0) { + throw new IllegalArgumentException("The created protobuf message is empty."); + } + return msg; + } + + /** + * Fills a non-repetaed protoField with the json data. + * + * @param protoMsg The protocol buffer message being constructed + * @param fieldDescriptor + * @param json + * @param exactJsonKeyName Exact key name in JSONObject instead of lowercased version + * @param currentScope Debugging purposes + * @param allowUnknownFields Ignores unknown JSON fields. + * @throws IllegalArgumentException when JSON data is not compatible with proto descriptor. + */ + private static void fillField( + DynamicMessage.Builder protoMsg, + FieldDescriptor fieldDescriptor, + JSONObject json, + String exactJsonKeyName, + String currentScope, + boolean allowUnknownFields) + throws IllegalArgumentException { + + java.lang.Object val = json.get(exactJsonKeyName); + switch (fieldDescriptor.getType()) { + case BOOL: + if (val instanceof Boolean) { + protoMsg.setField(fieldDescriptor, (Boolean) val); + return; + } + break; + case BYTES: + if (val instanceof String) { + protoMsg.setField(fieldDescriptor, ((String) val).getBytes()); + return; + } + break; + case INT64: + if (val instanceof Integer) { + protoMsg.setField(fieldDescriptor, new Long((Integer) val)); + return; + } else if (val instanceof Long) { + protoMsg.setField(fieldDescriptor, (Long) val); + return; + } + break; + case INT32: + if (val instanceof Integer) { + protoMsg.setField(fieldDescriptor, (Integer) val); + return; + } + break; + case STRING: + if (val instanceof String) { + protoMsg.setField(fieldDescriptor, (String) val); + return; + } + break; + case DOUBLE: + if (val instanceof Double) { + protoMsg.setField(fieldDescriptor, (Double) val); + return; + } else if (val instanceof Float) { + protoMsg.setField(fieldDescriptor, new Double((Float) val)); + return; + } + break; + case MESSAGE: + if (val instanceof JSONObject) { + Message.Builder message = protoMsg.newBuilderForField(fieldDescriptor); + protoMsg.setField( + fieldDescriptor, + convertJsonToProtoMessageImpl( + fieldDescriptor.getMessageType(), + json.getJSONObject(exactJsonKeyName), + currentScope, + /*topLevel =*/ false, + allowUnknownFields)); + return; + } + break; + } + throw new IllegalArgumentException( + String.format( + "JSONObject does not have a %s field at %s.", + FieldTypeToDebugMessage.get(fieldDescriptor.getType()), currentScope)); + } + + /** + * Fills a repeated protoField with the json data. + * + * @param protoMsg The protocol buffer message being constructed + * @param fieldDescriptor + * @param json If root level has no matching fields, throws exception. + * @param exactJsonKeyName Exact key name in JSONObject instead of lowercased version + * @param currentScope Debugging purposes + * @param allowUnknownFields Ignores unknown JSON fields. + * @throws IllegalArgumentException when JSON data is not compatible with proto descriptor. + */ + private static void fillRepeatedField( + DynamicMessage.Builder protoMsg, + FieldDescriptor fieldDescriptor, + JSONObject json, + String exactJsonKeyName, + String currentScope, + boolean allowUnknownFields) + throws IllegalArgumentException { + + JSONArray jsonArray; + try { + jsonArray = json.getJSONArray(exactJsonKeyName); + } catch (JSONException e) { + throw new IllegalArgumentException( + "JSONObject does not have a array field at " + currentScope + "."); + } + java.lang.Object val; + int index; + boolean fail = false; + for (int i = 0; i < jsonArray.length(); i++) { + val = jsonArray.get(i); + index = i; + switch (fieldDescriptor.getType()) { + case BOOL: + if (val instanceof Boolean) { + protoMsg.addRepeatedField(fieldDescriptor, (Boolean) val); + } else { + fail = true; + } + break; + case BYTES: + if (val instanceof String) { + protoMsg.addRepeatedField(fieldDescriptor, ((String) val).getBytes()); + } else { + fail = true; + } + break; + case INT64: + if (val instanceof Integer) { + protoMsg.addRepeatedField(fieldDescriptor, new Long((Integer) val)); + } else if (val instanceof Long) { + protoMsg.addRepeatedField(fieldDescriptor, (Long) val); + } else { + fail = true; + } + break; + case INT32: + if (val instanceof Integer) { + protoMsg.addRepeatedField(fieldDescriptor, (Integer) val); + } else { + fail = true; + } + break; + case STRING: + if (val instanceof String) { + protoMsg.addRepeatedField(fieldDescriptor, (String) val); + } else { + fail = true; + } + break; + case DOUBLE: + if (val instanceof Double) { + protoMsg.addRepeatedField(fieldDescriptor, (Double) val); + } else if (val instanceof Float) { + protoMsg.addRepeatedField(fieldDescriptor, new Double((float) val)); + } else { + fail = true; + } + break; + case MESSAGE: + if (val instanceof JSONObject) { + Message.Builder message = protoMsg.newBuilderForField(fieldDescriptor); + protoMsg.addRepeatedField( + fieldDescriptor, + convertJsonToProtoMessageImpl( + fieldDescriptor.getMessageType(), + jsonArray.getJSONObject(i), + currentScope, + /*topLevel =*/ false, + allowUnknownFields)); + } else { + fail = true; + } + break; + } + if (fail) { + throw new IllegalArgumentException( + String.format( + "JSONObject does not have a %s field at %s[%d].", + FieldTypeToDebugMessage.get(fieldDescriptor.getType()), currentScope, index)); + } + } + } +} diff --git a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/SchemaCompatibility.java b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/SchemaCompatibility.java index 2600e7a9d1..bbf3bfc62c 100644 --- a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/SchemaCompatibility.java +++ b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/SchemaCompatibility.java @@ -23,6 +23,7 @@ import com.google.cloud.bigquery.TableId; import com.google.cloud.bigquery.testing.RemoteBigQueryHelper; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; import com.google.protobuf.Descriptors; import java.util.Arrays; import java.util.Collections; @@ -43,7 +44,7 @@ */ public class SchemaCompatibility { private BigQuery bigquery; - private static SchemaCompatibility compact; + private static SchemaCompatibility compat; private static String tablePatternString = "projects/([^/]+)/datasets/([^/]+)/tables/([^/]+)"; private static Pattern tablePattern = Pattern.compile(tablePatternString); private static final int NestingLimit = 15; @@ -81,11 +82,11 @@ private SchemaCompatibility(BigQuery bigquery) { * @return */ public static SchemaCompatibility getInstance() { - if (compact == null) { + if (compat == null) { RemoteBigQueryHelper bigqueryHelper = RemoteBigQueryHelper.create(); - compact = new SchemaCompatibility(bigqueryHelper.getOptions().getService()); + compat = new SchemaCompatibility(bigqueryHelper.getOptions().getService()); } - return compact; + return compat; } /** @@ -96,6 +97,7 @@ public static SchemaCompatibility getInstance() { */ @VisibleForTesting public static SchemaCompatibility getInstance(BigQuery bigquery) { + Preconditions.checkNotNull(bigquery, "BigQuery is null."); return new SchemaCompatibility(bigquery); } @@ -112,6 +114,7 @@ private TableId getTableId(String tableName) { * @return True if fieldtype is supported by BQ Schema */ public static boolean isSupportedType(Descriptors.FieldDescriptor field) { + Preconditions.checkNotNull(field, "Field is null."); Descriptors.FieldDescriptor.Type fieldType = field.getType(); if (!SupportedTypes.contains(fieldType)) { return false; @@ -508,6 +511,9 @@ private void isProtoCompatibleWithBQ( public void check( String BQTableName, Descriptors.Descriptor protoSchema, boolean allowUnknownFields) throws IllegalArgumentException { + Preconditions.checkNotNull(BQTableName, "TableName is null."); + Preconditions.checkNotNull(protoSchema, "Protobuf descriptor is null."); + TableId tableId = getTableId(BQTableName); Table table = bigquery.getTable(tableId); Schema BQSchema = table.getDefinition().getSchema(); diff --git a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/StreamWriter.java b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/StreamWriter.java index 9bc08fe1ce..f3bd103d0b 100644 --- a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/StreamWriter.java +++ b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/StreamWriter.java @@ -217,7 +217,7 @@ public Boolean expired() { */ public ApiFuture append(AppendRowsRequest message) { Preconditions.checkState(!shutdown.get(), "Cannot append on a shut-down writer."); - + Preconditions.checkNotNull(message, "Message is null."); final AppendRequestAndFutureResponse outstandingAppend = new AppendRequestAndFutureResponse(message); List batchesToSend; @@ -556,6 +556,7 @@ protected boolean awaitTermination(long duration, TimeUnit unit) throws Interrup * } */ public static Builder newBuilder(String streamName) { + Preconditions.checkNotNull(streamName, "StreamName is null."); return new Builder(streamName, null); } @@ -563,7 +564,8 @@ public static Builder newBuilder(String streamName) { * Constructs a new {@link Builder} using the given stream and an existing BigQueryWriteClient. */ public static Builder newBuilder(String streamName, BigQueryWriteClient client) { - Preconditions.checkArgument(client != null); + Preconditions.checkNotNull(streamName, "StreamName is null."); + Preconditions.checkNotNull(client, "Client is null."); return new Builder(streamName, client); } @@ -631,13 +633,15 @@ private Builder(String stream, BigQueryWriteClient client) { * {@link com.google.api.gax.grpc.InstantiatingGrpcChannelProvider.Builder#setPoolSize(int)}. */ public Builder setChannelProvider(TransportChannelProvider channelProvider) { - this.channelProvider = Preconditions.checkNotNull(channelProvider); + this.channelProvider = + Preconditions.checkNotNull(channelProvider, "ChannelProvider is null."); return this; } /** {@code CredentialsProvider} to use to create Credentials to authenticate calls. */ public Builder setCredentialsProvider(CredentialsProvider credentialsProvider) { - this.credentialsProvider = Preconditions.checkNotNull(credentialsProvider); + this.credentialsProvider = + Preconditions.checkNotNull(credentialsProvider, "CredentialsProvider is null."); return this; } @@ -648,7 +652,7 @@ public Builder setCredentialsProvider(CredentialsProvider credentialsProvider) { * @return */ public Builder setBatchingSettings(BatchingSettings batchingSettings) { - Preconditions.checkNotNull(batchingSettings); + Preconditions.checkNotNull(batchingSettings, "BatchingSettings is null."); BatchingSettings.Builder builder = batchingSettings.toBuilder(); Preconditions.checkNotNull(batchingSettings.getElementCountThreshold()); @@ -722,20 +726,20 @@ > getApiMaxInflightRequests()) { * @return */ public Builder setRetrySettings(RetrySettings retrySettings) { - Preconditions.checkNotNull(retrySettings); - this.retrySettings = retrySettings; + this.retrySettings = Preconditions.checkNotNull(retrySettings, "RetrySettings is null."); return this; } /** Gives the ability to set a custom executor to be used by the library. */ public Builder setExecutorProvider(ExecutorProvider executorProvider) { - this.executorProvider = Preconditions.checkNotNull(executorProvider); + this.executorProvider = + Preconditions.checkNotNull(executorProvider, "ExecutorProvider is null."); return this; } /** Gives the ability to override the gRPC endpoint. */ public Builder setEndpoint(String endpoint) { - this.endpoint = endpoint; + this.endpoint = Preconditions.checkNotNull(endpoint, "Endpoint is null."); return this; } diff --git a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/WriterCache.java b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/WriterCache.java index a8e48e0759..7f9019bafe 100644 --- a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/WriterCache.java +++ b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/WriterCache.java @@ -16,6 +16,7 @@ package com.google.cloud.bigquery.storage.v1alpha2; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.cache.RemovalListener; @@ -47,11 +48,11 @@ public class WriterCache { private static final int MAX_WRITERS_PER_TABLE = 2; private final BigQueryWriteClient stub; - private final SchemaCompatibility compact; + private final SchemaCompatibility compat; - private WriterCache(BigQueryWriteClient stub, int maxTableEntry, SchemaCompatibility compact) { + private WriterCache(BigQueryWriteClient stub, int maxTableEntry, SchemaCompatibility compat) { this.stub = stub; - this.compact = compact; + this.compat = compat; writerCache = CacheBuilder.newBuilder() .maximumSize(maxTableEntry) @@ -79,8 +80,10 @@ public static WriterCache getInstance() throws IOException { /** Returns a cache with custom stub used by test. */ @VisibleForTesting public static WriterCache getTestInstance( - BigQueryWriteClient stub, int maxTableEntry, SchemaCompatibility compact) { - return new WriterCache(stub, maxTableEntry, compact); + BigQueryWriteClient stub, int maxTableEntry, SchemaCompatibility compat) { + Preconditions.checkNotNull(stub, "Stub is null."); + Preconditions.checkNotNull(stub, "Compat is null."); + return new WriterCache(stub, maxTableEntry, compat); } /** Returns an entry with {@code StreamWriter} and expiration time in millis. */ @@ -115,6 +118,8 @@ StreamWriter CreateNewWriter(String streamName) */ public StreamWriter getTableWriter(String tableName, Descriptor userSchema) throws IllegalArgumentException, IOException, InterruptedException { + Preconditions.checkNotNull(tableName, "TableName is null."); + Preconditions.checkNotNull(tableName, "UserSchema is null."); Matcher matcher = tablePattern.matcher(tableName); if (!matcher.matches()) { throw new IllegalArgumentException("Invalid table name: " + tableName); @@ -136,12 +141,12 @@ public StreamWriter getTableWriter(String tableName, Descriptor userSchema) writer.close(); } } - compact.check(tableName, userSchema); + compat.check(tableName, userSchema); streamName = CreateNewStream(tableName); writer = CreateNewWriter(streamName); tableEntry.put(userSchema, writer); } else { - compact.check(tableName, userSchema); + compat.check(tableName, userSchema); streamName = CreateNewStream(tableName); tableEntry = CacheBuilder.newBuilder() diff --git a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1beta1/BaseBigQueryStorageClient.java b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1beta1/BaseBigQueryStorageClient.java index c587b00d52..8f337335b5 100644 --- a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1beta1/BaseBigQueryStorageClient.java +++ b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1beta1/BaseBigQueryStorageClient.java @@ -50,7 +50,7 @@ * * try (BaseBigQueryStorageClient baseBigQueryStorageClient = BaseBigQueryStorageClient.create()) { * TableReference tableReference = TableReference.newBuilder().build(); - * String parent = ""; + * ProjectName parent = ProjectName.of("[PROJECT]"); * int requestedStreams = 0; * ReadSession response = baseBigQueryStorageClient.createReadSession(tableReference, parent, requestedStreams); * } @@ -180,7 +180,7 @@ public BigQueryStorageStub getStub() { *

    * try (BaseBigQueryStorageClient baseBigQueryStorageClient = BaseBigQueryStorageClient.create()) {
    *   TableReference tableReference = TableReference.newBuilder().build();
-   *   String parent = "";
+   *   ProjectName parent = ProjectName.of("[PROJECT]");
    *   int requestedStreams = 0;
    *   ReadSession response = baseBigQueryStorageClient.createReadSession(tableReference, parent, requestedStreams);
    * }
@@ -196,6 +196,51 @@ public BigQueryStorageStub getStub() {
    *     

Streams must be read starting from offset 0. * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ + public final ReadSession createReadSession( + TableReference tableReference, ProjectName parent, int requestedStreams) { + CreateReadSessionRequest request = + CreateReadSessionRequest.newBuilder() + .setTableReference(tableReference) + .setParent(parent == null ? null : parent.toString()) + .setRequestedStreams(requestedStreams) + .build(); + return createReadSession(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD + /** + * Creates a new read session. A read session divides the contents of a BigQuery table into one or + * more streams, which can then be used to read data from the table. The read session also + * specifies properties of the data to be read, such as a list of columns or a push-down filter + * describing the rows to be returned. + * + *

A particular row can be read by at most one stream. When the caller has reached the end of + * each stream in the session, then all the data in the table has been read. + * + *

Read sessions automatically expire 24 hours after they are created and do not require manual + * clean-up by the caller. + * + *

Sample code: + * + *


+   * try (BaseBigQueryStorageClient baseBigQueryStorageClient = BaseBigQueryStorageClient.create()) {
+   *   TableReference tableReference = TableReference.newBuilder().build();
+   *   ProjectName parent = ProjectName.of("[PROJECT]");
+   *   int requestedStreams = 0;
+   *   ReadSession response = baseBigQueryStorageClient.createReadSession(tableReference, parent.toString(), requestedStreams);
+   * }
+   * 
+ * + * @param tableReference Required. Reference to the table to read. + * @param parent Required. String of the form `projects/{project_id}` indicating the project this + * ReadSession is associated with. This is the project that will be billed for usage. + * @param requestedStreams Initial number of streams. If unset or 0, we will provide a value of + * streams so as to produce reasonable throughput. Must be non-negative. The number of streams + * may be lower than the requested number, depending on the amount parallelism that is + * reasonable for the table and the maximum amount of parallelism allowed by the system. + *

Streams must be read starting from offset 0. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ public final ReadSession createReadSession( TableReference tableReference, String parent, int requestedStreams) { CreateReadSessionRequest request = @@ -225,10 +270,10 @@ public final ReadSession createReadSession( *


    * try (BaseBigQueryStorageClient baseBigQueryStorageClient = BaseBigQueryStorageClient.create()) {
    *   TableReference tableReference = TableReference.newBuilder().build();
-   *   String parent = "";
+   *   ProjectName parent = ProjectName.of("[PROJECT]");
    *   CreateReadSessionRequest request = CreateReadSessionRequest.newBuilder()
    *     .setTableReference(tableReference)
-   *     .setParent(parent)
+   *     .setParent(parent.toString())
    *     .build();
    *   ReadSession response = baseBigQueryStorageClient.createReadSession(request);
    * }
@@ -259,10 +304,10 @@ public final ReadSession createReadSession(CreateReadSessionRequest request) {
    * 

    * try (BaseBigQueryStorageClient baseBigQueryStorageClient = BaseBigQueryStorageClient.create()) {
    *   TableReference tableReference = TableReference.newBuilder().build();
-   *   String parent = "";
+   *   ProjectName parent = ProjectName.of("[PROJECT]");
    *   CreateReadSessionRequest request = CreateReadSessionRequest.newBuilder()
    *     .setTableReference(tableReference)
-   *     .setParent(parent)
+   *     .setParent(parent.toString())
    *     .build();
    *   ApiFuture<ReadSession> future = baseBigQueryStorageClient.createReadSessionCallable().futureCall(request);
    *   // Do something
diff --git a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1beta1/package-info.java b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1beta1/package-info.java
index 2bbccfac2c..5c0d3b601e 100644
--- a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1beta1/package-info.java
+++ b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1beta1/package-info.java
@@ -31,7 +31,7 @@
  * 
  * try (BaseBigQueryStorageClient baseBigQueryStorageClient = BaseBigQueryStorageClient.create()) {
  *   TableReference tableReference = TableReference.newBuilder().build();
- *   String parent = "";
+ *   ProjectName parent = ProjectName.of("[PROJECT]");
  *   int requestedStreams = 0;
  *   ReadSession response = baseBigQueryStorageClient.createReadSession(tableReference, parent, requestedStreams);
  * }
diff --git a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1beta1/stub/BigQueryStorageStubSettings.java b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1beta1/stub/BigQueryStorageStubSettings.java
index 3ce39e32fe..1cf3ac0ccc 100644
--- a/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1beta1/stub/BigQueryStorageStubSettings.java
+++ b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1beta1/stub/BigQueryStorageStubSettings.java
@@ -229,13 +229,18 @@ public static class Builder extends StubSettings.Builder> definitions =
           ImmutableMap.builder();
       definitions.put(
-          "idempotent",
+          "retry_policy_1_codes",
           ImmutableSet.copyOf(
               Lists.newArrayList(
                   StatusCode.Code.DEADLINE_EXCEEDED, StatusCode.Code.UNAVAILABLE)));
-      definitions.put("non_idempotent", ImmutableSet.copyOf(Lists.newArrayList()));
+      definitions.put("no_retry_codes", ImmutableSet.copyOf(Lists.newArrayList()));
       definitions.put(
-          "unary_streaming",
+          "retry_policy_3_codes",
+          ImmutableSet.copyOf(
+              Lists.newArrayList(
+                  StatusCode.Code.DEADLINE_EXCEEDED, StatusCode.Code.UNAVAILABLE)));
+      definitions.put(
+          "retry_policy_2_codes",
           ImmutableSet.copyOf(Lists.newArrayList(StatusCode.Code.UNAVAILABLE)));
       RETRYABLE_CODE_DEFINITIONS = definitions.build();
     }
@@ -250,34 +255,36 @@ public static class Builder extends StubSettings.Builder AllTypesToDebugMessageTest =
+      new ImmutableMap.Builder()
+          .put(BoolType.getDescriptor(), "boolean")
+          .put(BytesType.getDescriptor(), "string")
+          .put(Int64Type.getDescriptor(), "int64")
+          .put(Int32Type.getDescriptor(), "int32")
+          .put(DoubleType.getDescriptor(), "double")
+          .put(StringType.getDescriptor(), "string")
+          .put(RepeatedType.getDescriptor(), "array")
+          .put(ObjectType.getDescriptor(), "object")
+          .build();
+
+  private static ImmutableMap AllTypesToCorrectProto =
+      new ImmutableMap.Builder()
+          .put(
+              BoolType.getDescriptor(),
+              new Message[] {BoolType.newBuilder().setTestFieldType(true).build()})
+          .put(
+              BytesType.getDescriptor(),
+              new Message[] {
+                BytesType.newBuilder()
+                    .setTestFieldType(ByteString.copyFrom("test".getBytes()))
+                    .build()
+              })
+          .put(
+              Int64Type.getDescriptor(),
+              new Message[] {
+                Int64Type.newBuilder().setTestFieldType(Long.MAX_VALUE).build(),
+                Int64Type.newBuilder().setTestFieldType(new Long(Integer.MAX_VALUE)).build()
+              })
+          .put(
+              Int32Type.getDescriptor(),
+              new Message[] {Int32Type.newBuilder().setTestFieldType(Integer.MAX_VALUE).build()})
+          .put(
+              DoubleType.getDescriptor(),
+              new Message[] {DoubleType.newBuilder().setTestFieldType(1.23).build()})
+          .put(
+              StringType.getDescriptor(),
+              new Message[] {StringType.newBuilder().setTestFieldType("test").build()})
+          .put(
+              RepeatedType.getDescriptor(),
+              new Message[] {
+                RepeatedType.newBuilder()
+                    .addAllTestFieldType(
+                        new ArrayList() {
+                          {
+                            add(1L);
+                            add(2L);
+                            add(3L);
+                          }
+                        })
+                    .build()
+              })
+          .put(
+              ObjectType.getDescriptor(),
+              new Message[] {
+                ObjectType.newBuilder()
+                    .setTestFieldType(ComplexLvl2.newBuilder().setTestInt(1).build())
+                    .build()
+              })
+          .build();
+
+  private static ImmutableMap AllRepeatedTypesToDebugMessageTest =
+      new ImmutableMap.Builder()
+          .put(RepeatedBool.getDescriptor(), "boolean")
+          .put(RepeatedBytes.getDescriptor(), "string")
+          .put(RepeatedInt64.getDescriptor(), "int64")
+          .put(RepeatedInt32.getDescriptor(), "int32")
+          .put(RepeatedDouble.getDescriptor(), "double")
+          .put(RepeatedString.getDescriptor(), "string")
+          .put(RepeatedObject.getDescriptor(), "object")
+          .build();
+
+  private static ImmutableMap AllRepeatedTypesToCorrectProto =
+      new ImmutableMap.Builder()
+          .put(
+              RepeatedBool.getDescriptor(),
+              new Message[] {
+                RepeatedBool.newBuilder().addTestRepeated(true).addTestRepeated(false).build()
+              })
+          .put(
+              RepeatedBytes.getDescriptor(),
+              new Message[] {
+                RepeatedBytes.newBuilder()
+                    .addTestRepeated(ByteString.copyFrom("hello".getBytes()))
+                    .addTestRepeated(ByteString.copyFrom("test".getBytes()))
+                    .build()
+              })
+          .put(
+              RepeatedString.getDescriptor(),
+              new Message[] {
+                RepeatedString.newBuilder().addTestRepeated("hello").addTestRepeated("test").build()
+              })
+          .put(
+              RepeatedInt64.getDescriptor(),
+              new Message[] {
+                RepeatedInt64.newBuilder()
+                    .addTestRepeated(Long.MAX_VALUE)
+                    .addTestRepeated(Long.MIN_VALUE)
+                    .addTestRepeated(Integer.MAX_VALUE)
+                    .addTestRepeated(Integer.MIN_VALUE)
+                    .addTestRepeated(Short.MAX_VALUE)
+                    .addTestRepeated(Short.MIN_VALUE)
+                    .addTestRepeated(Byte.MAX_VALUE)
+                    .addTestRepeated(Byte.MIN_VALUE)
+                    .addTestRepeated(0)
+                    .build(),
+                RepeatedInt64.newBuilder()
+                    .addTestRepeated(Integer.MAX_VALUE)
+                    .addTestRepeated(Integer.MIN_VALUE)
+                    .addTestRepeated(Short.MAX_VALUE)
+                    .addTestRepeated(Short.MIN_VALUE)
+                    .addTestRepeated(Byte.MAX_VALUE)
+                    .addTestRepeated(Byte.MIN_VALUE)
+                    .addTestRepeated(0)
+                    .build()
+              })
+          .put(
+              RepeatedInt32.getDescriptor(),
+              new Message[] {
+                RepeatedInt32.newBuilder()
+                    .addTestRepeated(Integer.MAX_VALUE)
+                    .addTestRepeated(Integer.MIN_VALUE)
+                    .addTestRepeated(Short.MAX_VALUE)
+                    .addTestRepeated(Short.MIN_VALUE)
+                    .addTestRepeated(Byte.MAX_VALUE)
+                    .addTestRepeated(Byte.MIN_VALUE)
+                    .addTestRepeated(0)
+                    .build()
+              })
+          .put(
+              RepeatedDouble.getDescriptor(),
+              new Message[] {
+                RepeatedDouble.newBuilder()
+                    .addTestRepeated(Double.MAX_VALUE)
+                    .addTestRepeated(Double.MIN_VALUE)
+                    .addTestRepeated(Float.MAX_VALUE)
+                    .addTestRepeated(Float.MIN_VALUE)
+                    .build(),
+                RepeatedDouble.newBuilder()
+                    .addTestRepeated(Float.MAX_VALUE)
+                    .addTestRepeated(Float.MIN_VALUE)
+                    .build()
+              })
+          .put(
+              RepeatedObject.getDescriptor(),
+              new Message[] {
+                RepeatedObject.newBuilder()
+                    .addTestRepeated(ComplexLvl2.newBuilder().setTestInt(1).build())
+                    .addTestRepeated(ComplexLvl2.newBuilder().setTestInt(2).build())
+                    .addTestRepeated(ComplexLvl2.newBuilder().setTestInt(3).build())
+                    .build()
+              })
+          .build();
+
+  private static JSONObject[] simpleJSONObjects = {
+    new JSONObject().put("test_field_type", Long.MAX_VALUE),
+    new JSONObject().put("test_field_type", Integer.MAX_VALUE),
+    new JSONObject().put("test_field_type", 1.23),
+    new JSONObject().put("test_field_type", true),
+    new JSONObject().put("test_field_type", "test"),
+    new JSONObject().put("test_field_type", new JSONArray("[1, 2, 3]")),
+    new JSONObject().put("test_field_type", new JSONObject().put("test_int", 1))
+  };
+
+  private static JSONObject[] simpleJSONArrays = {
+    new JSONObject()
+        .put(
+            "test_repeated",
+            new JSONArray(
+                new Long[] {
+                  Long.MAX_VALUE,
+                  Long.MIN_VALUE,
+                  (long) Integer.MAX_VALUE,
+                  (long) Integer.MIN_VALUE,
+                  (long) Short.MAX_VALUE,
+                  (long) Short.MIN_VALUE,
+                  (long) Byte.MAX_VALUE,
+                  (long) Byte.MIN_VALUE,
+                  0L
+                })),
+    new JSONObject()
+        .put(
+            "test_repeated",
+            new JSONArray(
+                new Integer[] {
+                  Integer.MAX_VALUE,
+                  Integer.MIN_VALUE,
+                  (int) Short.MAX_VALUE,
+                  (int) Short.MIN_VALUE,
+                  (int) Byte.MAX_VALUE,
+                  (int) Byte.MIN_VALUE,
+                  0
+                })),
+    new JSONObject()
+        .put(
+            "test_repeated",
+            new JSONArray(
+                new Double[] {
+                  Double.MAX_VALUE,
+                  Double.MIN_VALUE,
+                  (double) Float.MAX_VALUE,
+                  (double) Float.MIN_VALUE
+                })),
+    new JSONObject()
+        .put("test_repeated", new JSONArray(new Float[] {Float.MAX_VALUE, Float.MIN_VALUE})),
+    new JSONObject().put("test_repeated", new JSONArray(new Boolean[] {true, false})),
+    new JSONObject().put("test_repeated", new JSONArray(new String[] {"hello", "test"})),
+    new JSONObject()
+        .put(
+            "test_repeated",
+            new JSONArray(
+                new JSONObject[] {
+                  new JSONObject().put("test_int", 1),
+                  new JSONObject().put("test_int", 2),
+                  new JSONObject().put("test_int", 3)
+                }))
+  };
+
+  @Test
+  public void testDifferentNameCasing() throws Exception {
+    TestInt64 expectedProto =
+        TestInt64.newBuilder().setByte(1).setShort(1).setInt(1).setLong(1).build();
+
+    JSONObject json = new JSONObject();
+    json.put("bYtE", (byte) 1);
+    json.put("SHORT", (short) 1);
+    json.put("inT", 1);
+    json.put("lONg", 1L);
+    DynamicMessage protoMsg =
+        JsonToProtoMessage.convertJsonToProtoMessage(TestInt64.getDescriptor(), json, false);
+    assertEquals(protoMsg, expectedProto);
+  }
+
+  @Test
+  public void testInt64() throws Exception {
+    TestInt64 expectedProto =
+        TestInt64.newBuilder().setByte(1).setShort(1).setInt(1).setLong(1).build();
+    JSONObject json = new JSONObject();
+    json.put("byte", (byte) 1);
+    json.put("short", (short) 1);
+    json.put("int", 1);
+    json.put("long", 1L);
+    DynamicMessage protoMsg =
+        JsonToProtoMessage.convertJsonToProtoMessage(TestInt64.getDescriptor(), json, false);
+    assertEquals(protoMsg, expectedProto);
+  }
+
+  @Test
+  public void testInt32() throws Exception {
+    TestInt32 expectedProto = TestInt32.newBuilder().setByte(1).setShort(1).setInt(1).build();
+    JSONObject json = new JSONObject();
+    json.put("byte", (byte) 1);
+    json.put("short", (short) 1);
+    json.put("int", 1);
+    DynamicMessage protoMsg =
+        JsonToProtoMessage.convertJsonToProtoMessage(TestInt32.getDescriptor(), json, false);
+    assertEquals(protoMsg, expectedProto);
+  }
+
+  @Test
+  public void testInt32NotMatchInt64() throws Exception {
+    JSONObject json = new JSONObject();
+    json.put("byte", (byte) 1);
+    json.put("short", (short) 1);
+    json.put("int", 1L);
+    try {
+      DynamicMessage protoMsg =
+          JsonToProtoMessage.convertJsonToProtoMessage(TestInt32.getDescriptor(), json, false);
+    } catch (IllegalArgumentException e) {
+      assertEquals(e.getMessage(), "JSONObject does not have a int32 field at root.int.");
+    }
+  }
+
+  @Test
+  public void testDouble() throws Exception {
+    TestDouble expectedProto = TestDouble.newBuilder().setDouble(1.2).setFloat(3.4f).build();
+    JSONObject json = new JSONObject();
+    json.put("double", 1.2);
+    json.put("float", 3.4f);
+    DynamicMessage protoMsg =
+        JsonToProtoMessage.convertJsonToProtoMessage(TestDouble.getDescriptor(), json, false);
+    assertEquals(protoMsg, expectedProto);
+  }
+
+  @Test
+  public void testAllTypes() throws Exception {
+    for (Map.Entry entry : AllTypesToDebugMessageTest.entrySet()) {
+      int success = 0;
+      for (JSONObject json : simpleJSONObjects) {
+        try {
+          DynamicMessage protoMsg =
+              JsonToProtoMessage.convertJsonToProtoMessage(entry.getKey(), json, false);
+          assertEquals(protoMsg, AllTypesToCorrectProto.get(entry.getKey())[success]);
+          success += 1;
+        } catch (IllegalArgumentException e) {
+          assertEquals(
+              e.getMessage(),
+              "JSONObject does not have a " + entry.getValue() + " field at root.test_field_type.");
+        }
+      }
+      if (entry.getKey() == Int64Type.getDescriptor()) {
+        assertEquals(2, success);
+      } else {
+        assertEquals(1, success);
+      }
+    }
+  }
+
+  @Test
+  public void testAllRepeatedTypesWithLimits() throws Exception {
+    for (Map.Entry entry : AllRepeatedTypesToDebugMessageTest.entrySet()) {
+      int success = 0;
+      for (JSONObject json : simpleJSONArrays) {
+        try {
+          DynamicMessage protoMsg =
+              JsonToProtoMessage.convertJsonToProtoMessage(entry.getKey(), json, false);
+          assertEquals(protoMsg, AllRepeatedTypesToCorrectProto.get(entry.getKey())[success]);
+          success += 1;
+        } catch (IllegalArgumentException e) {
+          assertEquals(
+              e.getMessage(),
+              "JSONObject does not have a "
+                  + entry.getValue()
+                  + " field at root.test_repeated[0].");
+        }
+      }
+      if (entry.getKey() == RepeatedInt64.getDescriptor()
+          || entry.getKey() == RepeatedDouble.getDescriptor()) {
+        assertEquals(2, success);
+      } else {
+        assertEquals(1, success);
+      }
+    }
+  }
+
+  @Test
+  public void testOptional() throws Exception {
+    TestInt64 expectedProto = TestInt64.newBuilder().setByte(1).build();
+    JSONObject json = new JSONObject();
+    json.put("byte", 1);
+
+    DynamicMessage protoMsg =
+        JsonToProtoMessage.convertJsonToProtoMessage(TestInt64.getDescriptor(), json, false);
+    assertEquals(protoMsg, expectedProto);
+  }
+
+  @Test
+  public void testRepeatedIsOptional() throws Exception {
+    TestRepeatedIsOptional expectedProto =
+        TestRepeatedIsOptional.newBuilder().setRequiredDouble(1.1).build();
+    JSONObject json = new JSONObject();
+    json.put("required_double", 1.1);
+
+    DynamicMessage protoMsg =
+        JsonToProtoMessage.convertJsonToProtoMessage(
+            TestRepeatedIsOptional.getDescriptor(), json, false);
+    assertEquals(protoMsg, expectedProto);
+  }
+
+  @Test
+  public void testRequired() throws Exception {
+    JSONObject json = new JSONObject();
+    json.put("optional_double", 1.1);
+    try {
+      DynamicMessage protoMsg =
+          JsonToProtoMessage.convertJsonToProtoMessage(TestRequired.getDescriptor(), json, false);
+    } catch (IllegalArgumentException e) {
+      assertEquals(
+          e.getMessage(), "JSONObject does not have the required field root.required_double.");
+    }
+  }
+
+  @Test
+  public void testStructSimple() throws Exception {
+    MessageType expectedProto =
+        MessageType.newBuilder()
+            .setTestFieldType(StringType.newBuilder().setTestFieldType("test").build())
+            .build();
+    JSONObject stringType = new JSONObject();
+    stringType.put("test_field_type", "test");
+    JSONObject json = new JSONObject();
+    json.put("test_field_type", stringType);
+
+    DynamicMessage protoMsg =
+        JsonToProtoMessage.convertJsonToProtoMessage(MessageType.getDescriptor(), json, false);
+    assertEquals(protoMsg, expectedProto);
+  }
+
+  @Test
+  public void testStructSimpleFail() throws Exception {
+    JSONObject stringType = new JSONObject();
+    stringType.put("test_field_type", 1);
+    JSONObject json = new JSONObject();
+    json.put("test_field_type", stringType);
+    try {
+      DynamicMessage protoMsg =
+          JsonToProtoMessage.convertJsonToProtoMessage(MessageType.getDescriptor(), json, false);
+    } catch (IllegalArgumentException e) {
+      assertEquals(
+          e.getMessage(),
+          "JSONObject does not have a string field at root.test_field_type.test_field_type.");
+    }
+  }
+
+  @Test
+  public void testStructComplex() throws Exception {
+    ComplexRoot expectedProto =
+        ComplexRoot.newBuilder()
+            .setTestInt(1)
+            .addTestString("a")
+            .addTestString("b")
+            .addTestString("c")
+            .setTestBytes(ByteString.copyFrom("hello".getBytes()))
+            .setTestBool(true)
+            .addTestDouble(1.1)
+            .addTestDouble(2.2)
+            .addTestDouble(3.3)
+            .addTestDouble(4.4)
+            .setTestDate(1)
+            .setComplexLvl1(
+                ComplexLvl1.newBuilder()
+                    .setTestInt(2)
+                    .setComplexLvl2(ComplexLvl2.newBuilder().setTestInt(3).build())
+                    .build())
+            .setComplexLvl2(ComplexLvl2.newBuilder().setTestInt(3).build())
+            .build();
+    JSONObject complex_lvl2 = new JSONObject();
+    complex_lvl2.put("test_int", 3);
+
+    JSONObject complex_lvl1 = new JSONObject();
+    complex_lvl1.put("test_int", 2);
+    complex_lvl1.put("complex_lvl2", complex_lvl2);
+
+    JSONObject json = new JSONObject();
+    json.put("test_int", 1);
+    json.put("test_string", new JSONArray(new String[] {"a", "b", "c"}));
+    json.put("test_bytes", "hello");
+    json.put("test_bool", true);
+    json.put("test_DOUBLe", new JSONArray(new Double[] {1.1, 2.2, 3.3, 4.4}));
+    json.put("test_date", 1);
+    json.put("complex_lvl1", complex_lvl1);
+    json.put("complex_lvl2", complex_lvl2);
+
+    DynamicMessage protoMsg =
+        JsonToProtoMessage.convertJsonToProtoMessage(ComplexRoot.getDescriptor(), json, false);
+    assertEquals(protoMsg, expectedProto);
+  }
+
+  @Test
+  public void testStructComplexFail() throws Exception {
+    JSONObject complex_lvl2 = new JSONObject();
+    complex_lvl2.put("test_int", 3);
+
+    JSONObject complex_lvl1 = new JSONObject();
+    complex_lvl1.put("test_int", "not_int");
+    complex_lvl1.put("complex_lvl2", complex_lvl2);
+
+    JSONObject json = new JSONObject();
+    json.put("test_int", 1);
+    json.put("test_string", new JSONArray(new String[] {"a", "b", "c"}));
+    json.put("test_bytes", "hello");
+    json.put("test_bool", true);
+    json.put("test_double", new JSONArray(new Double[] {1.1, 2.2, 3.3, 4.4}));
+    json.put("test_date", 1);
+    json.put("complex_lvl1", complex_lvl1);
+    json.put("complex_lvl2", complex_lvl2);
+
+    try {
+      DynamicMessage protoMsg =
+          JsonToProtoMessage.convertJsonToProtoMessage(ComplexRoot.getDescriptor(), json, false);
+    } catch (IllegalArgumentException e) {
+      assertEquals(
+          e.getMessage(), "JSONObject does not have a int64 field at root.complex_lvl1.test_int.");
+    }
+  }
+
+  @Test
+  public void testRepeatedWithMixedTypes() throws Exception {
+    JSONObject json = new JSONObject();
+    json.put("test_repeated", new JSONArray("[1.1, 2.2, true]"));
+    try {
+      DynamicMessage protoMsg =
+          JsonToProtoMessage.convertJsonToProtoMessage(RepeatedDouble.getDescriptor(), json, false);
+    } catch (IllegalArgumentException e) {
+      assertEquals(
+          e.getMessage(), "JSONObject does not have a double field at root.test_repeated[2].");
+    }
+  }
+
+  @Test
+  public void testNestedRepeatedComplex() throws Exception {
+    NestedRepeated expectedProto =
+        NestedRepeated.newBuilder()
+            .addDouble(1.1)
+            .addDouble(2.2)
+            .addDouble(3.3)
+            .addDouble(4.4)
+            .addDouble(5.5)
+            .addInt(1)
+            .addInt(2)
+            .addInt(3)
+            .addInt(4)
+            .addInt(5)
+            .setRepeatedString(
+                RepeatedString.newBuilder()
+                    .addTestRepeated("hello")
+                    .addTestRepeated("this")
+                    .addTestRepeated("is")
+                    .addTestRepeated("a")
+                    .addTestRepeated("test")
+                    .build())
+            .build();
+    double[] doubleArr = {1.1, 2.2, 3.3, 4.4, 5.5};
+    String[] stringArr = {"hello", "this", "is", "a", "test"};
+    int[] intArr = {1, 2, 3, 4, 5};
+
+    JSONObject json = new JSONObject();
+    json.put("double", new JSONArray(doubleArr));
+    json.put("int", new JSONArray(intArr));
+    JSONObject jsonRepeatedString = new JSONObject();
+    jsonRepeatedString.put("test_repeated", new JSONArray(stringArr));
+    json.put("repeated_string", jsonRepeatedString);
+
+    DynamicMessage protoMsg =
+        JsonToProtoMessage.convertJsonToProtoMessage(NestedRepeated.getDescriptor(), json, false);
+    assertEquals(protoMsg, expectedProto);
+  }
+
+  @Test
+  public void testNestedRepeatedComplexFail() throws Exception {
+    double[] doubleArr = {1.1, 2.2, 3.3, 4.4, 5.5};
+    Boolean[] fakeStringArr = {true, false};
+    int[] intArr = {1, 2, 3, 4, 5};
+
+    JSONObject json = new JSONObject();
+    json.put("double", new JSONArray(doubleArr));
+    json.put("int", new JSONArray(intArr));
+    JSONObject jsonRepeatedString = new JSONObject();
+    jsonRepeatedString.put("test_repeated", new JSONArray(fakeStringArr));
+    json.put("repeated_string", jsonRepeatedString);
+
+    try {
+      DynamicMessage protoMsg =
+          JsonToProtoMessage.convertJsonToProtoMessage(NestedRepeated.getDescriptor(), json, false);
+    } catch (IllegalArgumentException e) {
+      assertEquals(
+          e.getMessage(),
+          "JSONObject does not have a string field at root.repeated_string.test_repeated[0].");
+    }
+  }
+
+  @Test
+  public void testAllowUnknownFields() throws Exception {
+    RepeatedInt64 expectedProto =
+        RepeatedInt64.newBuilder()
+            .addTestRepeated(1)
+            .addTestRepeated(2)
+            .addTestRepeated(3)
+            .addTestRepeated(4)
+            .addTestRepeated(5)
+            .build();
+    JSONObject json = new JSONObject();
+    json.put("test_repeated", new JSONArray(new int[] {1, 2, 3, 4, 5}));
+    json.put("string", "hello");
+
+    DynamicMessage protoMsg =
+        JsonToProtoMessage.convertJsonToProtoMessage(RepeatedInt64.getDescriptor(), json, true);
+    assertEquals(protoMsg, expectedProto);
+  }
+
+  @Test
+  public void testEmptySecondLevelObject() throws Exception {
+    ComplexLvl1 expectedProto =
+        ComplexLvl1.newBuilder()
+            .setTestInt(1)
+            .setComplexLvl2(ComplexLvl2.newBuilder().build())
+            .build();
+    JSONObject complexLvl2 = new JSONObject();
+    JSONObject json = new JSONObject();
+    json.put("test_int", 1);
+    json.put("complex_lvl2", complexLvl2);
+
+    DynamicMessage protoMsg =
+        JsonToProtoMessage.convertJsonToProtoMessage(ComplexLvl1.getDescriptor(), json, true);
+    assertEquals(protoMsg, expectedProto);
+  }
+
+  @Test
+  public void testAllowUnknownFieldsError() throws Exception {
+    JSONObject json = new JSONObject();
+    json.put("test_repeated", new JSONArray(new int[] {1, 2, 3, 4, 5}));
+    json.put("string", "hello");
+
+    try {
+      DynamicMessage protoMsg =
+          JsonToProtoMessage.convertJsonToProtoMessage(RepeatedInt64.getDescriptor(), json, false);
+    } catch (IllegalArgumentException e) {
+      assertEquals(
+          e.getMessage(),
+          "JSONObject has fields unknown to BigQuery: root.string. Set allowUnknownFields to True to allow unknown fields.");
+    }
+  }
+
+  @Test
+  public void testEmptyProtoMessage() throws Exception {
+    JSONObject json = new JSONObject();
+    json.put("test_repeated", new JSONArray(new int[0]));
+    json.put("string", "hello");
+
+    try {
+      DynamicMessage protoMsg =
+          JsonToProtoMessage.convertJsonToProtoMessage(RepeatedInt64.getDescriptor(), json, true);
+    } catch (IllegalArgumentException e) {
+      assertEquals(e.getMessage(), "The created protobuf message is empty.");
+    }
+  }
+
+  @Test
+  public void testEmptyJSONObject() throws Exception {
+    JSONObject json = new JSONObject();
+    try {
+      DynamicMessage protoMsg =
+          JsonToProtoMessage.convertJsonToProtoMessage(Int64Type.getDescriptor(), json, false);
+    } catch (IllegalStateException e) {
+      assertEquals(e.getMessage(), "JSONObject is empty.");
+    }
+  }
+
+  @Test
+  public void testNullJson() throws Exception {
+    try {
+      DynamicMessage protoMsg =
+          JsonToProtoMessage.convertJsonToProtoMessage(Int64Type.getDescriptor(), null, false);
+    } catch (NullPointerException e) {
+      assertEquals(e.getMessage(), "JSONObject is null.");
+    }
+  }
+
+  @Test
+  public void testNullDescriptor() throws Exception {
+    try {
+      DynamicMessage protoMsg =
+          JsonToProtoMessage.convertJsonToProtoMessage(null, new JSONObject(), false);
+    } catch (NullPointerException e) {
+      assertEquals(e.getMessage(), "Protobuf descriptor is null.");
+    }
+  }
+
+  @Test
+  public void testAllowUnknownFieldsSecondLevel() throws Exception {
+    JSONObject complex_lvl2 = new JSONObject();
+    complex_lvl2.put("no_match", 1);
+    JSONObject json = new JSONObject();
+    json.put("test_int", 1);
+    json.put("complex_lvl2", complex_lvl2);
+
+    try {
+      DynamicMessage protoMsg =
+          JsonToProtoMessage.convertJsonToProtoMessage(ComplexLvl1.getDescriptor(), json, false);
+    } catch (IllegalArgumentException e) {
+      assertEquals(
+          e.getMessage(),
+          "JSONObject has fields unknown to BigQuery: root.complex_lvl2.no_match. Set allowUnknownFields to True to allow unknown fields.");
+    }
+  }
+
+  @Test
+  public void testTopLevelMismatch() throws Exception {
+    JSONObject json = new JSONObject();
+    json.put("no_match", 1.1);
+
+    try {
+      DynamicMessage protoMsg =
+          JsonToProtoMessage.convertJsonToProtoMessage(
+              TopLevelMismatch.getDescriptor(), json, true);
+    } catch (IllegalArgumentException e) {
+      assertEquals(
+          e.getMessage(),
+          "There are no matching fields found for the JSONObject and the protocol buffer descriptor.");
+    }
+  }
+
+  @Test
+  public void testTopLevelMatchSecondLevelMismatch() throws Exception {
+    ComplexLvl1 expectedProto =
+        ComplexLvl1.newBuilder()
+            .setTestInt(1)
+            .setComplexLvl2(ComplexLvl2.newBuilder().build())
+            .build();
+    JSONObject complex_lvl2 = new JSONObject();
+    complex_lvl2.put("no_match", 1);
+    JSONObject json = new JSONObject();
+    json.put("test_int", 1);
+    json.put("complex_lvl2", complex_lvl2);
+
+    DynamicMessage protoMsg =
+        JsonToProtoMessage.convertJsonToProtoMessage(ComplexLvl1.getDescriptor(), json, true);
+    assertEquals(protoMsg, expectedProto);
+  }
+
+  @Test
+  public void testJsonNullValue() throws Exception {
+    JSONObject json = new JSONObject();
+    json.put("long", JSONObject.NULL);
+    json.put("int", 1);
+    try {
+      DynamicMessage protoMsg =
+          JsonToProtoMessage.convertJsonToProtoMessage(TestInt64.getDescriptor(), json, false);
+    } catch (IllegalArgumentException e) {
+      assertEquals(e.getMessage(), "JSONObject does not have a int64 field at root.long.");
+    }
+  }
+}
diff --git a/google-cloud-bigquerystorage/src/test/java/com/google/cloud/bigquery/storage/v1beta1/BaseBigQueryStorageClientTest.java b/google-cloud-bigquerystorage/src/test/java/com/google/cloud/bigquery/storage/v1beta1/BaseBigQueryStorageClientTest.java
index a9d5e092f3..7d3c752e11 100644
--- a/google-cloud-bigquerystorage/src/test/java/com/google/cloud/bigquery/storage/v1beta1/BaseBigQueryStorageClientTest.java
+++ b/google-cloud-bigquerystorage/src/test/java/com/google/cloud/bigquery/storage/v1beta1/BaseBigQueryStorageClientTest.java
@@ -94,12 +94,12 @@ public void tearDown() throws Exception {
   @Test
   @SuppressWarnings("all")
   public void createReadSessionTest() {
-    String name = "name3373707";
-    ReadSession expectedResponse = ReadSession.newBuilder().setName(name).build();
+    ReadSessionName name = ReadSessionName.of("[PROJECT]", "[LOCATION]", "[SESSION]");
+    ReadSession expectedResponse = ReadSession.newBuilder().setName(name.toString()).build();
     mockBigQueryStorage.addResponse(expectedResponse);
 
     TableReference tableReference = TableReference.newBuilder().build();
-    String parent = "parent-995424086";
+    ProjectName parent = ProjectName.of("[PROJECT]");
     int requestedStreams = 1017221410;
 
     ReadSession actualResponse = client.createReadSession(tableReference, parent, requestedStreams);
@@ -110,7 +110,7 @@ public void createReadSessionTest() {
     CreateReadSessionRequest actualRequest = (CreateReadSessionRequest) actualRequests.get(0);
 
     Assert.assertEquals(tableReference, actualRequest.getTableReference());
-    Assert.assertEquals(parent, actualRequest.getParent());
+    Assert.assertEquals(parent, ProjectName.parse(actualRequest.getParent()));
     Assert.assertEquals(requestedStreams, actualRequest.getRequestedStreams());
     Assert.assertTrue(
         channelProvider.isHeaderSent(
@@ -126,7 +126,7 @@ public void createReadSessionExceptionTest() throws Exception {
 
     try {
       TableReference tableReference = TableReference.newBuilder().build();
-      String parent = "parent-995424086";
+      ProjectName parent = ProjectName.of("[PROJECT]");
       int requestedStreams = 1017221410;
 
       client.createReadSession(tableReference, parent, requestedStreams);
diff --git a/google-cloud-bigquerystorage/src/test/proto/jsonTest.proto b/google-cloud-bigquerystorage/src/test/proto/jsonTest.proto
index 26a3499c23..8e3d1d9675 100644
--- a/google-cloud-bigquerystorage/src/test/proto/jsonTest.proto
+++ b/google-cloud-bigquerystorage/src/test/proto/jsonTest.proto
@@ -32,6 +32,14 @@ message ComplexLvl2 {
   optional int64 test_int = 1;
 }
 
+message ObjectType {
+  optional ComplexLvl2 test_field_type = 1;
+}
+
+message RepeatedType {
+  repeated int64 test_field_type = 1;
+}
+
 message OptionTest {
   optional int64 test_optional = 1;
   required int64 test_required = 2;
@@ -52,3 +60,69 @@ message ReuseLvl1 {
 message ReuseLvl2 {
   optional int64 test_int = 1;
 }
+
+message RepeatedInt64 {
+  repeated int64 test_repeated = 1;
+}
+
+message RepeatedInt32 {
+  repeated int32 test_repeated = 1;
+}
+
+message RepeatedDouble {
+  repeated double test_repeated = 1;
+}
+
+message RepeatedString {
+  repeated string test_repeated = 1;
+}
+
+message RepeatedBool {
+  repeated bool test_repeated = 1;
+}
+
+message RepeatedBytes {
+  repeated bytes test_repeated = 1;
+}
+
+message RepeatedObject {
+  repeated ComplexLvl2 test_repeated = 1;
+}
+
+message TestInt64 {
+  optional int64 byte = 1;
+  optional int64 short = 2;
+  optional int64 int = 3;
+  optional int64 long = 4;
+}
+
+message TestInt32 {
+  optional int32 byte = 1;
+  optional int32 short = 2;
+  optional int32 int = 3;
+}
+
+message TestDouble {
+  optional double double = 1;
+  optional double float = 2;
+}
+
+message NestedRepeated {
+  repeated int64 int = 1;
+  repeated double double = 2;
+  optional RepeatedString repeated_string = 3;
+}
+
+message TestRequired {
+  optional double optional_double = 1;
+  required double required_double = 2;
+}
+
+message TestRepeatedIsOptional {
+  optional double required_double = 1;
+  repeated double repeated_double = 2;
+}
+
+message TopLevelMismatch {
+  optional double mismatch_double = 1;
+}
diff --git a/grpc-google-cloud-bigquerystorage-v1/pom.xml b/grpc-google-cloud-bigquerystorage-v1/pom.xml
index d9f70d1365..e256b7496f 100644
--- a/grpc-google-cloud-bigquerystorage-v1/pom.xml
+++ b/grpc-google-cloud-bigquerystorage-v1/pom.xml
@@ -4,13 +4,13 @@
   4.0.0
   com.google.api.grpc
   grpc-google-cloud-bigquerystorage-v1
-  1.2.1
+  1.3.0
   grpc-google-cloud-bigquerystorage-v1
   GRPC library for grpc-google-cloud-bigquerystorage-v1
   
     com.google.cloud
     google-cloud-bigquerystorage-parent
-    1.2.1
+    1.3.0
   
   
     
diff --git a/grpc-google-cloud-bigquerystorage-v1alpha2/pom.xml b/grpc-google-cloud-bigquerystorage-v1alpha2/pom.xml
index 56f431688c..069733dfe9 100644
--- a/grpc-google-cloud-bigquerystorage-v1alpha2/pom.xml
+++ b/grpc-google-cloud-bigquerystorage-v1alpha2/pom.xml
@@ -4,13 +4,13 @@
   4.0.0
   com.google.api.grpc
   grpc-google-cloud-bigquerystorage-v1alpha2
-  0.102.1
+  0.103.0
   grpc-google-cloud-bigquerystorage-v1alpha2
   GRPC library for grpc-google-cloud-bigquerystorage-v1alpha2
   
     com.google.cloud
     google-cloud-bigquerystorage-parent
-    1.2.1
+    1.3.0
   
   
     
diff --git a/grpc-google-cloud-bigquerystorage-v1beta1/pom.xml b/grpc-google-cloud-bigquerystorage-v1beta1/pom.xml
index 02078ac063..53cc705a34 100644
--- a/grpc-google-cloud-bigquerystorage-v1beta1/pom.xml
+++ b/grpc-google-cloud-bigquerystorage-v1beta1/pom.xml
@@ -4,13 +4,13 @@
   4.0.0
   com.google.api.grpc
   grpc-google-cloud-bigquerystorage-v1beta1
-  0.102.1
+  0.103.0
   grpc-google-cloud-bigquerystorage-v1beta1
   GRPC library for grpc-google-cloud-bigquerystorage-v1beta1
   
     com.google.cloud
     google-cloud-bigquerystorage-parent
-    1.2.1
+    1.3.0
   
   
     
diff --git a/grpc-google-cloud-bigquerystorage-v1beta2/pom.xml b/grpc-google-cloud-bigquerystorage-v1beta2/pom.xml
index 5502f175b1..e32b64dd8f 100644
--- a/grpc-google-cloud-bigquerystorage-v1beta2/pom.xml
+++ b/grpc-google-cloud-bigquerystorage-v1beta2/pom.xml
@@ -4,13 +4,13 @@
   4.0.0
   com.google.api.grpc
   grpc-google-cloud-bigquerystorage-v1beta2
-  0.102.1
+  0.103.0
   grpc-google-cloud-bigquerystorage-v1beta2
   GRPC library for grpc-google-cloud-bigquerystorage-v1beta2
   
     com.google.cloud
     google-cloud-bigquerystorage-parent
-    1.2.1
+    1.3.0
   
   
     
diff --git a/pom.xml b/pom.xml
index 7601a899c2..1e5386ce0a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
   com.google.cloud
   google-cloud-bigquerystorage-parent
   pom
-  1.2.1
+  1.3.0
   BigQuery Storage Parent
   https://github.com/googleapis/java-bigquerystorage
   
@@ -103,47 +103,47 @@
       
         com.google.api.grpc
         proto-google-cloud-bigquerystorage-v1alpha2
-        0.102.1
+        0.103.0
       
       
         com.google.api.grpc
         proto-google-cloud-bigquerystorage-v1beta1
-        0.102.1
+        0.103.0
       
       
         com.google.api.grpc
         proto-google-cloud-bigquerystorage-v1beta2
-        0.102.1
+        0.103.0
       
       
         com.google.api.grpc
         proto-google-cloud-bigquerystorage-v1
-        1.2.1
+        1.3.0
       
       
         com.google.api.grpc
         grpc-google-cloud-bigquerystorage-v1alpha2
-        0.102.1
+        0.103.0
       
       
         com.google.api.grpc
         grpc-google-cloud-bigquerystorage-v1beta1
-        0.102.1
+        0.103.0
       
       
         com.google.api.grpc
         grpc-google-cloud-bigquerystorage-v1beta2
-        0.102.1
+        0.103.0
       
       
         com.google.api.grpc
         grpc-google-cloud-bigquerystorage-v1
-        1.2.1
+        1.3.0
       
       
         com.google.cloud
         google-cloud-bigquerystorage
-        1.2.1
+        1.3.0
       
       
         com.fasterxml.jackson.core
@@ -155,6 +155,12 @@
         commons-lang3
         ${commons-lang3.version}
       
+      
+        org.json
+        json
+        20200518
+      
+
 
       
       
diff --git a/proto-google-cloud-bigquerystorage-v1/pom.xml b/proto-google-cloud-bigquerystorage-v1/pom.xml
index e1cd2249ec..7490ff4603 100644
--- a/proto-google-cloud-bigquerystorage-v1/pom.xml
+++ b/proto-google-cloud-bigquerystorage-v1/pom.xml
@@ -4,13 +4,13 @@
   4.0.0
   com.google.api.grpc
   proto-google-cloud-bigquerystorage-v1
-  1.2.1
+  1.3.0
   proto-google-cloud-bigquerystorage-v1
   PROTO library for proto-google-cloud-bigquerystorage-v1
   
     com.google.cloud
     google-cloud-bigquerystorage-parent
-    1.2.1
+    1.3.0
   
   
     
diff --git a/proto-google-cloud-bigquerystorage-v1alpha2/pom.xml b/proto-google-cloud-bigquerystorage-v1alpha2/pom.xml
index d08a25150e..d3db4c2005 100644
--- a/proto-google-cloud-bigquerystorage-v1alpha2/pom.xml
+++ b/proto-google-cloud-bigquerystorage-v1alpha2/pom.xml
@@ -4,13 +4,13 @@
   4.0.0
   com.google.api.grpc
   proto-google-cloud-bigquerystorage-v1alpha2
-  0.102.1
+  0.103.0
   proto-google-cloud-bigquerystorage-v1alpha2
   PROTO library for proto-google-cloud-bigquerystorage-v1alpha2
   
     com.google.cloud
     google-cloud-bigquerystorage-parent
-    1.2.1
+    1.3.0
   
   
     
diff --git a/proto-google-cloud-bigquerystorage-v1beta1/pom.xml b/proto-google-cloud-bigquerystorage-v1beta1/pom.xml
index 519be65aa4..b9c5e12f05 100644
--- a/proto-google-cloud-bigquerystorage-v1beta1/pom.xml
+++ b/proto-google-cloud-bigquerystorage-v1beta1/pom.xml
@@ -4,13 +4,13 @@
   4.0.0
   com.google.api.grpc
   proto-google-cloud-bigquerystorage-v1beta1
-  0.102.1
+  0.103.0
   proto-google-cloud-bigquerystorage-v1beta1
   PROTO library for proto-google-cloud-bigquerystorage-v1beta1
   
     com.google.cloud
     google-cloud-bigquerystorage-parent
-    1.2.1
+    1.3.0
   
   
     
@@ -21,6 +21,14 @@
       com.google.api.grpc
       proto-google-common-protos
     
+    
+      com.google.api
+      api-common
+    
+    
+      com.google.guava
+      guava
+    
   
 
   
@@ -31,4 +39,4 @@
       
     
   
-
\ No newline at end of file
+
diff --git a/proto-google-cloud-bigquerystorage-v1beta1/src/main/java/com/google/cloud/bigquery/storage/v1beta1/ProjectName.java b/proto-google-cloud-bigquerystorage-v1beta1/src/main/java/com/google/cloud/bigquery/storage/v1beta1/ProjectName.java
new file mode 100644
index 0000000000..3ffe5f3360
--- /dev/null
+++ b/proto-google-cloud-bigquerystorage-v1beta1/src/main/java/com/google/cloud/bigquery/storage/v1beta1/ProjectName.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2020 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
+ *
+ *     https://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.storage.v1beta1;
+
+import com.google.api.pathtemplate.PathTemplate;
+import com.google.api.resourcenames.ResourceName;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/** AUTO-GENERATED DOCUMENTATION AND CLASS */
+@javax.annotation.Generated("by GAPIC protoc plugin")
+public class ProjectName implements ResourceName {
+
+  private static final PathTemplate PATH_TEMPLATE =
+      PathTemplate.createWithoutUrlEncoding("projects/{project}");
+
+  private volatile Map fieldValuesMap;
+
+  private final String project;
+
+  public String getProject() {
+    return project;
+  }
+
+  public static Builder newBuilder() {
+    return new Builder();
+  }
+
+  public Builder toBuilder() {
+    return new Builder(this);
+  }
+
+  private ProjectName(Builder builder) {
+    project = Preconditions.checkNotNull(builder.getProject());
+  }
+
+  public static ProjectName of(String project) {
+    return newBuilder().setProject(project).build();
+  }
+
+  public static String format(String project) {
+    return newBuilder().setProject(project).build().toString();
+  }
+
+  public static ProjectName parse(String formattedString) {
+    if (formattedString.isEmpty()) {
+      return null;
+    }
+    Map matchMap =
+        PATH_TEMPLATE.validatedMatch(
+            formattedString, "ProjectName.parse: formattedString not in valid format");
+    return of(matchMap.get("project"));
+  }
+
+  public static List parseList(List formattedStrings) {
+    List list = new ArrayList<>(formattedStrings.size());
+    for (String formattedString : formattedStrings) {
+      list.add(parse(formattedString));
+    }
+    return list;
+  }
+
+  public static List toStringList(List values) {
+    List list = new ArrayList(values.size());
+    for (ProjectName value : values) {
+      if (value == null) {
+        list.add("");
+      } else {
+        list.add(value.toString());
+      }
+    }
+    return list;
+  }
+
+  public static boolean isParsableFrom(String formattedString) {
+    return PATH_TEMPLATE.matches(formattedString);
+  }
+
+  public Map getFieldValuesMap() {
+    if (fieldValuesMap == null) {
+      synchronized (this) {
+        if (fieldValuesMap == null) {
+          ImmutableMap.Builder fieldMapBuilder = ImmutableMap.builder();
+          fieldMapBuilder.put("project", project);
+          fieldValuesMap = fieldMapBuilder.build();
+        }
+      }
+    }
+    return fieldValuesMap;
+  }
+
+  public String getFieldValue(String fieldName) {
+    return getFieldValuesMap().get(fieldName);
+  }
+
+  @Override
+  public String toString() {
+    return PATH_TEMPLATE.instantiate("project", project);
+  }
+
+  /** Builder for ProjectName. */
+  public static class Builder {
+
+    private String project;
+
+    public String getProject() {
+      return project;
+    }
+
+    public Builder setProject(String project) {
+      this.project = project;
+      return this;
+    }
+
+    private Builder() {}
+
+    private Builder(ProjectName projectName) {
+      project = projectName.project;
+    }
+
+    public ProjectName build() {
+      return new ProjectName(this);
+    }
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (o == this) {
+      return true;
+    }
+    if (o instanceof ProjectName) {
+      ProjectName that = (ProjectName) o;
+      return (this.project.equals(that.project));
+    }
+    return false;
+  }
+
+  @Override
+  public int hashCode() {
+    int h = 1;
+    h *= 1000003;
+    h ^= project.hashCode();
+    return h;
+  }
+}
diff --git a/proto-google-cloud-bigquerystorage-v1beta1/src/main/java/com/google/cloud/bigquery/storage/v1beta1/ReadSessionName.java b/proto-google-cloud-bigquerystorage-v1beta1/src/main/java/com/google/cloud/bigquery/storage/v1beta1/ReadSessionName.java
new file mode 100644
index 0000000000..c0762f78e5
--- /dev/null
+++ b/proto-google-cloud-bigquerystorage-v1beta1/src/main/java/com/google/cloud/bigquery/storage/v1beta1/ReadSessionName.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2020 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
+ *
+ *     https://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.storage.v1beta1;
+
+import com.google.api.pathtemplate.PathTemplate;
+import com.google.api.resourcenames.ResourceName;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/** AUTO-GENERATED DOCUMENTATION AND CLASS */
+@javax.annotation.Generated("by GAPIC protoc plugin")
+public class ReadSessionName implements ResourceName {
+
+  private static final PathTemplate PATH_TEMPLATE =
+      PathTemplate.createWithoutUrlEncoding(
+          "projects/{project}/locations/{location}/sessions/{session}");
+
+  private volatile Map fieldValuesMap;
+
+  private final String project;
+  private final String location;
+  private final String session;
+
+  public String getProject() {
+    return project;
+  }
+
+  public String getLocation() {
+    return location;
+  }
+
+  public String getSession() {
+    return session;
+  }
+
+  public static Builder newBuilder() {
+    return new Builder();
+  }
+
+  public Builder toBuilder() {
+    return new Builder(this);
+  }
+
+  private ReadSessionName(Builder builder) {
+    project = Preconditions.checkNotNull(builder.getProject());
+    location = Preconditions.checkNotNull(builder.getLocation());
+    session = Preconditions.checkNotNull(builder.getSession());
+  }
+
+  public static ReadSessionName of(String project, String location, String session) {
+    return newBuilder().setProject(project).setLocation(location).setSession(session).build();
+  }
+
+  public static String format(String project, String location, String session) {
+    return newBuilder()
+        .setProject(project)
+        .setLocation(location)
+        .setSession(session)
+        .build()
+        .toString();
+  }
+
+  public static ReadSessionName parse(String formattedString) {
+    if (formattedString.isEmpty()) {
+      return null;
+    }
+    Map matchMap =
+        PATH_TEMPLATE.validatedMatch(
+            formattedString, "ReadSessionName.parse: formattedString not in valid format");
+    return of(matchMap.get("project"), matchMap.get("location"), matchMap.get("session"));
+  }
+
+  public static List parseList(List formattedStrings) {
+    List list = new ArrayList<>(formattedStrings.size());
+    for (String formattedString : formattedStrings) {
+      list.add(parse(formattedString));
+    }
+    return list;
+  }
+
+  public static List toStringList(List values) {
+    List list = new ArrayList(values.size());
+    for (ReadSessionName value : values) {
+      if (value == null) {
+        list.add("");
+      } else {
+        list.add(value.toString());
+      }
+    }
+    return list;
+  }
+
+  public static boolean isParsableFrom(String formattedString) {
+    return PATH_TEMPLATE.matches(formattedString);
+  }
+
+  public Map getFieldValuesMap() {
+    if (fieldValuesMap == null) {
+      synchronized (this) {
+        if (fieldValuesMap == null) {
+          ImmutableMap.Builder fieldMapBuilder = ImmutableMap.builder();
+          fieldMapBuilder.put("project", project);
+          fieldMapBuilder.put("location", location);
+          fieldMapBuilder.put("session", session);
+          fieldValuesMap = fieldMapBuilder.build();
+        }
+      }
+    }
+    return fieldValuesMap;
+  }
+
+  public String getFieldValue(String fieldName) {
+    return getFieldValuesMap().get(fieldName);
+  }
+
+  @Override
+  public String toString() {
+    return PATH_TEMPLATE.instantiate("project", project, "location", location, "session", session);
+  }
+
+  /** Builder for ReadSessionName. */
+  public static class Builder {
+
+    private String project;
+    private String location;
+    private String session;
+
+    public String getProject() {
+      return project;
+    }
+
+    public String getLocation() {
+      return location;
+    }
+
+    public String getSession() {
+      return session;
+    }
+
+    public Builder setProject(String project) {
+      this.project = project;
+      return this;
+    }
+
+    public Builder setLocation(String location) {
+      this.location = location;
+      return this;
+    }
+
+    public Builder setSession(String session) {
+      this.session = session;
+      return this;
+    }
+
+    private Builder() {}
+
+    private Builder(ReadSessionName readSessionName) {
+      project = readSessionName.project;
+      location = readSessionName.location;
+      session = readSessionName.session;
+    }
+
+    public ReadSessionName build() {
+      return new ReadSessionName(this);
+    }
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (o == this) {
+      return true;
+    }
+    if (o instanceof ReadSessionName) {
+      ReadSessionName that = (ReadSessionName) o;
+      return (this.project.equals(that.project))
+          && (this.location.equals(that.location))
+          && (this.session.equals(that.session));
+    }
+    return false;
+  }
+
+  @Override
+  public int hashCode() {
+    int h = 1;
+    h *= 1000003;
+    h ^= project.hashCode();
+    h *= 1000003;
+    h ^= location.hashCode();
+    h *= 1000003;
+    h ^= session.hashCode();
+    return h;
+  }
+}
diff --git a/proto-google-cloud-bigquerystorage-v1beta1/src/main/java/com/google/cloud/bigquery/storage/v1beta1/StreamName.java b/proto-google-cloud-bigquerystorage-v1beta1/src/main/java/com/google/cloud/bigquery/storage/v1beta1/StreamName.java
new file mode 100644
index 0000000000..a486d4fc85
--- /dev/null
+++ b/proto-google-cloud-bigquerystorage-v1beta1/src/main/java/com/google/cloud/bigquery/storage/v1beta1/StreamName.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2020 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
+ *
+ *     https://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.storage.v1beta1;
+
+import com.google.api.pathtemplate.PathTemplate;
+import com.google.api.resourcenames.ResourceName;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/** AUTO-GENERATED DOCUMENTATION AND CLASS */
+@javax.annotation.Generated("by GAPIC protoc plugin")
+public class StreamName implements ResourceName {
+
+  private static final PathTemplate PATH_TEMPLATE =
+      PathTemplate.createWithoutUrlEncoding(
+          "projects/{project}/locations/{location}/streams/{stream}");
+
+  private volatile Map fieldValuesMap;
+
+  private final String project;
+  private final String location;
+  private final String stream;
+
+  public String getProject() {
+    return project;
+  }
+
+  public String getLocation() {
+    return location;
+  }
+
+  public String getStream() {
+    return stream;
+  }
+
+  public static Builder newBuilder() {
+    return new Builder();
+  }
+
+  public Builder toBuilder() {
+    return new Builder(this);
+  }
+
+  private StreamName(Builder builder) {
+    project = Preconditions.checkNotNull(builder.getProject());
+    location = Preconditions.checkNotNull(builder.getLocation());
+    stream = Preconditions.checkNotNull(builder.getStream());
+  }
+
+  public static StreamName of(String project, String location, String stream) {
+    return newBuilder().setProject(project).setLocation(location).setStream(stream).build();
+  }
+
+  public static String format(String project, String location, String stream) {
+    return newBuilder()
+        .setProject(project)
+        .setLocation(location)
+        .setStream(stream)
+        .build()
+        .toString();
+  }
+
+  public static StreamName parse(String formattedString) {
+    if (formattedString.isEmpty()) {
+      return null;
+    }
+    Map matchMap =
+        PATH_TEMPLATE.validatedMatch(
+            formattedString, "StreamName.parse: formattedString not in valid format");
+    return of(matchMap.get("project"), matchMap.get("location"), matchMap.get("stream"));
+  }
+
+  public static List parseList(List formattedStrings) {
+    List list = new ArrayList<>(formattedStrings.size());
+    for (String formattedString : formattedStrings) {
+      list.add(parse(formattedString));
+    }
+    return list;
+  }
+
+  public static List toStringList(List values) {
+    List list = new ArrayList(values.size());
+    for (StreamName value : values) {
+      if (value == null) {
+        list.add("");
+      } else {
+        list.add(value.toString());
+      }
+    }
+    return list;
+  }
+
+  public static boolean isParsableFrom(String formattedString) {
+    return PATH_TEMPLATE.matches(formattedString);
+  }
+
+  public Map getFieldValuesMap() {
+    if (fieldValuesMap == null) {
+      synchronized (this) {
+        if (fieldValuesMap == null) {
+          ImmutableMap.Builder fieldMapBuilder = ImmutableMap.builder();
+          fieldMapBuilder.put("project", project);
+          fieldMapBuilder.put("location", location);
+          fieldMapBuilder.put("stream", stream);
+          fieldValuesMap = fieldMapBuilder.build();
+        }
+      }
+    }
+    return fieldValuesMap;
+  }
+
+  public String getFieldValue(String fieldName) {
+    return getFieldValuesMap().get(fieldName);
+  }
+
+  @Override
+  public String toString() {
+    return PATH_TEMPLATE.instantiate("project", project, "location", location, "stream", stream);
+  }
+
+  /** Builder for StreamName. */
+  public static class Builder {
+
+    private String project;
+    private String location;
+    private String stream;
+
+    public String getProject() {
+      return project;
+    }
+
+    public String getLocation() {
+      return location;
+    }
+
+    public String getStream() {
+      return stream;
+    }
+
+    public Builder setProject(String project) {
+      this.project = project;
+      return this;
+    }
+
+    public Builder setLocation(String location) {
+      this.location = location;
+      return this;
+    }
+
+    public Builder setStream(String stream) {
+      this.stream = stream;
+      return this;
+    }
+
+    private Builder() {}
+
+    private Builder(StreamName streamName) {
+      project = streamName.project;
+      location = streamName.location;
+      stream = streamName.stream;
+    }
+
+    public StreamName build() {
+      return new StreamName(this);
+    }
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (o == this) {
+      return true;
+    }
+    if (o instanceof StreamName) {
+      StreamName that = (StreamName) o;
+      return (this.project.equals(that.project))
+          && (this.location.equals(that.location))
+          && (this.stream.equals(that.stream));
+    }
+    return false;
+  }
+
+  @Override
+  public int hashCode() {
+    int h = 1;
+    h *= 1000003;
+    h ^= project.hashCode();
+    h *= 1000003;
+    h ^= location.hashCode();
+    h *= 1000003;
+    h ^= stream.hashCode();
+    return h;
+  }
+}
diff --git a/proto-google-cloud-bigquerystorage-v1beta2/pom.xml b/proto-google-cloud-bigquerystorage-v1beta2/pom.xml
index b10e45c294..643b926286 100644
--- a/proto-google-cloud-bigquerystorage-v1beta2/pom.xml
+++ b/proto-google-cloud-bigquerystorage-v1beta2/pom.xml
@@ -4,13 +4,13 @@
   4.0.0
   com.google.api.grpc
   proto-google-cloud-bigquerystorage-v1beta2
-  0.102.1
+  0.103.0
   proto-google-cloud-bigquerystorage-v1beta2
   PROTO library for proto-google-cloud-bigquerystorage-v1beta2
   
     com.google.cloud
     google-cloud-bigquerystorage-parent
-    1.2.1
+    1.3.0
   
   
     
diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml
index ec8b1f9830..c2248fe512 100644
--- a/samples/install-without-bom/pom.xml
+++ b/samples/install-without-bom/pom.xml
@@ -29,7 +29,7 @@
     
       com.google.cloud
       google-cloud-bigquerystorage
-      1.2.0
+      1.2.1
     
     
 
diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml
index 9780c997e5..c594dd0bf7 100644
--- a/samples/snapshot/pom.xml
+++ b/samples/snapshot/pom.xml
@@ -28,7 +28,7 @@
     
       com.google.cloud
       google-cloud-bigquerystorage
-      1.2.1
+      1.3.0
     
     
 
diff --git a/synth.metadata b/synth.metadata
index 51b94eaf01..a792aab51d 100644
--- a/synth.metadata
+++ b/synth.metadata
@@ -11,39 +11,39 @@
       "git": {
         "name": ".",
         "remote": "https://github.com/googleapis/java-bigquerystorage.git",
-        "sha": "1584bdbf5820a378d844d333e8546b6a26b3c643"
+        "sha": "90bb713795676c6a2434476fde2d4a941b40cbd9"
       }
     },
     {
       "git": {
         "name": "googleapis",
         "remote": "https://github.com/googleapis/googleapis.git",
-        "sha": "da557a85c1c060a6dbffeea1e0867d2586091cf4",
-        "internalRef": "321249584"
+        "sha": "d7a347b819096886f4644b0ed5a978a777f4bbb4",
+        "internalRef": "322235422"
       }
     },
     {
       "git": {
         "name": "googleapis",
         "remote": "https://github.com/googleapis/googleapis.git",
-        "sha": "da557a85c1c060a6dbffeea1e0867d2586091cf4",
-        "internalRef": "321249584"
+        "sha": "d7a347b819096886f4644b0ed5a978a777f4bbb4",
+        "internalRef": "322235422"
       }
     },
     {
       "git": {
         "name": "googleapis",
         "remote": "https://github.com/googleapis/googleapis.git",
-        "sha": "da557a85c1c060a6dbffeea1e0867d2586091cf4",
-        "internalRef": "321249584"
+        "sha": "d7a347b819096886f4644b0ed5a978a777f4bbb4",
+        "internalRef": "322235422"
       }
     },
     {
       "git": {
         "name": "googleapis",
         "remote": "https://github.com/googleapis/googleapis.git",
-        "sha": "da557a85c1c060a6dbffeea1e0867d2586091cf4",
-        "internalRef": "321249584"
+        "sha": "d7a347b819096886f4644b0ed5a978a777f4bbb4",
+        "internalRef": "322235422"
       }
     },
     {
diff --git a/versions.txt b/versions.txt
index 1569a7ca4d..ef1902211f 100644
--- a/versions.txt
+++ b/versions.txt
@@ -1,12 +1,12 @@
 # Format:
 # module:released-version:current-version
 
-proto-google-cloud-bigquerystorage-v1alpha2:0.102.1:0.102.1
-proto-google-cloud-bigquerystorage-v1beta1:0.102.1:0.102.1
-proto-google-cloud-bigquerystorage-v1beta2:0.102.1:0.102.1
-proto-google-cloud-bigquerystorage-v1:1.2.1:1.2.1
-grpc-google-cloud-bigquerystorage-v1alpha2:0.102.1:0.102.1
-grpc-google-cloud-bigquerystorage-v1beta1:0.102.1:0.102.1
-grpc-google-cloud-bigquerystorage-v1beta2:0.102.1:0.102.1
-grpc-google-cloud-bigquerystorage-v1:1.2.1:1.2.1
-google-cloud-bigquerystorage:1.2.1:1.2.1
+proto-google-cloud-bigquerystorage-v1alpha2:0.103.0:0.103.0
+proto-google-cloud-bigquerystorage-v1beta1:0.103.0:0.103.0
+proto-google-cloud-bigquerystorage-v1beta2:0.103.0:0.103.0
+proto-google-cloud-bigquerystorage-v1:1.3.0:1.3.0
+grpc-google-cloud-bigquerystorage-v1alpha2:0.103.0:0.103.0
+grpc-google-cloud-bigquerystorage-v1beta1:0.103.0:0.103.0
+grpc-google-cloud-bigquerystorage-v1beta2:0.103.0:0.103.0
+grpc-google-cloud-bigquerystorage-v1:1.3.0:1.3.0
+google-cloud-bigquerystorage:1.3.0:1.3.0