Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
Expand Up @@ -455,11 +455,11 @@
{{#allVars}}
{{^isDiscriminator}}
{{^isNullable}}
{{#vendorExtensions.x-is-reference-type}}
if ({{^required}}{{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}Option.IsSet && {{/required}}{{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}} == null)
throw new ArgumentNullException(nameof({{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}), "Property is required for class {{classname}}.");
{{^required}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: Required non-nullable reference-type properties lose their serialization null guard entirely. The old code checked prop == null for required properties too; now the guard is emitted only inside {{^required}}. NRT is compile-time only, and the generated model exposes public setters (and nulls can come from reflection or null!), so a required property can be null at runtime. Serializing it now silently writes a JSON null (for strings) or throws a confusing NullReferenceException deeper in the write path instead of the previous clear ArgumentNullException. Consider keeping the null check for required properties (it was not the source of the wrong error message being fixed), or otherwise document the deliberate loss of this runtime check.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/csharp/libraries/generichost/JsonConverter.mustache, line 459:

<comment>Required non-nullable reference-type properties lose their serialization null guard entirely. The old code checked `prop == null` for required properties too; now the guard is emitted only inside `{{^required}}`. NRT is compile-time only, and the generated model exposes public setters (and nulls can come from reflection or `null!`), so a required property can be null at runtime. Serializing it now silently writes a JSON null (for strings) or throws a confusing NullReferenceException deeper in the write path instead of the previous clear ArgumentNullException. Consider keeping the null check for required properties (it was not the source of the wrong error message being fixed), or otherwise document the deliberate loss of this runtime check.</comment>

<file context>
@@ -456,9 +456,11 @@
             {{#vendorExtensions.x-is-reference-type}}
-            if ({{^required}}{{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}Option.IsSet && {{/required}}{{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}} == null)
-                throw new ArgumentNullException(nameof({{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}), "Property is required for class {{classname}}.");
+            {{^required}}
+            if ({{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}Option.IsSet && {{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}} == null)
+                throw new JsonException("Cannot write null property {{classname}}.{{name}} to non-nullable JSON property '{{baseName}}'.");
</file context>

if ({{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}}Option.IsSet && {{#lambda.camelcase_sanitize_param}}{{classname}}{{/lambda.camelcase_sanitize_param}}.{{name}} == null)
throw new JsonException("Cannot write null property {{classname}}.{{name}} to non-nullable JSON property '{{baseName}}'.");

{{/vendorExtensions.x-is-reference-type}}
{{/required}}
{{/isNullable}}
{{/isDiscriminator}}
{{/allVars}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ public override void Write(Utf8JsonWriter writer, OneOfNullAndRef oneOfNullAndRe
/// <exception cref="NotImplementedException"></exception>
public void WriteProperties(Utf8JsonWriter writer, OneOfNullAndRef oneOfNullAndRef, JsonSerializerOptions jsonSerializerOptions)
{
if (oneOfNullAndRef.NumberOption.IsSet && oneOfNullAndRef.Number == null)
throw new JsonException("Cannot write null property OneOfNullAndRef.Number to non-nullable JSON property 'number'.");

if (oneOfNullAndRef.NumberOption.IsSet)
{
var numberRawValue = NumberValueConverter.ToJsonValue(oneOfNullAndRef.Number!.Value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ public override void Write(Utf8JsonWriter writer, OneOfNullAndRef2 oneOfNullAndR
/// <exception cref="NotImplementedException"></exception>
public void WriteProperties(Utf8JsonWriter writer, OneOfNullAndRef2 oneOfNullAndRef2, JsonSerializerOptions jsonSerializerOptions)
{
if (oneOfNullAndRef2.NumberOption.IsSet && oneOfNullAndRef2.Number == null)
throw new JsonException("Cannot write null property OneOfNullAndRef2.Number to non-nullable JSON property 'number'.");

if (oneOfNullAndRef2.NumberOption.IsSet)
{
var numberRawValue = NumberValueConverter.ToJsonValue(oneOfNullAndRef2.Number!.Value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ public override void Write(Utf8JsonWriter writer, OneOfNullAndRef3 oneOfNullAndR
/// <exception cref="NotImplementedException"></exception>
public void WriteProperties(Utf8JsonWriter writer, OneOfNullAndRef3 oneOfNullAndRef3, JsonSerializerOptions jsonSerializerOptions)
{
if (oneOfNullAndRef3.NumberOption.IsSet && oneOfNullAndRef3.Number == null)
throw new JsonException("Cannot write null property OneOfNullAndRef3.Number to non-nullable JSON property 'number'.");

if (oneOfNullAndRef3.NumberOption.IsSet)
{
var numberRawValue = NumberValueConverter.ToJsonValue(oneOfNullAndRef3.Number!.Value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ public override void Write(Utf8JsonWriter writer, Parent parent, JsonSerializerO
/// <exception cref="NotImplementedException"></exception>
public void WriteProperties(Utf8JsonWriter writer, Parent parent, JsonSerializerOptions jsonSerializerOptions)
{
if (parent.NumberOption.IsSet && parent.Number == null)
throw new JsonException("Cannot write null property Parent.Number to non-nullable JSON property 'number'.");

if (parent.NumberOption.IsSet)
{
var numberRawValue = NumberValueConverter.ToJsonValue(parent.Number!.Value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ public override void Write(Utf8JsonWriter writer, ParentWithOneOfProperty parent
/// <exception cref="NotImplementedException"></exception>
public void WriteProperties(Utf8JsonWriter writer, ParentWithOneOfProperty parentWithOneOfProperty, JsonSerializerOptions jsonSerializerOptions)
{
if (parentWithOneOfProperty.NumberOption.IsSet && parentWithOneOfProperty.Number == null)
throw new JsonException("Cannot write null property ParentWithOneOfProperty.Number to non-nullable JSON property 'number'.");

if (parentWithOneOfProperty.NumberOption.IsSet)
{
var numberRawValue = NumberValueConverter.ToJsonValue(parentWithOneOfProperty.Number!.Value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public override void Write(Utf8JsonWriter writer, ParentWithPluralOneOfProperty
public void WriteProperties(Utf8JsonWriter writer, ParentWithPluralOneOfProperty parentWithPluralOneOfProperty, JsonSerializerOptions jsonSerializerOptions)
{
if (parentWithPluralOneOfProperty.NumberOption.IsSet && parentWithPluralOneOfProperty.Number == null)
throw new ArgumentNullException(nameof(parentWithPluralOneOfProperty.Number), "Property is required for class ParentWithPluralOneOfProperty.");
throw new JsonException("Cannot write null property ParentWithPluralOneOfProperty.Number to non-nullable JSON property 'number'.");

if (parentWithPluralOneOfProperty.NumberOption.IsSet)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public override void Write(Utf8JsonWriter writer, HelloWorldPostRequest helloWor
public void WriteProperties(Utf8JsonWriter writer, HelloWorldPostRequest helloWorldPostRequest, JsonSerializerOptions jsonSerializerOptions)
{
if (helloWorldPostRequest.MessageOption.IsSet && helloWorldPostRequest.Message == null)
throw new ArgumentNullException(nameof(helloWorldPostRequest.Message), "Property is required for class HelloWorldPostRequest.");
throw new JsonException("Cannot write null property HelloWorldPostRequest.Message to non-nullable JSON property 'message'.");

if (helloWorldPostRequest.MessageOption.IsSet)
writer.WriteString("message", helloWorldPostRequest.Message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public override void Write(Utf8JsonWriter writer, Foo foo, JsonSerializerOptions
public void WriteProperties(Utf8JsonWriter writer, Foo foo, JsonSerializerOptions jsonSerializerOptions)
{
if (foo.BarOption.IsSet && foo.Bar == null)
throw new ArgumentNullException(nameof(foo.Bar), "Property is required for class Foo.");
throw new JsonException("Cannot write null property Foo.Bar to non-nullable JSON property 'bar'.");
Comment thread
devhl-labs marked this conversation as resolved.

if (foo.BarOption.IsSet)
writer.WriteString("bar", foo.Bar);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public override void Write(Utf8JsonWriter writer, IconsDefaultResponse iconsDefa
public void WriteProperties(Utf8JsonWriter writer, IconsDefaultResponse iconsDefaultResponse, JsonSerializerOptions jsonSerializerOptions)
{
if (iconsDefaultResponse.StringOption.IsSet && iconsDefaultResponse.String == null)
throw new ArgumentNullException(nameof(iconsDefaultResponse.String), "Property is required for class IconsDefaultResponse.");
throw new JsonException("Cannot write null property IconsDefaultResponse.String to non-nullable JSON property 'string'.");

if (iconsDefaultResponse.StringOption.IsSet)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,15 @@ public override void Write(Utf8JsonWriter writer, Color color, JsonSerializerOpt
/// <exception cref="NotImplementedException"></exception>
public void WriteProperties(Utf8JsonWriter writer, Color color, JsonSerializerOptions jsonSerializerOptions)
{
if (color.BOption.IsSet && color.B == null)
throw new JsonException("Cannot write null property Color.B to non-nullable JSON property 'b'.");

if (color.GOption.IsSet && color.G == null)
throw new JsonException("Cannot write null property Color.G to non-nullable JSON property 'g'.");

if (color.ROption.IsSet && color.R == null)
throw new JsonException("Cannot write null property Color.R to non-nullable JSON property 'r'.");

if (color.BOption.IsSet)
writer.WriteNumber("b", color.BOption.Value!.Value);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ public override void Write(Utf8JsonWriter writer, NullTypeDirect nullTypeDirect,
/// <exception cref="NotImplementedException"></exception>
public void WriteProperties(Utf8JsonWriter writer, NullTypeDirect nullTypeDirect, JsonSerializerOptions jsonSerializerOptions)
{
if (nullTypeDirect.IdOption.IsSet && nullTypeDirect.Id == null)
throw new JsonException("Cannot write null property NullTypeDirect.Id to non-nullable JSON property 'id'.");

if (nullTypeDirect.AlwaysNullOption.IsSet)
if (nullTypeDirect.AlwaysNullOption.Value != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ public override void Write(Utf8JsonWriter writer, Shape shape, JsonSerializerOpt
/// <exception cref="NotImplementedException"></exception>
public void WriteProperties(Utf8JsonWriter writer, Shape shape, JsonSerializerOptions jsonSerializerOptions)
{
if (shape.ShapeType == null)
throw new ArgumentNullException(nameof(shape.ShapeType), "Property is required for class Shape.");
if (shape.AreaOption.IsSet && shape.Area == null)
throw new JsonException("Cannot write null property Shape.Area to non-nullable JSON property 'area'.");

writer.WriteString("shapeType", shape.ShapeType);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ public override void Write(Utf8JsonWriter writer, ShapeOrNull shapeOrNull, JsonS
/// <exception cref="NotImplementedException"></exception>
public void WriteProperties(Utf8JsonWriter writer, ShapeOrNull shapeOrNull, JsonSerializerOptions jsonSerializerOptions)
{
if (shapeOrNull.ShapeType == null)
throw new ArgumentNullException(nameof(shapeOrNull.ShapeType), "Property is required for class ShapeOrNull.");
if (shapeOrNull.AreaOption.IsSet && shapeOrNull.Area == null)
throw new JsonException("Cannot write null property ShapeOrNull.Area to non-nullable JSON property 'area'.");

writer.WriteString("shapeType", shapeOrNull.ShapeType);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,6 @@ public override void Write(Utf8JsonWriter writer, Widget widget, JsonSerializerO
/// <exception cref="NotImplementedException"></exception>
public void WriteProperties(Utf8JsonWriter writer, Widget widget, JsonSerializerOptions jsonSerializerOptions)
{
if (widget.Name == null)
throw new ArgumentNullException(nameof(widget.Name), "Property is required for class Widget.");

writer.WriteNumber("id", widget.Id);

writer.WriteString("name", widget.Name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public override void Write(Utf8JsonWriter writer, TestObject testObject, JsonSer
public void WriteProperties(Utf8JsonWriter writer, TestObject testObject, JsonSerializerOptions jsonSerializerOptions)
{
if (testObject.NameOption.IsSet && testObject.Name == null)
throw new ArgumentNullException(nameof(testObject.Name), "Property is required for class TestObject.");
throw new JsonException("Cannot write null property TestObject.Name to non-nullable JSON property 'name'.");

if (testObject.NameOption.IsSet)
writer.WriteString("name", testObject.Name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public override void Write(Utf8JsonWriter writer, Activity activity, JsonSeriali
public void WriteProperties(Utf8JsonWriter writer, Activity activity, JsonSerializerOptions jsonSerializerOptions)
{
if (activity.ActivityOutputsOption.IsSet && activity.ActivityOutputs == null)
throw new ArgumentNullException(nameof(activity.ActivityOutputs), "Property is required for class Activity.");
throw new JsonException("Cannot write null property Activity.ActivityOutputs to non-nullable JSON property 'activity_outputs'.");

if (activity.ActivityOutputsOption.IsSet)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,10 @@ public override void Write(Utf8JsonWriter writer, ActivityOutputElementRepresent
public void WriteProperties(Utf8JsonWriter writer, ActivityOutputElementRepresentation activityOutputElementRepresentation, JsonSerializerOptions jsonSerializerOptions)
{
if (activityOutputElementRepresentation.Prop1Option.IsSet && activityOutputElementRepresentation.Prop1 == null)
throw new ArgumentNullException(nameof(activityOutputElementRepresentation.Prop1), "Property is required for class ActivityOutputElementRepresentation.");
throw new JsonException("Cannot write null property ActivityOutputElementRepresentation.Prop1 to non-nullable JSON property 'prop1'.");

if (activityOutputElementRepresentation.Prop2Option.IsSet && activityOutputElementRepresentation.Prop2 == null)
throw new ArgumentNullException(nameof(activityOutputElementRepresentation.Prop2), "Property is required for class ActivityOutputElementRepresentation.");
throw new JsonException("Cannot write null property ActivityOutputElementRepresentation.Prop2 to non-nullable JSON property 'prop2'.");

if (activityOutputElementRepresentation.Prop1Option.IsSet)
writer.WriteString("prop1", activityOutputElementRepresentation.Prop1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,25 +328,25 @@ public override void Write(Utf8JsonWriter writer, AdditionalPropertiesClass addi
public void WriteProperties(Utf8JsonWriter writer, AdditionalPropertiesClass additionalPropertiesClass, JsonSerializerOptions jsonSerializerOptions)
{
if (additionalPropertiesClass.EmptyMapOption.IsSet && additionalPropertiesClass.EmptyMap == null)
throw new ArgumentNullException(nameof(additionalPropertiesClass.EmptyMap), "Property is required for class AdditionalPropertiesClass.");
throw new JsonException("Cannot write null property AdditionalPropertiesClass.EmptyMap to non-nullable JSON property 'empty_map'.");

if (additionalPropertiesClass.MapOfMapPropertyOption.IsSet && additionalPropertiesClass.MapOfMapProperty == null)
throw new ArgumentNullException(nameof(additionalPropertiesClass.MapOfMapProperty), "Property is required for class AdditionalPropertiesClass.");
throw new JsonException("Cannot write null property AdditionalPropertiesClass.MapOfMapProperty to non-nullable JSON property 'map_of_map_property'.");

if (additionalPropertiesClass.MapPropertyOption.IsSet && additionalPropertiesClass.MapProperty == null)
throw new ArgumentNullException(nameof(additionalPropertiesClass.MapProperty), "Property is required for class AdditionalPropertiesClass.");
throw new JsonException("Cannot write null property AdditionalPropertiesClass.MapProperty to non-nullable JSON property 'map_property'.");

if (additionalPropertiesClass.MapWithUndeclaredPropertiesAnytype1Option.IsSet && additionalPropertiesClass.MapWithUndeclaredPropertiesAnytype1 == null)
throw new ArgumentNullException(nameof(additionalPropertiesClass.MapWithUndeclaredPropertiesAnytype1), "Property is required for class AdditionalPropertiesClass.");
throw new JsonException("Cannot write null property AdditionalPropertiesClass.MapWithUndeclaredPropertiesAnytype1 to non-nullable JSON property 'map_with_undeclared_properties_anytype_1'.");

if (additionalPropertiesClass.MapWithUndeclaredPropertiesAnytype2Option.IsSet && additionalPropertiesClass.MapWithUndeclaredPropertiesAnytype2 == null)
throw new ArgumentNullException(nameof(additionalPropertiesClass.MapWithUndeclaredPropertiesAnytype2), "Property is required for class AdditionalPropertiesClass.");
throw new JsonException("Cannot write null property AdditionalPropertiesClass.MapWithUndeclaredPropertiesAnytype2 to non-nullable JSON property 'map_with_undeclared_properties_anytype_2'.");

if (additionalPropertiesClass.MapWithUndeclaredPropertiesAnytype3Option.IsSet && additionalPropertiesClass.MapWithUndeclaredPropertiesAnytype3 == null)
throw new ArgumentNullException(nameof(additionalPropertiesClass.MapWithUndeclaredPropertiesAnytype3), "Property is required for class AdditionalPropertiesClass.");
throw new JsonException("Cannot write null property AdditionalPropertiesClass.MapWithUndeclaredPropertiesAnytype3 to non-nullable JSON property 'map_with_undeclared_properties_anytype_3'.");

if (additionalPropertiesClass.MapWithUndeclaredPropertiesStringOption.IsSet && additionalPropertiesClass.MapWithUndeclaredPropertiesString == null)
throw new ArgumentNullException(nameof(additionalPropertiesClass.MapWithUndeclaredPropertiesString), "Property is required for class AdditionalPropertiesClass.");
throw new JsonException("Cannot write null property AdditionalPropertiesClass.MapWithUndeclaredPropertiesString to non-nullable JSON property 'map_with_undeclared_properties_string'.");

if (additionalPropertiesClass.Anytype1Option.IsSet)
if (additionalPropertiesClass.Anytype1Option.Value != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ public override void Write(Utf8JsonWriter writer, Animal animal, JsonSerializerO
public void WriteProperties(Utf8JsonWriter writer, Animal animal, JsonSerializerOptions jsonSerializerOptions)
{
if (animal.ColorOption.IsSet && animal.Color == null)
throw new ArgumentNullException(nameof(animal.Color), "Property is required for class Animal.");
throw new JsonException("Cannot write null property Animal.Color to non-nullable JSON property 'color'.");

writer.WriteString("className", animal.ClassName);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,14 @@ public override void Write(Utf8JsonWriter writer, ApiResponse apiResponse, JsonS
/// <exception cref="NotImplementedException"></exception>
public void WriteProperties(Utf8JsonWriter writer, ApiResponse apiResponse, JsonSerializerOptions jsonSerializerOptions)
{
if (apiResponse.CodeOption.IsSet && apiResponse.Code == null)
throw new JsonException("Cannot write null property ApiResponse.Code to non-nullable JSON property 'code'.");

if (apiResponse.MessageOption.IsSet && apiResponse.Message == null)
throw new ArgumentNullException(nameof(apiResponse.Message), "Property is required for class ApiResponse.");
throw new JsonException("Cannot write null property ApiResponse.Message to non-nullable JSON property 'message'.");
Comment thread
devhl-labs marked this conversation as resolved.

if (apiResponse.TypeOption.IsSet && apiResponse.Type == null)
throw new ArgumentNullException(nameof(apiResponse.Type), "Property is required for class ApiResponse.");
throw new JsonException("Cannot write null property ApiResponse.Type to non-nullable JSON property 'type'.");

if (apiResponse.CodeOption.IsSet)
writer.WriteNumber("code", apiResponse.CodeOption.Value!.Value);
Expand Down
Loading
Loading