Skip to content

GODRIVER-2017 Skip empty extJSON objects correctly in Unmarshal #677

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

Merged
merged 3 commits into from
May 28, 2021
Merged

GODRIVER-2017 Skip empty extJSON objects correctly in Unmarshal #677

merged 3 commits into from
May 28, 2021

Conversation

benjirewis
Copy link
Contributor

@benjirewis benjirewis commented May 26, 2021

GODRIVER-2017

Adds a case for empty objects in extJSONValueReader#skipObject(). Adds tests for empty objects in undefined fields for UnmarshalExtJSON.

Empty objects in extended JSON were being skipped without setting ejvr.p.emptyObject back to false. So, a regular object following an empty object, as in

{
   "skip": {},
   "a": {"b", "c"}
}

was being unmarshaled to an empty object even though it wasn't empty (i.e. a unmarshaled to bson.D{}).

@benjirewis benjirewis requested review from iwysiu and matthewdale May 26, 2021 16:10
ejvr.p.advanceState()
}
depth--
return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to return or continue? what happens if we need to skip something with a nested empty document, something like
"UndefinedField": {"empty": {}, "key": 1}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

continue is more correct, but it actually doesn't change the parsing behavior 💭

In that example, the parser will realize UndefinedField is undefined in the destination struct and will call skipObject on the value of UndefinedField: {"empty": {}, "key": 1}. Since that value is not an empty object itself, the emptyObject flag will not have been set, so the logic in this block won't actually apply. That said, continueing is more accurate than returning in my opinion, since the depth variable will be set back to 0 and return anyway.

Also updated the existing test for "empty embedded document" to be the case you described above.

@benjirewis benjirewis requested a review from iwysiu May 27, 2021 17:29
@vfedosieiev
Copy link

hi guys, any update when this will be merged?

Copy link
Collaborator

@matthewdale matthewdale left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, with a suggestion to extend the comment to describe a little more about the expected state(s) of the parser.

// If object is empty, raise depth and continue. If there is a comma, there are
// remaining fields, emptyObject must be set back to false, and comma must be
// skipped with advanceState().
if ejvr.p.emptyObject {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: Add a description of the expected state of the parser/buffer to help people reading the code understand why we need different behavior for when ejvr.p.emptyObject is true.

E.g.

When emptyObject is true, the parser has already read both the opening and closing brackets of an empty object ("{}"), so the next valid token will be part of the parent document, not part of the nested document.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea! Added a description of the state of the parser (the exact text you gave).

@benjirewis benjirewis merged commit 0cd0d3c into mongodb:master May 28, 2021
@benjirewis benjirewis deleted the skipEmptyObject.2017 branch May 28, 2021 19:58
tsedgwick pushed a commit to mongodb-forks/mongo-go-driver that referenced this pull request Jun 1, 2021
@A40in
Copy link

A40in commented Sep 17, 2021

Hi!
the function does not handle the state jpsInvalidState.

func (ejvr *extJSONValueReader) skipObject() {
	// read entire object until depth returns to 0 (last ending } or ] seen)
	depth := 1
	for depth > 0 {
		ejvr.p.advanceState()    // loop if returned jpsInvalidState

Next test loops in skipObject() function

var WrongJson string = `{
"undefined_field":{
	"u": [
		"q":{
		}
	]
	}
}`

type V struct {
	Cmd bson.D
}

func TestBson1(t *testing.T) {
	var req V
	err := bson.UnmarshalExtJSON([]byte(WrongJson), false, &req)
	t.Log(req, err)
}

faem pushed a commit to kubedb/mongo-go-driver that referenced this pull request Mar 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants