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

nullable declaration is not working correctly for reference types #214

Closed
ahokkonen opened this issue May 5, 2021 · 19 comments
Closed

nullable declaration is not working correctly for reference types #214

ahokkonen opened this issue May 5, 2021 · 19 comments
Assignees
Labels
help wanted Extra attention is needed this-release Scheduled to be implemented for this release in development

Comments

@ahokkonen
Copy link
Contributor

ahokkonen commented May 5, 2021

Seems like nullable field declaration for reference types is not valid and during code generation property stays as non-nullable despite "nullable": true.

Example from icarMetaType.json:

    "created": {
      "$ref": "../types/icarDateTimeType.json",
      "nullable": true
    },

non-nullable date type gets generated as a result.
Not sure if this is a generator issue or invalid OpenAPI markup for these kind on declaration. It look like valid way of defining nullable reference type would be:

OpenAPI 3.0

"created": {
    "nullable": true,
    "allOf": [
        { "$ref": "../types/icarDateTimeType.json" }
    ]
}

OpenAPI 3.1

"created": {
    "anyOf": [
        { "type": "null" },
        { "$ref": "../types/icarDateTimeType.json" }
    ]
}

I haven't tested that myself yet.

@ahokkonen ahokkonen added the help wanted Extra attention is needed label May 5, 2021
@AndreasSchultzGEA
Copy link
Collaborator

AndreasSchultzGEA commented May 6, 2021

Our generating-process seems to cover this correctly:
@ApiModelProperty(required = true, value = "udt:DateTimeType | A particular point in the progression of time together with relevant supplementary information.") @NotNull @Valid public OffsetDateTime getModified() { return modified; }

vs
@ApiModelProperty(value = "udt:DateTimeType | A particular point in the progression of time together with relevant supplementary information.") @Valid public OffsetDateTime getCreated() { return created; }

@ahokkonen
Copy link
Contributor Author

Our generating-process seems to cover this correctly:
@ApiModelProperty(required = true, value = "udt:DateTimeType | A particular point in the progression of time together with relevant supplementary information.") @NotNull @Valid public OffsetDateTime getModified() { return modified; }

vs
@ApiModelProperty(value = "udt:DateTimeType | A particular point in the progression of time together with relevant supplementary information.") @Valid public OffsetDateTime getCreated() { return created; }

Are you using openapi-generator tools for this? Maybe this is an issue of .NET code generation...

@AndreasSchultzGEA
Copy link
Collaborator

AndreasSchultzGEA commented May 7, 2021 via email

@ahokkonen
Copy link
Contributor Author

ahokkonen commented Aug 12, 2021

With some research, things around Nullable types gets even more complicated. With defining complex reference type having just a "nullable: true" is actually not right (and not spec compliant on OAS3.0), but somehow supported by various generators :)

Here is a nice issue to read on "openapi-generator" project.

Had no luck with csharp generator producing proper nullable types only with "nullable: true", but when changed code to use "allOf" (I guess "oneOf" or "anyOf" will also do the trick) from my first message everything went smoothly through.

"created": {
    "nullable": true,
    "allOf": [
        { "$ref": "../types/icarDateTimeType.json" }
    ]
}

In some feedbacks this is also considered as a workaround and not a "fully official" OAS3.0 spec.

@cookeac
Copy link
Collaborator

cookeac commented Aug 12, 2021

Agreed, looking back through the JSON Schema specs, "nullable": true is ignored by JSON Schema, and we had started using it purely to support OpenAPI, based on assumptions from the YAML version of OpenAPI.
JSON Schema's solution is allOf for reference types as you have described, or for simple types:

"type" : [ "string", "null" ]

Of course, different versions of OpenAPI spec support different subsets of the JSON Schema spec, hence our confusion.

@ahokkonen
Copy link
Contributor Author

ahokkonen commented Aug 25, 2021

Any opinion on if we should fix a declarations for those properties which meant to be nullable?

@AndreasSchultzGEA
Copy link
Collaborator

AndreasSchultzGEA commented Aug 26, 2021

Has any one from the Java-users verified the result of OpenAPI 3.1 if we change the to '"type" : [ "string", "null" ]' and
"created": { "anyOf": [ { "type": "null" }, { "$ref": "../types/icarDateTimeType.json" } ] }
Just to avoid, that C# works, but Java and JavaScript not ...

@alamers
Copy link
Collaborator

alamers commented Sep 9, 2021

I've just did some testing with Java. I specified 'created' date in the 'proper' 3.0 style as Anton proposed. The 'validFrom' (and other fields I left as-is.

Client generation with openapi-generator-cli-4.3.1 and openapi-generator-cli-5.2.0
In both cases, the field private OffsetDateTime created is replaced with JsonNullable<OffsetDateTime> created = JsonNullable.<OffsetDateTime>of(null);

The rationale behind the JsonNullable wrapper is, according to OpenAPITools:

The JsonNullable wrapper shall be used to wrap Java bean fields for which it is important to distinguish between an explicit "null" and the field not being present. A typical usage is when implementing Json Merge Patch where an explicit "null"has the meaning "set this field to null / remove this field" whereas a non-present field has the meaning "don't change the value of this field".

