diff --git a/google-cloud-bigquerystorage/pom.xml b/google-cloud-bigquerystorage/pom.xml index 7d330ef067..74185b9c98 100644 --- a/google-cloud-bigquerystorage/pom.xml +++ b/google-cloud-bigquerystorage/pom.xml @@ -108,6 +108,12 @@ org.apache.commons commons-lang3 + + org.json + json + 20200518 + + 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..2257ad667e --- /dev/null +++ b/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/JsonToProtoMessage.java @@ -0,0 +1,346 @@ +/* + * 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.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.DynamicMessage; +import com.google.protobuf.Message; +import java.util.List; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +/** Converts Json data to protocol buffer messages given the protocol buffer descriptor. */ +public class JsonToProtoMessage { + + /** + * Converts Json data to protocol buffer messages given the protocol buffer descriptor. + * + * @param protoSchema + * @param json + * @throws IllegalArgumentException when JSON data is not compatible with proto descriptor. + */ + public static DynamicMessage convertJsonToProtoMessage(Descriptor protoSchema, JSONObject json) + throws IllegalArgumentException { + return convertJsonToProtoMessage(protoSchema, json, false); + } + + /** + * 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 { + return convertJsonToProtoMessageImpl(protoSchema, json, "root", true, allowUnknownFields); + } + + /** + * Converts Json data to protocol buffer messages given the protocol buffer descriptor. + * + * @param protoSchema + * @param json + * @param jsonScope Debugging purposes + * @param topLevel If root level has no matching fields, throws exception. + * @param allowUnknownFields Ignores unknown JSON 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); + int matchedFields = 0; + List protoFields = protoSchema.getFields(); + + if (JSONObject.getNames(json).length > protoFields.size()) { + if (!allowUnknownFields) { + throw new IllegalArgumentException( + "JSONObject has unknown fields. Set allowUnknownFields to True to ignore unknown fields."); + } + } + + for (FieldDescriptor field : protoFields) { + String fieldName = field.getName(); + String currentScope = jsonScope + "." + fieldName; + + if (!json.has(fieldName)) { + if (field.isRequired()) { + throw new IllegalArgumentException( + "JSONObject does not have the required field " + currentScope + "."); + } else { + continue; + } + } + matchedFields++; + if (!field.isRepeated()) { + fillField(protoMsg, field, json, currentScope, allowUnknownFields); + } else { + fillRepeatedField(protoMsg, field, json, currentScope, allowUnknownFields); + } + } + if (matchedFields == 0 && topLevel) { + throw new IllegalArgumentException( + "There are no matching fields found for the JSONObject and the protocol buffer descriptor."); + } + return protoMsg.build(); + } + + /** + * Fills a non-repetaed protoField with the json data. + * + * @param protoMsg + * @param field + * @param json + * @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 field, + JSONObject json, + String currentScope, + boolean allowUnknownFields) + throws IllegalArgumentException { + + String fieldName = field.getName(); + switch (field.getType()) { + case BOOL: + try { + protoMsg.setField(field, new Boolean(json.getBoolean(fieldName))); + } catch (JSONException e) { + throw new IllegalArgumentException( + "JSONObject does not have a boolean field at " + currentScope + "."); + } + break; + case BYTES: + try { + protoMsg.setField(field, json.getString(fieldName).getBytes()); + } catch (JSONException e) { + throw new IllegalArgumentException( + "JSONObject does not have a string field at " + currentScope + "."); + } + break; + case INT64: + try { + java.lang.Object val = json.get(fieldName); + if (val instanceof Byte) { + protoMsg.setField(field, new Long((Byte) val)); + } else if (val instanceof Short) { + protoMsg.setField(field, new Long((Short) val)); + } else if (val instanceof Integer) { + protoMsg.setField(field, new Long((Integer) val)); + } else if (val instanceof Long) { + protoMsg.setField(field, new Long((Long) val)); + } else { + throw new IllegalArgumentException( + "JSONObject does not have a int64 field at " + currentScope + "."); + } + } catch (JSONException e) { + throw new IllegalArgumentException( + "JSONObject does not have a int64 field at " + currentScope + "."); + } + break; + case STRING: + try { + protoMsg.setField(field, json.getString(fieldName)); + } catch (JSONException e) { + throw new IllegalArgumentException( + "JSONObject does not have a string field at " + currentScope + "."); + } + break; + case DOUBLE: + try { + java.lang.Object val = json.get(fieldName); + if (val instanceof Double) { + protoMsg.setField(field, new Double((double) val)); + } else if (val instanceof Float) { + protoMsg.setField(field, new Double((float) val)); + } else { + throw new IllegalArgumentException( + "JSONObject does not have a double field at " + currentScope + "."); + } + } catch (JSONException e) { + throw new IllegalArgumentException( + "JSONObject does not have a double field at " + currentScope + "."); + } + break; + case MESSAGE: + Message.Builder message = protoMsg.newBuilderForField(field); + try { + protoMsg.setField( + field, + convertJsonToProtoMessageImpl( + field.getMessageType(), + json.getJSONObject(fieldName), + currentScope, + false, + allowUnknownFields)); + } catch (JSONException e) { + throw new IllegalArgumentException( + "JSONObject does not have an object field at " + currentScope + "."); + } + break; + } + } + + /** + * Fills a repeated protoField with the json data. + * + * @param protoMsg + * @param field + * @param json If root level has no matching fields, throws exception. + * @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 field, + JSONObject json, + String currentScope, + boolean allowUnknownFields) + throws IllegalArgumentException { + String fieldName = field.getName(); + JSONArray jsonArray; + try { + jsonArray = json.getJSONArray(fieldName); + } catch (JSONException e) { + throw new IllegalArgumentException( + "JSONObject does not have an array field at " + currentScope + "."); + } + + switch (field.getType()) { + case BOOL: + for (int i = 0; i < jsonArray.length(); i++) { + try { + protoMsg.addRepeatedField(field, new Boolean(jsonArray.getBoolean(i))); + } catch (JSONException e) { + throw new IllegalArgumentException( + "JSONObject does not have a boolean field at " + + currentScope + + "[" + + i + + "]" + + "."); + } + } + break; + case BYTES: + for (int i = 0; i < jsonArray.length(); i++) { + try { + protoMsg.addRepeatedField(field, jsonArray.getString(i).getBytes()); + } catch (JSONException e) { + throw new IllegalArgumentException( + "JSONObject does not have a string field at " + currentScope + "[" + i + "]" + "."); + } + } + break; + case INT64: + for (int i = 0; i < jsonArray.length(); i++) { + try { + java.lang.Object val = jsonArray.get(i); + if (val instanceof Byte) { + protoMsg.addRepeatedField(field, new Long((Byte) val)); + } else if (val instanceof Short) { + protoMsg.addRepeatedField(field, new Long((Short) val)); + } else if (val instanceof Integer) { + protoMsg.addRepeatedField(field, new Long((Integer) val)); + } else if (val instanceof Long) { + protoMsg.addRepeatedField(field, new Long((Long) val)); + } else { + throw new IllegalArgumentException( + "JSONObject does not have a int64 field at " + + currentScope + + "[" + + i + + "]" + + "."); + } + } catch (JSONException e) { + throw new IllegalArgumentException( + "JSONObject does not have a int64 field at " + currentScope + "[" + i + "]" + "."); + } + } + break; + case STRING: + for (int i = 0; i < jsonArray.length(); i++) { + try { + protoMsg.addRepeatedField(field, jsonArray.getString(i)); + } catch (JSONException e) { + throw new IllegalArgumentException( + "JSONObject does not have a string field at " + currentScope + "[" + i + "]" + "."); + } + } + break; + case DOUBLE: + for (int i = 0; i < jsonArray.length(); i++) { + try { + java.lang.Object val = jsonArray.get(i); + if (val instanceof Double) { + protoMsg.addRepeatedField(field, new Double((double) val)); + } else if (val instanceof Float) { + protoMsg.addRepeatedField(field, new Double((float) val)); + } else { + throw new IllegalArgumentException( + "JSONObject does not have a double field at " + + currentScope + + "[" + + i + + "]" + + "."); + } + } catch (JSONException e) { + throw new IllegalArgumentException( + "JSONObject does not have a double field at " + currentScope + "[" + i + "]" + "."); + } + } + break; + case MESSAGE: + for (int i = 0; i < jsonArray.length(); i++) { + try { + Message.Builder message = protoMsg.newBuilderForField(field); + protoMsg.addRepeatedField( + field, + convertJsonToProtoMessageImpl( + field.getMessageType(), + jsonArray.getJSONObject(i), + currentScope, + false, + allowUnknownFields)); + } catch (JSONException e) { + throw new IllegalArgumentException( + "JSONObject does not have an object field at " + + currentScope + + "[" + + i + + "]" + + "."); + } + } + break; + } + } +} diff --git a/google-cloud-bigquerystorage/src/test/java/com/google/cloud/bigquery/storage/v1alpha2/JsonToProtoMessageTest.java b/google-cloud-bigquerystorage/src/test/java/com/google/cloud/bigquery/storage/v1alpha2/JsonToProtoMessageTest.java new file mode 100644 index 0000000000..104baeb69a --- /dev/null +++ b/google-cloud-bigquerystorage/src/test/java/com/google/cloud/bigquery/storage/v1alpha2/JsonToProtoMessageTest.java @@ -0,0 +1,625 @@ +/* + * 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 static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import com.google.cloud.bigquery.storage.test.SchemaTest.*; +import com.google.common.collect.ImmutableMap; +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.DynamicMessage; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import org.json.JSONArray; +import org.json.JSONObject; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class JsonToProtoMessageTest { + private static ImmutableMap SimpleDescriptorsToDebugMessageTest = + new ImmutableMap.Builder() + .put(BoolType.getDescriptor(), "boolean") + .put(BytesType.getDescriptor(), "string") + .put(Int64Type.getDescriptor(), "int64") + .put(DoubleType.getDescriptor(), "double") + .put(StringType.getDescriptor(), "string") + .build(); + + private static JSONObject[] simpleJSONObjects = { + new JSONObject().put("test_field_type", 123), + new JSONObject().put("test_field_type", 1.23), + new JSONObject().put("test_field_type", true), + new JSONObject().put("test_field_type", "test") + }; + + // private static JSONObject[] simpleJSONArrays = { + // new JSONObject() + // .put( + // "test_field_type", + // new JSONArray(new Long[] {Long.MAX_VALUE, Long.MIN_VALUE, Integer.MAX_VALUE, + // Integer.MIN_VALUE, Short.MAX_VALUE, Short.MIN_VALUE, Byte.MAX_VALUE, Byte.MIN_VALUE, 0})), + // new JSONObject().put("test_field_type", new JSONArray(new Double[]{Double.MAX_VALUE, + // Double.MIN_VALUE})), + // new JSONObject().put("test_field_type", new JSONArray("[true, false]")), + // new JSONObject().put("test_field_type", new JSONArray("[hello, test]")) + // }; + + private void isProtoJsonEqual(DynamicMessage proto, JSONObject json) { + for (Map.Entry entry : proto.getAllFields().entrySet()) { + FieldDescriptor key = entry.getKey(); + java.lang.Object value = entry.getValue(); + if (key.isRepeated()) { + isProtoArrayJsonArrayEqual(key, value, json); + } else { + isProtoFieldJsonFieldEqual(key, value, json); + } + } + } + + private void isProtoFieldJsonFieldEqual( + FieldDescriptor key, java.lang.Object value, JSONObject json) { + String fieldName = key.getName(); + switch (key.getType()) { + case BOOL: + assertTrue((Boolean) value == json.getBoolean(fieldName)); + break; + case BYTES: + assertTrue(Arrays.equals((byte[]) value, json.getString(fieldName).getBytes())); + break; + case INT64: + assertTrue((long) value == json.getLong(fieldName)); + break; + case STRING: + assertTrue(((String) value).equals(json.getString(fieldName))); + break; + case DOUBLE: + assertTrue((double) value == json.getDouble(fieldName)); + break; + case MESSAGE: + isProtoJsonEqual((DynamicMessage) value, json.getJSONObject(fieldName)); + break; + } + } + + private void isProtoArrayJsonArrayEqual( + FieldDescriptor key, java.lang.Object value, JSONObject json) { + String fieldName = key.getName(); + JSONArray jsonArray = json.getJSONArray(fieldName); + switch (key.getType()) { + case BOOL: + List boolArr = (List) value; + for (int i = 0; i < jsonArray.length(); i++) { + assertTrue((boolArr.get(i) == jsonArray.getBoolean(i))); + } + break; + case BYTES: + List byteArr = (List) value; + for (int i = 0; i < jsonArray.length(); i++) { + assertTrue(Arrays.equals(byteArr.get(i), jsonArray.getString(i).getBytes())); + } + break; + case INT64: + List longArr = (List) value; + for (int i = 0; i < jsonArray.length(); i++) { + assertTrue((longArr.get(i) == jsonArray.getLong(i))); + } + break; + case STRING: + List stringArr = (List) value; + for (int i = 0; i < jsonArray.length(); i++) { + assertTrue(stringArr.get(i).equals(jsonArray.getString(i))); + } + break; + case DOUBLE: + List doubleArr = (List) value; + for (int i = 0; i < jsonArray.length(); i++) { + assertTrue((doubleArr.get(i) == jsonArray.getDouble(i))); + } + break; + case MESSAGE: + List messageArr = (List) value; + for (int i = 0; i < jsonArray.length(); i++) { + isProtoJsonEqual(messageArr.get(i), jsonArray.getJSONObject(i)); + } + break; + } + } + + @Test + public void testSimpleTypes() throws Exception { + for (Map.Entry entry : SimpleDescriptorsToDebugMessageTest.entrySet()) { + int success = 0; + for (JSONObject json : simpleJSONObjects) { + try { + DynamicMessage protoMsg = + JsonToProtoMessage.convertJsonToProtoMessage(entry.getKey(), json); + isProtoJsonEqual(protoMsg, json); + success += 1; + } catch (IllegalArgumentException e) { + assertEquals( + e.getMessage(), + "JSONObject does not have a " + entry.getValue() + " field at root.test_field_type."); + } + } + assertEquals(1, success); + } + } + + @Test + public void testBQSchemaToProtobufferStructSimple() throws Exception { + 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); + isProtoJsonEqual(protoMsg, json); + } + + @Test + public void testBQSchemaToProtobufferStructSimpleFail() 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); + } catch (IllegalArgumentException e) { + assertEquals( + e.getMessage(), + "JSONObject does not have a string field at root.test_field_type.test_field_type."); + } + } + + // @Test + // public void testBQSchemaToProtobufferStructComplex() throws Exception { + // Table.TableFieldSchema bqBytes = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.BYTES) + // .setMode(Table.TableFieldSchema.Mode.NULLABLE) + // .setName("bytes") + // .build(); + // Table.TableFieldSchema bqInt = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.INT64) + // .setMode(Table.TableFieldSchema.Mode.NULLABLE) + // .setName("int") + // .build(); + // Table.TableFieldSchema record1 = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.STRUCT) + // .setMode(Table.TableFieldSchema.Mode.NULLABLE) + // .setName("record1") + // .addFields(0, bqInt) + // .build(); + // Table.TableFieldSchema record = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.STRUCT) + // .setMode(Table.TableFieldSchema.Mode.NULLABLE) + // .setName("record") + // .addFields(0, bqInt) + // .addFields(1, bqBytes) + // .addFields(2, record1) + // .build(); + // Table.TableFieldSchema bqDouble = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.DOUBLE) + // .setMode(Table.TableFieldSchema.Mode.NULLABLE) + // .setName("float") + // .build(); + // Table.TableSchema tableSchema = + // Table.TableSchema.newBuilder().addFields(0, record).addFields(1, bqDouble).build(); + // + // JSONObject jsonRecord1 = new JSONObject(); + // jsonRecord1.put("int", 2048); + // JSONObject jsonRecord = new JSONObject(); + // jsonRecord.put("int", 1024); + // jsonRecord.put("bytes", "testing"); + // jsonRecord.put("record1", jsonRecord1); + // JSONObject json = new JSONObject(); + // json.put("record", jsonRecord); + // json.put("float", 1.23); + // + // Descriptor descriptor = JsonToProtoConverter.BQTableSchemaToProtoSchema(tableSchema); + // DynamicMessage protoMsg = JsonToProtoConverter.protoSchemaToProtoMessage(descriptor, json); + // assertTrue(isProtoJsonEqual(protoMsg, json)); + // } + // + // @Test + // public void testBQSchemaToProtobufferStructComplexFail() throws Exception { + // Table.TableFieldSchema bqInt = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.INT64) + // .setMode(Table.TableFieldSchema.Mode.NULLABLE) + // .setName("int") + // .build(); + // Table.TableFieldSchema record = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.STRUCT) + // .setMode(Table.TableFieldSchema.Mode.NULLABLE) + // .setName("record") + // .addFields(0, bqInt) + // .build(); + // Table.TableFieldSchema bqDouble = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.DOUBLE) + // .setMode(Table.TableFieldSchema.Mode.NULLABLE) + // .setName("float") + // .build(); + // Table.TableSchema tableSchema = + // Table.TableSchema.newBuilder().addFields(0, record).addFields(1, bqDouble).build(); + // + // JSONObject json = new JSONObject(); + // json.put("record", 1.23); + // json.put("float", 1.23); + // try { + // Descriptor descriptor = JsonToProtoConverter.BQTableSchemaToProtoSchema(tableSchema); + // DynamicMessage protoMsg = JsonToProtoConverter.protoSchemaToProtoMessage(descriptor, json); + // } catch (IllegalArgumentException e) { + // assertEquals(e.getMessage(), "JSONObject does not have an object field at .record."); + // } + // } + // + // @Test + // public void testBQSchemaToProtobufferRepeatedSimple() throws Exception { + // for (Map.Entry entry : + // BQTableTypeToDebugMessage.entrySet()) { + // Table.TableFieldSchema tableFieldSchema = + // Table.TableFieldSchema.newBuilder() + // .setType(entry.getKey()) + // .setMode(Table.TableFieldSchema.Mode.REPEATED) + // .setName("test_field_type") + // .build(); + // Table.TableSchema tableSchema = + // Table.TableSchema.newBuilder().addFields(0, tableFieldSchema).build(); + // int success = 0; + // for (JSONObject json : simpleJSONArrays) { + // try { + // Descriptor descriptor = JsonToProtoConverter.BQTableSchemaToProtoSchema(tableSchema); + // DynamicMessage protoMsg = + // JsonToProtoConverter.protoSchemaToProtoMessage(descriptor, json); + // success += 1; + // } catch (IllegalArgumentException e) { + // assertEquals( + // e.getMessage(), + // "JSONObject does not have a " + // + entry.getValue() + // + " field at .test_field_type[0]."); + // } + // } + // assertEquals(1, success); + // } + // } + // + // @Test + // public void testBQSchemaToProtobufferRepeatedSimpleInt64() throws Exception { + // Table.TableFieldSchema bqByte = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.INT64) + // .setMode(Table.TableFieldSchema.Mode.REPEATED) + // .setName("byte") + // .build(); + // Table.TableFieldSchema bqShort = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.INT64) + // .setMode(Table.TableFieldSchema.Mode.REPEATED) + // .setName("short") + // .build(); + // Table.TableFieldSchema bqInt = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.INT64) + // .setMode(Table.TableFieldSchema.Mode.REPEATED) + // .setName("int") + // .build(); + // Table.TableFieldSchema bqLong = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.INT64) + // .setMode(Table.TableFieldSchema.Mode.REPEATED) + // .setName("long") + // .build(); + // Table.TableSchema tableSchema = + // Table.TableSchema.newBuilder() + // .addFields(0, bqByte) + // .addFields(1, bqShort) + // .addFields(2, bqInt) + // .addFields(3, bqLong) + // .build(); + // JSONObject json = new JSONObject(); + // byte[] byteArr = {(byte) 1, (byte) 2}; + // short[] shortArr = {(short) 1, (short) 2}; + // int[] intArr = {1, 2, 3, 4, 5}; + // long[] longArr = {1L, 2L, 3L, 4L, 5L}; + // json.put("byte", new JSONArray(byteArr)); + // json.put("short", new JSONArray(shortArr)); + // json.put("int", new JSONArray(intArr)); + // json.put("long", new JSONArray(longArr)); + // Descriptor descriptor = JsonToProtoConverter.BQTableSchemaToProtoSchema(tableSchema); + // DynamicMessage protoMsg = JsonToProtoConverter.protoSchemaToProtoMessage(descriptor, json); + // assertTrue(isProtoJsonEqual(protoMsg, json)); + // } + // + // @Test + // public void testBQSchemaToProtobufferRepeatedSimpleDouble() throws Exception { + // Table.TableFieldSchema bqDouble = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.DOUBLE) + // .setMode(Table.TableFieldSchema.Mode.REPEATED) + // .setName("double") + // .build(); + // Table.TableFieldSchema bqFloat = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.DOUBLE) + // .setMode(Table.TableFieldSchema.Mode.REPEATED) + // .setName("float") + // .build(); + // Table.TableSchema tableSchema = + // Table.TableSchema.newBuilder().addFields(0, bqDouble).addFields(1, bqFloat).build(); + // JSONObject json = new JSONObject(); + // double[] doubleArr = {1.1, 2.2, 3.3, 4.4, 5.5}; + // float[] floatArr = {1.1f, 2.2f, 3.3f, 4.4f, 5.5f}; + // json.put("double", new JSONArray(doubleArr)); + // json.put("float", new JSONArray(floatArr)); + // Descriptor descriptor = JsonToProtoConverter.BQTableSchemaToProtoSchema(tableSchema); + // DynamicMessage protoMsg = JsonToProtoConverter.protoSchemaToProtoMessage(descriptor, json); + // assertTrue(isProtoJsonEqual(protoMsg, json)); + // } + // + // @Test + // public void testBQSchemaToProtobufferRepeatedSimpleFail() throws Exception { + // Table.TableFieldSchema bqDouble = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.DOUBLE) + // .setMode(Table.TableFieldSchema.Mode.REPEATED) + // .setName("float") + // .build(); + // Table.TableSchema tableSchema = Table.TableSchema.newBuilder().addFields(0, + // bqDouble).build(); + // JSONObject json = new JSONObject(); + // json.put("float", new JSONArray("[1.1, 2.2, 3.3, hello, 4.4]")); + // try { + // Descriptor descriptor = JsonToProtoConverter.BQTableSchemaToProtoSchema(tableSchema); + // DynamicMessage protoMsg = JsonToProtoConverter.protoSchemaToProtoMessage(descriptor, json); + // } catch (IllegalArgumentException e) { + // assertEquals(e.getMessage(), "JSONObject does not have a double field at .float[3]."); + // } + // } + // + // @Test + // public void testBQSchemaToProtobufferRepeatedComplex() throws Exception { + // Table.TableFieldSchema bqString = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.STRING) + // .setMode(Table.TableFieldSchema.Mode.REPEATED) + // .setName("string") + // .build(); + // Table.TableFieldSchema record = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.STRUCT) + // .setMode(Table.TableFieldSchema.Mode.NULLABLE) + // .setName("test_field_type") + // .addFields(0, bqString) + // .build(); + // Table.TableFieldSchema bqInt = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.INT64) + // .setMode(Table.TableFieldSchema.Mode.REPEATED) + // .setName("int") + // .build(); + // Table.TableFieldSchema bqDouble = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.DOUBLE) + // .setMode(Table.TableFieldSchema.Mode.REPEATED) + // .setName("float") + // .build(); + // Table.TableSchema tableSchema = + // Table.TableSchema.newBuilder() + // .addFields(0, bqDouble) + // .addFields(1, bqInt) + // .addFields(2, record) + // .build(); + // JSONObject json = new JSONObject(); + // 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}; + // json.put("float", new JSONArray(doubleArr)); + // json.put("int", new JSONArray(intArr)); + // JSONObject jsonRecord = new JSONObject(); + // jsonRecord.put("string", new JSONArray(stringArr)); + // json.put("test_field_type", jsonRecord); + // Descriptor descriptor = JsonToProtoConverter.BQTableSchemaToProtoSchema(tableSchema); + // DynamicMessage protoMsg = JsonToProtoConverter.protoSchemaToProtoMessage(descriptor, json); + // assertTrue(isProtoJsonEqual(protoMsg, json)); + // } + // + // @Test + // public void testBQSchemaToProtobufferRepeatedComplexFail() throws Exception { + // Table.TableFieldSchema bqInt = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.INT64) + // .setMode(Table.TableFieldSchema.Mode.REPEATED) + // .setName("int") + // .build(); + // Table.TableFieldSchema bqDouble = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.DOUBLE) + // .setMode(Table.TableFieldSchema.Mode.REPEATED) + // .setName("float") + // .build(); + // Table.TableSchema tableSchema = + // Table.TableSchema.newBuilder().addFields(0, bqDouble).addFields(1, bqInt).build(); + // JSONObject json = new JSONObject(); + // int[] intArr = {1, 2, 3, 4, 5}; + // json.put("float", "1"); + // json.put("int", new JSONArray(intArr)); + // try { + // Descriptor descriptor = JsonToProtoConverter.BQTableSchemaToProtoSchema(tableSchema); + // DynamicMessage protoMsg = JsonToProtoConverter.protoSchemaToProtoMessage(descriptor, json); + // } catch (IllegalArgumentException e) { + // assertEquals(e.getMessage(), "JSONObject does not have an array field at .float."); + // } + // } + // + // @Test + // public void testBQSchemaToProtobufferAllowUnknownFields() throws Exception { + // Table.TableFieldSchema bqDouble = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.DOUBLE) + // .setMode(Table.TableFieldSchema.Mode.NULLABLE) + // .setName("float") + // .build(); + // Table.TableSchema tableSchema = Table.TableSchema.newBuilder().addFields(0, + // bqDouble).build(); + // JSONObject json = new JSONObject(); + // json.put("float", 1.1); + // json.put("string", "hello"); + // + // Descriptor descriptor = JsonToProtoConverter.BQTableSchemaToProtoSchema(tableSchema); + // DynamicMessage protoMsg = + // JsonToProtoConverter.protoSchemaToProtoMessage(descriptor, json, true); + // assertTrue(isProtoJsonEqual(protoMsg, json)); + // } + // + // @Test + // public void testBQSchemaToProtobufferAllowUnknownFieldsFail() throws Exception { + // Table.TableFieldSchema bqDouble = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.DOUBLE) + // .setMode(Table.TableFieldSchema.Mode.NULLABLE) + // .setName("float") + // .build(); + // Table.TableSchema tableSchema = Table.TableSchema.newBuilder().addFields(0, + // bqDouble).build(); + // JSONObject json = new JSONObject(); + // json.put("float", 1.1); + // json.put("string", "hello"); + // try { + // Descriptor descriptor = JsonToProtoConverter.BQTableSchemaToProtoSchema(tableSchema); + // DynamicMessage protoMsg = JsonToProtoConverter.protoSchemaToProtoMessage(descriptor, json); + // } catch (IllegalArgumentException e) { + // assertEquals( + // e.getMessage(), + // "JSONObject has unknown fields. Set allowUnknownFields to True to ignore unknown + // fields."); + // } + // } + // + // @Test + // public void testBQSchemaToProtobufferRequiredFail() throws Exception { + // Table.TableFieldSchema bqDouble = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.DOUBLE) + // .setMode(Table.TableFieldSchema.Mode.REQUIRED) + // .setName("float") + // .build(); + // Table.TableSchema tableSchema = Table.TableSchema.newBuilder().addFields(0, + // bqDouble).build(); + // JSONObject json = new JSONObject(); + // json.put("float1", 1.1); + // try { + // Descriptor descriptor = JsonToProtoConverter.BQTableSchemaToProtoSchema(tableSchema); + // DynamicMessage protoMsg = JsonToProtoConverter.protoSchemaToProtoMessage(descriptor, json); + // } catch (IllegalArgumentException e) { + // assertEquals(e.getMessage(), "JSONObject does not have the required field .float."); + // } + // } + // + // @Test + // public void testBQSchemaToProtobufferTopLevelMatchFail() throws Exception { + // Table.TableFieldSchema bqDouble = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.DOUBLE) + // .setMode(Table.TableFieldSchema.Mode.NULLABLE) + // .setName("float") + // .build(); + // Table.TableSchema tableSchema = Table.TableSchema.newBuilder().addFields(0, + // bqDouble).build(); + // JSONObject json = new JSONObject(); + // json.put("float1", 1.1); + // try { + // Descriptor descriptor = JsonToProtoConverter.BQTableSchemaToProtoSchema(tableSchema); + // DynamicMessage protoMsg = JsonToProtoConverter.protoSchemaToProtoMessage(descriptor, json); + // } catch (IllegalArgumentException e) { + // assertEquals( + // e.getMessage(), + // "There are no matching fields found for the JSONObject and the BigQuery table."); + // } + // } + // + // @Test + // public void testBQSchemaToProtobufferOptional() throws Exception { + // Table.TableFieldSchema StringType = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.STRING) + // .setMode(Table.TableFieldSchema.Mode.NULLABLE) + // .setName("test_field_type") + // .build(); + // Table.TableFieldSchema tableFieldSchema = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.STRUCT) + // .setMode(Table.TableFieldSchema.Mode.NULLABLE) + // .setName("test_field_type") + // .addFields(0, StringType) + // .build(); + // Table.TableFieldSchema actualStringType = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.STRING) + // .setMode(Table.TableFieldSchema.Mode.NULLABLE) + // .setName("test_field_type1") + // .build(); + // Table.TableSchema tableSchema = + // Table.TableSchema.newBuilder() + // .addFields(0, tableFieldSchema) + // .addFields(1, actualStringType) + // .build(); + // + // JSONObject stringType = new JSONObject(); + // stringType.put("test_field_type1", 1); + // JSONObject json = new JSONObject(); + // json.put("test_field_type", stringType); + // json.put("test_field_type2", "hello"); + // + // Descriptor descriptor = JsonToProtoConverter.BQTableSchemaToProtoSchema(tableSchema); + // DynamicMessage protoMsg = JsonToProtoConverter.protoSchemaToProtoMessage(descriptor, json); + // assertTrue(isProtoJsonEqual(protoMsg, json)); + // } + // + // @Test + // public void testBQSchemaToProtobufferNullJson() throws Exception { + // Table.TableFieldSchema bqDouble = + // Table.TableFieldSchema.newBuilder() + // .setType(Table.TableFieldSchema.Type.DOUBLE) + // .setMode(Table.TableFieldSchema.Mode.NULLABLE) + // .setName("float") + // .build(); + // Table.TableSchema tableSchema = Table.TableSchema.newBuilder().addFields(0, + // bqDouble).build(); + // JSONObject json = new JSONObject(); + // json.put("float", JSONObject.NULL); + // try { + // Descriptor descriptor = JsonToProtoConverter.BQTableSchemaToProtoSchema(tableSchema); + // DynamicMessage protoMsg = JsonToProtoConverter.protoSchemaToProtoMessage(descriptor, json); + // } catch (IllegalArgumentException e) { + // assertEquals(e.getMessage(), "JSONObject does not have a double field at .float."); + // } + // } +}