Skip to content

Commit

Permalink
Fix according to PR (added case insensitive feature, added support to…
Browse files Browse the repository at this point in the history
… int32 for BQDate)
  • Loading branch information
allenc3 committed Jul 13, 2020
1 parent 5ec43bd commit 3ea5b56
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 54 deletions.
Expand Up @@ -19,6 +19,7 @@
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.DynamicMessage;
import com.google.protobuf.Message;
import java.util.HashMap;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
Expand Down Expand Up @@ -77,15 +78,21 @@ private static DynamicMessage convertJsonToProtoMessageImpl(
if (JSONObject.getNames(json).length > protoFields.size()) {
if (!allowUnknownFields) {
throw new IllegalArgumentException(
"JSONObject has unknown fields. Set allowUnknownFields to True to ignore unknown fields.");
"JSONObject has fields unknown to BigQuery: f1. Set allowUnknownFields to True to allow unknown fields.");
}
}
HashMap<String, String> jsonLowercaseNameToActualName = new HashMap<String, String>();
String[] actualNames = JSONObject.getNames(json);
for (int i = 0; i < actualNames.length; i++) {
jsonLowercaseNameToActualName.put(actualNames[i].toLowerCase(), actualNames[i]);
}

for (FieldDescriptor field : protoFields) {
String fieldName = field.getName();
String lowercaseFieldName = fieldName.toLowerCase();
String currentScope = jsonScope + "." + fieldName;

if (!json.has(fieldName)) {
if (!jsonLowercaseNameToActualName.containsKey(lowercaseFieldName)) {
if (field.isRequired()) {
throw new IllegalArgumentException(
"JSONObject does not have the required field " + currentScope + ".");
Expand All @@ -95,9 +102,21 @@ private static DynamicMessage convertJsonToProtoMessageImpl(
}
matchedFields++;
if (!field.isRepeated()) {
fillField(protoMsg, field, json, currentScope, allowUnknownFields);
fillField(
protoMsg,
field,
json,
jsonLowercaseNameToActualName.get(lowercaseFieldName),
currentScope,
allowUnknownFields);
} else {
fillRepeatedField(protoMsg, field, json, currentScope, allowUnknownFields);
fillRepeatedField(
protoMsg,
field,
json,
jsonLowercaseNameToActualName.get(lowercaseFieldName),
currentScope,
allowUnknownFields);
}
}
if (matchedFields == 0 && topLevel) {
Expand All @@ -110,50 +129,51 @@ private static DynamicMessage convertJsonToProtoMessageImpl(
/**
* Fills a non-repetaed protoField with the json data.
*
* @param protoMsg
* @param field
* @param protoMsg The protocol buffer message being constructed
* @param fieldDescriptor
* @param json
* @param actualJsonKeyName Actual 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 field,
FieldDescriptor fieldDescriptor,
JSONObject json,
String actualJsonKeyName,
String currentScope,
boolean allowUnknownFields)
throws IllegalArgumentException {

String fieldName = field.getName();
switch (field.getType()) {
switch (fieldDescriptor.getType()) {
case BOOL:
try {
protoMsg.setField(field, new Boolean(json.getBoolean(fieldName)));
protoMsg.setField(fieldDescriptor, new Boolean(json.getBoolean(actualJsonKeyName)));
} 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());
protoMsg.setField(fieldDescriptor, json.getString(actualJsonKeyName).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);
java.lang.Object val = json.get(actualJsonKeyName);
if (val instanceof Byte) {
protoMsg.setField(field, new Long((Byte) val));
protoMsg.setField(fieldDescriptor, new Long((Byte) val));
} else if (val instanceof Short) {
protoMsg.setField(field, new Long((Short) val));
protoMsg.setField(fieldDescriptor, new Long((Short) val));
} else if (val instanceof Integer) {
protoMsg.setField(field, new Long((Integer) val));
protoMsg.setField(fieldDescriptor, new Long((Integer) val));
} else if (val instanceof Long) {
protoMsg.setField(field, new Long((Long) val));
protoMsg.setField(fieldDescriptor, new Long((Long) val));
} else {
throw new IllegalArgumentException(
"JSONObject does not have a int64 field at " + currentScope + ".");
Expand All @@ -163,21 +183,39 @@ private static void fillField(
"JSONObject does not have a int64 field at " + currentScope + ".");
}
break;
case INT32:
try {
java.lang.Object val = json.get(actualJsonKeyName);
if (val instanceof Byte) {
protoMsg.setField(fieldDescriptor, new Integer((Byte) val));
} else if (val instanceof Short) {
protoMsg.setField(fieldDescriptor, new Integer((Short) val));
} else if (val instanceof Integer) {
protoMsg.setField(fieldDescriptor, new Integer((Integer) val));
} else {
throw new IllegalArgumentException(
"JSONObject does not have a int32 field at " + currentScope + ".");
}
} catch (JSONException e) {
throw new IllegalArgumentException(
"JSONObject does not have a int32 field at " + currentScope + ".");
}
break;
case STRING:
try {
protoMsg.setField(field, json.getString(fieldName));
protoMsg.setField(fieldDescriptor, json.getString(actualJsonKeyName));
} 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);
java.lang.Object val = json.get(actualJsonKeyName);
if (val instanceof Double) {
protoMsg.setField(field, new Double((double) val));
protoMsg.setField(fieldDescriptor, new Double((double) val));
} else if (val instanceof Float) {
protoMsg.setField(field, new Double((float) val));
protoMsg.setField(fieldDescriptor, new Double((float) val));
} else {
throw new IllegalArgumentException(
"JSONObject does not have a double field at " + currentScope + ".");
Expand All @@ -188,13 +226,13 @@ private static void fillField(
}
break;
case MESSAGE:
Message.Builder message = protoMsg.newBuilderForField(field);
Message.Builder message = protoMsg.newBuilderForField(fieldDescriptor);
try {
protoMsg.setField(
field,
fieldDescriptor,
convertJsonToProtoMessageImpl(
field.getMessageType(),
json.getJSONObject(fieldName),
fieldDescriptor.getMessageType(),
json.getJSONObject(actualJsonKeyName),
currentScope,
false,
allowUnknownFields));
Expand All @@ -209,34 +247,36 @@ private static void fillField(
/**
* Fills a repeated protoField with the json data.
*
* @param protoMsg
* @param field
* @param protoMsg The protocol buffer message being constructed
* @param fieldDescriptor
* @param json If root level has no matching fields, throws exception.
* @param actualJsonKeyName Actual 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 field,
FieldDescriptor fieldDescriptor,
JSONObject json,
String actualJsonKeyName,
String currentScope,
boolean allowUnknownFields)
throws IllegalArgumentException {
String fieldName = field.getName();

JSONArray jsonArray;
try {
jsonArray = json.getJSONArray(fieldName);
jsonArray = json.getJSONArray(actualJsonKeyName);
} catch (JSONException e) {
throw new IllegalArgumentException(
"JSONObject does not have a array field at " + currentScope + ".");
}

switch (field.getType()) {
switch (fieldDescriptor.getType()) {
case BOOL:
for (int i = 0; i < jsonArray.length(); i++) {
try {
protoMsg.addRepeatedField(field, new Boolean(jsonArray.getBoolean(i)));
protoMsg.addRepeatedField(fieldDescriptor, new Boolean(jsonArray.getBoolean(i)));
} catch (JSONException e) {
throw new IllegalArgumentException(
"JSONObject does not have a boolean field at "
Expand All @@ -251,7 +291,7 @@ private static void fillRepeatedField(
case BYTES:
for (int i = 0; i < jsonArray.length(); i++) {
try {
protoMsg.addRepeatedField(field, jsonArray.getString(i).getBytes());
protoMsg.addRepeatedField(fieldDescriptor, jsonArray.getString(i).getBytes());
} catch (JSONException e) {
throw new IllegalArgumentException(
"JSONObject does not have a string field at " + currentScope + "[" + i + "]" + ".");
Expand All @@ -263,13 +303,13 @@ private static void fillRepeatedField(
try {
java.lang.Object val = jsonArray.get(i);
if (val instanceof Byte) {
protoMsg.addRepeatedField(field, new Long((Byte) val));
protoMsg.addRepeatedField(fieldDescriptor, new Long((Byte) val));
} else if (val instanceof Short) {
protoMsg.addRepeatedField(field, new Long((Short) val));
protoMsg.addRepeatedField(fieldDescriptor, new Long((Short) val));
} else if (val instanceof Integer) {
protoMsg.addRepeatedField(field, new Long((Integer) val));
protoMsg.addRepeatedField(fieldDescriptor, new Long((Integer) val));
} else if (val instanceof Long) {
protoMsg.addRepeatedField(field, new Long((Long) val));
protoMsg.addRepeatedField(fieldDescriptor, new Long((Long) val));
} else {
throw new IllegalArgumentException(
"JSONObject does not have a int64 field at "
Expand All @@ -285,10 +325,35 @@ private static void fillRepeatedField(
}
}
break;
case INT32:
for (int i = 0; i < jsonArray.length(); i++) {
try {
java.lang.Object val = jsonArray.get(i);
if (val instanceof Byte) {
protoMsg.addRepeatedField(fieldDescriptor, new Integer((Byte) val));
} else if (val instanceof Short) {
protoMsg.addRepeatedField(fieldDescriptor, new Integer((Short) val));
} else if (val instanceof Integer) {
protoMsg.addRepeatedField(fieldDescriptor, new Integer((Integer) val));
} else {
throw new IllegalArgumentException(
"JSONObject does not have a int32 field at "
+ currentScope
+ "["
+ i
+ "]"
+ ".");
}
} catch (JSONException e) {
throw new IllegalArgumentException(
"JSONObject does not have a int32 field at " + currentScope + "[" + i + "]" + ".");
}
}
break;
case STRING:
for (int i = 0; i < jsonArray.length(); i++) {
try {
protoMsg.addRepeatedField(field, jsonArray.getString(i));
protoMsg.addRepeatedField(fieldDescriptor, jsonArray.getString(i));
} catch (JSONException e) {
throw new IllegalArgumentException(
"JSONObject does not have a string field at " + currentScope + "[" + i + "]" + ".");
Expand All @@ -300,9 +365,9 @@ private static void fillRepeatedField(
try {
java.lang.Object val = jsonArray.get(i);
if (val instanceof Double) {
protoMsg.addRepeatedField(field, new Double((double) val));
protoMsg.addRepeatedField(fieldDescriptor, new Double((double) val));
} else if (val instanceof Float) {
protoMsg.addRepeatedField(field, new Double((float) val));
protoMsg.addRepeatedField(fieldDescriptor, new Double((float) val));
} else {
throw new IllegalArgumentException(
"JSONObject does not have a double field at "
Expand All @@ -321,11 +386,11 @@ private static void fillRepeatedField(
case MESSAGE:
for (int i = 0; i < jsonArray.length(); i++) {
try {
Message.Builder message = protoMsg.newBuilderForField(field);
Message.Builder message = protoMsg.newBuilderForField(fieldDescriptor);
protoMsg.addRepeatedField(
field,
fieldDescriptor,
convertJsonToProtoMessageImpl(
field.getMessageType(),
fieldDescriptor.getMessageType(),
jsonArray.getJSONObject(i),
currentScope,
false,
Expand Down

0 comments on commit 3ea5b56

Please sign in to comment.