So, it seems that the original implementation leaves out this different interpretations of null. It probably works for most cases though.

Changing to the 'proper' 3.0 style means a compile time breaking change.

@ahokkonen
Copy link
Contributor Author

I've performed my tests with various versions of openapi-generators and unless I had nullable declaration set as suggested for 3.0 (refer to my comment) the compiled result was incorrect. So, unfortunately, with using openapi-generator tool for .net specs needs to be adjusted.

I also has some tries with autorest, but seems like I need to look a bit deeper into the configuration docs :) With default setting compiled result was produced only for url APIs and not models/types. Maybe I need to merge the schemes first into one so autorest will pick all the defs from single file...

@ahokkonen
Copy link
Contributor Author

I've just did some testing with Java. I specified 'created' date in the 'proper' 3.0 style as Anton proposed. The 'validFrom' (and other fields I left as-is.

Client generation with openapi-generator-cli-4.3.1 and openapi-generator-cli-5.2.0
In both cases, the field private OffsetDateTime created is replaced with JsonNullable<OffsetDateTime> created = JsonNullable.<OffsetDateTime>of(null);

The rationale behind the JsonNullable wrapper is, according to OpenAPITools:

The JsonNullable wrapper shall be used to wrap Java bean fields for which it is important to distinguish between an explicit "null" and the field not being present. A typical usage is when implementing Json Merge Patch where an explicit "null"has the meaning "set this field to null / remove this field" whereas a non-present field has the meaning "don't change the value of this field".

So, it seems that the original implementation leaves out this different interpretations of null. It probably works for most cases though.

Changing to the 'proper' 3.0 style means a compile time breaking change.

btw, @alamers, what if you try to switch off the "openApiNullable" in configuration and then compile? Looks like Jackson library is used by default for nullable as stated in openapi-generator Java docs. This setting I assume leads to that strange declaration in a compiled code.

@alamers
Copy link
Collaborator

alamers commented Sep 10, 2021

I tested with that openApiNullable parameter and for 5.2.0 that generates the same code as before. For 4.3.1, the switch doesn't seem to do anything.

So, the proper '3.0' style works also for Java: either you get the JsonNullable wrapper (with the rationale as stated above), or you explicitly switch that off to get the same code back as we have now. That is, if you use the 5.2.0 generator.

@ahokkonen
Copy link
Contributor Author

ahokkonen commented Sep 10, 2021

I tested with that openApiNullable parameter and for 5.2.0 that generates the same code as before. For 4.3.1, the switch doesn't seem to do anything.

So, the proper '3.0' style works also for Java: either you get the JsonNullable wrapper (with the rationale as stated above), or you explicitly switch that off to get the same code back as we have now. That is, if you use the 5.2.0 generator.

Ok, maybe for the older version that switch wasn't just supported. So we can state that using latest version of the generator and proper OpenAPI 3.0 nullable declaration we'll get correct results in both languages (c# and java). Was there still something wrong for TypeScript? @AndreasSchultzGEA

@AndreasSchultzGEA
Copy link
Collaborator

AndreasSchultzGEA commented Sep 10, 2021 via email

cookeac added a commit that referenced this issue Sep 15, 2021
Reference known issue #214.
Also updated version number information in the Readme.
@ahokkonen
Copy link
Contributor Author

back to that issue - should we work on correcting nullable declarations in all schemata for the next minor release (1.3?) and then provide a clear and proper descriptions on code generation (at least Java, .NET, TS)?

I can assign that task on myself and verify for .NET gens, but then I'll need an input from the others to make sure we'll get correct output for Java and TS :)

ahokkonen added a commit that referenced this issue Sep 24, 2021
Changes for parturition event with new progeny details
closes #214
@AndreasSchultzGEA
Copy link
Collaborator

AndreasSchultzGEA commented Sep 24, 2021

I configured the Java-Generator for the update from 1.1 to 1.2. Now we use the mvn-generator v5.2.1. And as a hint to @alamers :
<configOptions> <dateLibrary>java8</dateLibrary> <openApiNullable>false</openApiNullable> </configOptions> <templateDirectory>${project.basedir}/openapi-generator-templates</templateDirectory>
and within the template, we exchanged include = JsonTypeInfo.As.EXISTING_PROPERTY by PROPERTY.

The results are:
Within the

  • Java-code the nullable attributes are initialized with null at their declaration. Nothing more, nothing less. And, there are @NotNull-Annotations, etc. for non-null attributes located at their getter.
  • TypeScript-Code there is nothing left in concerns of the non-/nullability. I'll have to check this generator next.

Does anybody have a configuration which contains more?

@ahokkonen
Copy link
Contributor Author

PR with the fix is published, code generation tested for .NET and typescript.

@cookeac cookeac added the this-release Scheduled to be implemented for this release in development label Oct 7, 2021
@ahokkonen
Copy link
Contributor Author

PR is merged and we only need a last Java verification before closing this issue

@AndreasSchultzGEA
Copy link
Collaborator

Java & JS code generation seems to be okay.

@ahokkonen
Copy link
Contributor Author

seems like all is good, closing this tissue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed this-release Scheduled to be implemented for this release in development
Projects
None yet
Development

No branches or pull requests

5 participants