Skip to content

Commit 3ea5b56

Browse files
committed
Fix according to PR (added case insensitive feature, added support to int32 for BQDate)
1 parent 5ec43bd commit 3ea5b56

File tree

3 files changed

+211
-54
lines changed

3 files changed

+211
-54
lines changed

google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/JsonToProtoMessage.java

Lines changed: 107 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.google.protobuf.Descriptors.FieldDescriptor;
2020
import com.google.protobuf.DynamicMessage;
2121
import com.google.protobuf.Message;
22+
import java.util.HashMap;
2223
import java.util.List;
2324
import org.json.JSONArray;
2425
import org.json.JSONException;
@@ -77,15 +78,21 @@ private static DynamicMessage convertJsonToProtoMessageImpl(
7778
if (JSONObject.getNames(json).length > protoFields.size()) {
7879
if (!allowUnknownFields) {
7980
throw new IllegalArgumentException(
80-
"JSONObject has unknown fields. Set allowUnknownFields to True to ignore unknown fields.");
81+
"JSONObject has fields unknown to BigQuery: f1. Set allowUnknownFields to True to allow unknown fields.");
8182
}
8283
}
84+
HashMap<String, String> jsonLowercaseNameToActualName = new HashMap<String, String>();
85+
String[] actualNames = JSONObject.getNames(json);
86+
for (int i = 0; i < actualNames.length; i++) {
87+
jsonLowercaseNameToActualName.put(actualNames[i].toLowerCase(), actualNames[i]);
88+
}
8389

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

