Skip to content
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

[BUG][go-experimental] Explicit nulls support is broken #5278

Closed
3 of 6 tasks
bkabrda opened this issue Feb 11, 2020 · 3 comments
Closed
3 of 6 tasks

[BUG][go-experimental] Explicit nulls support is broken #5278

bkabrda opened this issue Feb 11, 2020 · 3 comments

Comments

@bkabrda
Copy link
Contributor

bkabrda commented Feb 11, 2020

Bug Report Checklist

  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator (example)?
  • What's the version of OpenAPI Generator used?
  • Have you search for related issues/PRs?
  • What's the actual output vs expected output?
  • [Optional] Bounty to sponsor the fix (example)
Description

The current support for explicit nulls, as modified in PR #3989 by @shaxbee (and approved by myself) is broken. I'm opening this issue to discuss the best approach to fix it - I'm ok with implementing the solution for it.

For any given nullable and not required field, we currently generate code like:

type V struct {
    A *NullableInt32 `json:"a,omitempty"`
}

The problem right now is that when an API sends back an explicit-null field, it's not deserialized properly as an explicit null. This is because for a pointer field, Go unmarshalling machinery doesn't even invoke the custom unmarshall method, it basically considers explicit null to be the same as the field not being present at all.

So there are 2 options:

  • Create custom unmarshaller for V
  • Don't make A a pointer

Following the reasoning in #3989 about not overloading marshal/unmarshal for these potentially large structures, let's try going with not making A a pointer, hence getting:

type V struct {
    A NullableInt32 `json:"a,omitempty"`
}

This would make deserialization work, as the custom unmarshaller for A would always run, but there's another problem - the custom marshaller for A would always run when serializing. IOW, now there's no way to not serialize this field. But the field is supposed to be optional, so we'll have to create a custom marshaller for V.

So based on the above (if my thinking is correct), we have two options:

  • Leave the field to be a pointer and provide custom unmarshaller
  • Make the field non-pointer and provide custom marshaller

I'm leaning towards the latter, as I think it's easier. I've been playing with how this could work and came up with [1] - this solution changes how the Nullable* structures work a bit, but it also brings it closer to how this is implemented for Java/jackson clients, using [2].

If everyone agrees, I'll send a PR.

Also CCing members of go language committee: @antihax (2017/11) @bvwells (2017/12) @grokify (2018/07) @kemokemo (2018/09) @bkabrda (2019/07)

[1] https://play.golang.org/p/O4AOkyVTikT
[2] https://github.com/OpenAPITools/jackson-databind-nullable/

openapi-generator version

4.3.x branch

OpenAPI declaration file content or url

Use anything that has a field marked with nullable: true and for which the API actually sends an explicit null back.

Command line used for generation
Steps to reproduce
Related issues/PRs

#3989

Suggest a fix

See above

@sebastien-rosset
Copy link
Contributor

One consideration is that to address #4881, #4606, #4559, I think it will be required to write a customer unmarshaler.

@shaxbee
Copy link
Contributor

shaxbee commented Mar 1, 2020 via email

@spacether
Copy link
Contributor

spacether commented May 2, 2022

Looks like this was closed by the above PR
#5414

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants