-
Notifications
You must be signed in to change notification settings - Fork 132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
json: Ignore unknown enum values #170
Conversation
Thanks for this PR, @whs. It looks like the PR you mentioned has not landed. This PR however has. The difference between those PRs is that the latter one ignores unrecognized values instead of setting the field to |
I suppose returning |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some comments on how fields with unrecognized values could be skipped without rewriting the entire class. It's not pretty, but I'd still prefer.
it('return -1 if unknown value was found, but ignoreUnknownFields was set', function () { | ||
const reader = new ReflectionJsonReader({typeName: '.test.Message', fields: []}); | ||
expect(reader.enum([".spec.SimpleEnum", SimpleEnum], 'test', '', true)).toEqual(0); | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the string value is not recognized, nothing should be done here.
@@ -196,7 +196,7 @@ export class ReflectionJsonReader { | |||
/** | |||
* google.protobuf.NullValue accepts only JSON `null`. | |||
*/ | |||
enum(type: EnumInfo, json: unknown, fieldName: string): UnknownEnum { | |||
enum(type: EnumInfo, json: unknown, fieldName: string, ignoreUnknownFields = false): UnknownEnum { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you omit the default argument? ignoreUnknownStringValue: boolean
is enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For unrecognized string values, we should return false
. The return type of the method can be UnknownEnum | false
. The method needs a doc explaining that false
means an unknown string value was encountered.
case "enum": | ||
val = this.enum(field.V.T(), jsonObjValue, field.name); | ||
val = this.enum(field.V.T(), jsonObjValue, field.name, options.ignoreUnknownFields); | ||
break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, the existing code isn't suited well to skipping fields here. We'll have to resort to labels 🙄
case "enum":
val = this.enum(field.V.T(), jsonObjValue, field.name, options.ignoreUnknownFields);
if (val === false)
break map_entries;
break;
And further above:
// read entries
map_entries:
for (const [jsonObjKey, jsonObjValue] of Object.entries(jsonValue)) {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be continue
instead of break? (eg. {key1: "INVALID_ENUM", key2: "VALID_ENUM"}
would break
skip the second key?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, you're right, let's not break the entire loop!
@@ -154,7 +154,7 @@ export class ReflectionJsonReader { | |||
break; | |||
|
|||
case "enum": | |||
val = this.enum(field.T(), jsonItem, field.name); | |||
val = this.enum(field.T(), jsonItem, field.name, options.ignoreUnknownFields); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as for maps, we'll need a label array_entries
and break that here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For array if we continue
I suppose we would cause the output length to be less than the input length?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, same for map. That's what JsonFormat.java does.
@@ -180,7 +180,7 @@ export class ReflectionJsonReader { | |||
break; | |||
|
|||
case "enum": | |||
target[localName] = this.enum(field.T(), jsonValue, field.name); | |||
target[localName] = this.enum(field.T(), jsonValue, field.name, options.ignoreUnknownFields); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one will work just by not setting the value:
case "enum":
let val = this.enum(field.T(), jsonValue, field.name, options.ignoreUnknownFields);
if (val === false)
break;
target[localName] = val;
break;
Thanks, just saw that while reviewing 😅 . Whether we return |
Updated the PR to skip fields - also added additional tests on read() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you 🙏
Released in v2.0.7 |
Would you mind labeling this PR with |
While parsing proto from JSON, any unknown enum values would result in assertion error. This would cause backward compatibility issue.
I looked on how other implementations are doing it and found that the protobuf team has decided that ignoringUnknownFields not ignoring missing enum values is a bug. The Java implementation now returns 0 if
ignoringUnknownFields
is set.