88-
if (!json.has(fieldName)) {
95+
if (!jsonLowercaseNameToActualName.containsKey(lowercaseFieldName)) {
8996
if (field.isRequired()) {
9097
throw new IllegalArgumentException(
9198
"JSONObject does not have the required field " + currentScope + ".");
@@ -95,9 +102,21 @@ private static DynamicMessage convertJsonToProtoMessageImpl(
95102
}
96103
matchedFields++;
97104
if (!field.isRepeated()) {
98-
fillField(protoMsg, field, json, currentScope, allowUnknownFields);
105+
fillField(
106+
protoMsg,
107+
field,
108+
json,
109+
jsonLowercaseNameToActualName.get(lowercaseFieldName),
110+
currentScope,
111+
allowUnknownFields);
99112
} else {
100-
fillRepeatedField(protoMsg, field, json, currentScope, allowUnknownFields);
113+
fillRepeatedField(
114+
protoMsg,
115+
field,
116+
json,
117+
jsonLowercaseNameToActualName.get(lowercaseFieldName),
118+
currentScope,
119+
allowUnknownFields);
101120
}
102121
}
103122
if (matchedFields == 0 && topLevel) {
@@ -110,50 +129,51 @@ private static DynamicMessage convertJsonToProtoMessageImpl(
110129
/**
111130
* Fills a non-repetaed protoField with the json data.
112131
*
113-
* @param protoMsg
114-
* @param field
132+
* @param protoMsg The protocol buffer message being constructed
133+
* @param fieldDescriptor
115134
* @param json
135+
* @param actualJsonKeyName Actual key name in JSONObject instead of lowercased version
116136
* @param currentScope Debugging purposes
117137
* @param allowUnknownFields Ignores unknown JSON fields.
118138
* @throws IllegalArgumentException when JSON data is not compatible with proto descriptor.
119139
*/
120140
private static void fillField(
121141
DynamicMessage.Builder protoMsg,
122-
FieldDescriptor field,
142+
FieldDescriptor fieldDescriptor,
123143
JSONObject json,
144+
String actualJsonKeyName,
124145
String currentScope,
125146
boolean allowUnknownFields)
126147
throws IllegalArgumentException {
127148

128-
String fieldName = field.getName();
129-
switch (field.getType()) {
149+
switch (fieldDescriptor.getType()) {
130150
case BOOL:
131151
try {
132-
protoMsg.setField(field, new Boolean(json.getBoolean(fieldName)));
152+
protoMsg.setField(fieldDescriptor, new Boolean(json.getBoolean(actualJsonKeyName)));
133153
} catch (JSONException e) {
134154
throw new IllegalArgumentException(
135155
"JSONObject does not have a boolean field at " + currentScope + ".");
136156
}
137157
break;
138158
case BYTES:
139159
try {
140-
protoMsg.setField(field, json.getString(fieldName).getBytes());
160+
protoMsg.setField(fieldDescriptor, json.getString(actualJsonKeyName).getBytes());
141161
} catch (JSONException e) {
142162
throw new IllegalArgumentException(
143163
"JSONObject does not have a string field at " + currentScope + ".");
144164
}
145165
break;
146166
case INT64:
147167
try {
148-
java.lang.Object val = json.get(fieldName);
168+
java.lang.Object val = json.get(actualJsonKeyName);
149169
if (val instanceof Byte) {
150-
protoMsg.setField(field, new Long((Byte) val));
170+
protoMsg.setField(fieldDescriptor, new Long((Byte) val));
151171
} else if (val instanceof Short) {
152-
protoMsg.setField(field, new Long((Short) val));
172+
protoMsg.setField(fieldDescriptor, new Long((Short) val));
153173
} else if (val instanceof Integer) {
154-
protoMsg.setField(field, new Long((Integer) val));
174+
protoMsg.setField(fieldDescriptor, new Long((Integer) val));
155175
} else if (val instanceof Long) {
156-
protoMsg.setField(field, new Long((Long) val));
176+
protoMsg.setField(fieldDescriptor, new Long((Long) val));
157177
} else {
158178
throw new IllegalArgumentException(
159179
"JSONObject does not have a int64 field at " + currentScope + ".");
@@ -163,21 +183,39 @@ private static void fillField(
163183
"JSONObject does not have a int64 field at " + currentScope + ".");
164184
}
165185
break;
186+
case INT32:
187+
try {
188+
java.lang.Object val = json.get(actualJsonKeyName);
189+
if (val instanceof Byte) {
190+
protoMsg.setField(fieldDescriptor, new Integer((Byte) val));
191+
} else if (val instanceof Short) {
192+
protoMsg.setField(fieldDescriptor, new Integer((Short) val));
193+
} else if (val instanceof Integer) {
194+
protoMsg.setField(fieldDescriptor, new Integer((Integer) val));
195+
} else {
196+
throw new IllegalArgumentException(
197+
"JSONObject does not have a int32 field at " + currentScope + ".");
198+
}
199+
} catch (JSONException e) {
200+
throw new IllegalArgumentException(
201+
"JSONObject does not have a int32 field at " + currentScope + ".");
202+
}
203+
break;
166204
case STRING:
167205
try {
168-
protoMsg.setField(field, json.getString(fieldName));
206+
protoMsg.setField(fieldDescriptor, json.getString(actualJsonKeyName));
169207
} catch (JSONException e) {
170208
throw new IllegalArgumentException(
171209
"JSONObject does not have a string field at " + currentScope + ".");
172210
}
173211
break;
174212
case DOUBLE:
175213
try {
176-
java.lang.Object val = json.get(fieldName);
214+
java.lang.Object val = json.get(actualJsonKeyName);
177215
if (val instanceof Double) {
178-
protoMsg.setField(field, new Double((double) val));
216+
protoMsg.setField(fieldDescriptor, new Double((double) val));
179217
} else if (val instanceof Float) {
180-
protoMsg.setField(field, new Double((float) val));
218+
protoMsg.setField(fieldDescriptor, new Double((float) val));
181219
} else {
182220
throw new IllegalArgumentException(
183221
"JSONObject does not have a double field at " + currentScope + ".");
@@ -188,13 +226,13 @@ private static void fillField(
188226
}
189227
break;
190228
case MESSAGE:
191-
Message.Builder message = protoMsg.newBuilderForField(field);
229+
Message.Builder message = protoMsg.newBuilderForField(fieldDescriptor);
192230
try {
193231
protoMsg.setField(
194-
field,
232+
fieldDescriptor,
195233
convertJsonToProtoMessageImpl(
196-
field.getMessageType(),
197-
json.getJSONObject(fieldName),
234+
fieldDescriptor.getMessageType(),
235+
json.getJSONObject(actualJsonKeyName),
198236
currentScope,
199237
false,
200238
allowUnknownFields));
@@ -209,34 +247,36 @@ private static void fillField(
209247
/**
210248
* Fills a repeated protoField with the json data.
211249
*
212-
* @param protoMsg
213-
* @param field
250+
* @param protoMsg The protocol buffer message being constructed
251+
* @param fieldDescriptor
214252
* @param json If root level has no matching fields, throws exception.
253+
* @param actualJsonKeyName Actual key name in JSONObject instead of lowercased version
215254
* @param currentScope Debugging purposes
216255
* @param allowUnknownFields Ignores unknown JSON fields.
217256
* @throws IllegalArgumentException when JSON data is not compatible with proto descriptor.
218257
*/
219258
private static void fillRepeatedField(
220259
DynamicMessage.Builder protoMsg,
221-
FieldDescriptor field,
260+
FieldDescriptor fieldDescriptor,
222261
JSONObject json,
262+
String actualJsonKeyName,
223263
String currentScope,
224264
boolean allowUnknownFields)
225265
throws IllegalArgumentException {
226-
String fieldName = field.getName();
266+
227267
JSONArray jsonArray;
228268
try {
229-
jsonArray = json.getJSONArray(fieldName);
269+
jsonArray = json.getJSONArray(actualJsonKeyName);
230270
} catch (JSONException e) {
231271
throw new IllegalArgumentException(
232272
"JSONObject does not have a array field at " + currentScope + ".");
233273
}
234274

235-
switch (field.getType()) {
275+
switch (fieldDescriptor.getType()) {
236276
case BOOL:
237277
for (int i = 0; i < jsonArray.length(); i++) {
238278
try {
239-
protoMsg.addRepeatedField(field, new Boolean(jsonArray.getBoolean(i)));
279+
protoMsg.addRepeatedField(fieldDescriptor, new Boolean(jsonArray.getBoolean(i)));
240280
} catch (JSONException e) {
241281
throw new IllegalArgumentException(
242282
"JSONObject does not have a boolean field at "
@@ -251,7 +291,7 @@ private static void fillRepeatedField(
251291
case BYTES:
252292
for (int i = 0; i < jsonArray.length(); i++) {
253293
try {
254-
protoMsg.addRepeatedField(field, jsonArray.getString(i).getBytes());
294+
protoMsg.addRepeatedField(fieldDescriptor, jsonArray.getString(i).getBytes());
255295
} catch (JSONException e) {
256296
throw new IllegalArgumentException(
257297
"JSONObject does not have a string field at " + currentScope + "[" + i + "]" + ".");
@@ -263,13 +303,13 @@ private static void fillRepeatedField(
263303
try {
264304
java.lang.Object val = jsonArray.get(i);
265305
if (val instanceof Byte) {
266-
protoMsg.addRepeatedField(field, new Long((Byte) val));
306+
protoMsg.addRepeatedField(fieldDescriptor, new Long((Byte) val));
267307
} else if (val instanceof Short) {
268-
protoMsg.addRepeatedField(field, new Long((Short) val));
308+
protoMsg.addRepeatedField(fieldDescriptor, new Long((Short) val));
269309
} else if (val instanceof Integer) {
270-
protoMsg.addRepeatedField(field, new Long((Integer) val));
310+
protoMsg.addRepeatedField(fieldDescriptor, new Long((Integer) val));
271311
} else if (val instanceof Long) {
272-
protoMsg.addRepeatedField(field, new Long((Long) val));
312+
protoMsg.addRepeatedField(fieldDescriptor, new Long((Long) val));
273313
} else {
274314
throw new IllegalArgumentException(
275315
"JSONObject does not have a int64 field at "
@@ -285,10 +325,35 @@ private static void fillRepeatedField(
285325
}
286326
}
287327
break;
328+
case INT32:
329+
for (int i = 0; i < jsonArray.length(); i++) {
330+
try {
331+
java.lang.Object val = jsonArray.get(i);
332+
if (val instanceof Byte) {
333+
protoMsg.addRepeatedField(fieldDescriptor, new Integer((Byte) val));
334+
} else if (val instanceof Short) {
335+
protoMsg.addRepeatedField(fieldDescriptor, new Integer((Short) val));
336+
} else if (val instanceof Integer) {
337+
protoMsg.addRepeatedField(fieldDescriptor, new Integer((Integer) val));
338+
} else {
339+
throw new IllegalArgumentException(
340+
"JSONObject does not have a int32 field at "
341+
+ currentScope
342+
+ "["
343+
+ i
344+
+ "]"
345+
+ ".");
346+
}
347+
} catch (JSONException e) {
348+
throw new IllegalArgumentException(
349+
"JSONObject does not have a int32 field at " + currentScope + "[" + i + "]" + ".");
350+
}
351+
}
352+
break;
288353
case STRING:
289354
for (int i = 0; i < jsonArray.length(); i++) {
290355
try {
291-
protoMsg.addRepeatedField(field, jsonArray.getString(i));
356+
protoMsg.addRepeatedField(fieldDescriptor, jsonArray.getString(i));
292357
} catch (JSONException e) {
293358
throw new IllegalArgumentException(
294359
"JSONObject does not have a string field at " + currentScope + "[" + i + "]" + ".");
@@ -300,9 +365,9 @@ private static void fillRepeatedField(
300365
try {
301366
java.lang.Object val = jsonArray.get(i);
302367
if (val instanceof Double) {
303-
protoMsg.addRepeatedField(field, new Double((double) val));
368+
protoMsg.addRepeatedField(fieldDescriptor, new Double((double) val));
304369
} else if (val instanceof Float) {
305-
protoMsg.addRepeatedField(field, new Double((float) val));
370+
protoMsg.addRepeatedField(fieldDescriptor, new Double((float) val));
306371
} else {
307372
throw new IllegalArgumentException(
308373
"JSONObject does not have a double field at "
@@ -321,11 +386,11 @@ private static void fillRepeatedField(
321386
case MESSAGE:
322387
for (int i = 0; i < jsonArray.length(); i++) {
323388
try {
324-
Message.Builder message = protoMsg.newBuilderForField(field);
389+
Message.Builder message = protoMsg.newBuilderForField(fieldDescriptor);
325390
protoMsg.addRepeatedField(
326-
field,
391+
fieldDescriptor,
327392
convertJsonToProtoMessageImpl(
328-
field.getMessageType(),
393+
fieldDescriptor.getMessageType(),
329394
jsonArray.getJSONObject(i),
330395
currentScope,
331396
false,

0 commit comments

Comments
 (0)