Skip to content

Commit

Permalink
Add customizable number types in code generation
Browse files Browse the repository at this point in the history
This commit introduces an update enabling the customization of number types during code generation.

It introduces settings to customize the .NET type of number, float, double, and decimal data types during code generation in 'CSharpGeneratorSettings.cs' and updates 'CSharpTypeResolver.cs' to use these settings.

This change allows better user control over how the number types get translated, making the code generation more versatile. Unit tests for different scenarios are included in the new 'NumberTests.cs'.
  • Loading branch information
Jimmy committed Nov 27, 2023
1 parent 63ee615 commit 0828652
Show file tree
Hide file tree
Showing 3 changed files with 308 additions and 20 deletions.
263 changes: 263 additions & 0 deletions src/NJsonSchema.CodeGeneration.CSharp.Tests/NumberTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
using System.Threading.Tasks;
using NJsonSchema.CodeGeneration.CSharp;
using Xunit;

namespace NJsonSchema.CodeGeneration.Tests.CSharp;

public class NumberTests
{
[Fact]
public async Task When_number_has_no_format_then_default_is_generated()
{
//// Arrange
var json =
@"{
""type"": ""object"",
""properties"": {
""amount"" : {
""type"":""number""
}
}
}";
var schema = await JsonSchema.FromJsonAsync(json);
var generator = new CSharpGenerator(schema);

//// Act
var code = generator.GenerateFile("MyClass");

//// Assert
Assert.Contains("public double Amount", code);
}

[Fact]
public async Task When_number_has_decimal_format_then_decimal_is_generated()
{
//// Arrange
var json =
@"{
""type"": ""object"",
""properties"": {
""amount"" : {
""type"":""number"",
""format"": ""decimal""
}
}
}";
var schema = await JsonSchema.FromJsonAsync(json);
var generator = new CSharpGenerator(schema);

//// Act
var code = generator.GenerateFile("MyClass");

//// Assert
Assert.Contains("public decimal Amount", code);
}

[Fact]
public async Task When_number_has_double_format_then_double_is_generated()
{
//// Arrange
var json =
@"{
""type"": ""object"",
""properties"": {
""amount"" : {
""type"":""number"",
""format"": ""double""
}
}
}";
var schema = await JsonSchema.FromJsonAsync(json);
var generator = new CSharpGenerator(schema);

//// Act
var code = generator.GenerateFile("MyClass");

//// Assert
Assert.Contains("public double Amount", code);
}

[Fact]
public async Task When_number_has_float_format_then_float_is_generated()
{
//// Arrange
var json =
@"{
""type"": ""object"",
""properties"": {
""amount"" : {
""type"":""number"",
""format"": ""float""
}
}
}";
var schema = await JsonSchema.FromJsonAsync(json);
var generator = new CSharpGenerator(schema);

//// Act
var code = generator.GenerateFile("MyClass");

//// Assert
Assert.Contains("public float Amount", code);
}

[Fact]
public async Task When_number_type_setting_is_defined_then_setting_type_is_generated()
{
//// Arrange
var json =
@"{
""type"": ""object"",
""properties"": {
""amount"" : {
""type"":""number""
}
}
}";
var schema = await JsonSchema.FromJsonAsync(json);
var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings
{
NumberType = "customNumberType"
});

//// Act
var code = generator.GenerateFile("MyClass");

//// Assert
Assert.Contains("public customNumberType Amount", code);
}

[Fact]
public async Task When_number_type_setting_is_whitespace_then_double_is_generated()
{
//// Arrange
var json =
@"{
""type"": ""object"",
""properties"": {
""amount"" : {
""type"":""number""
}
}
}";
var schema = await JsonSchema.FromJsonAsync(json);
var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings
{
NumberType = " \t\n"
});

//// Act
var code = generator.GenerateFile("MyClass");

//// Assert
Assert.Contains("public double Amount", code);
}

[Fact]
public async Task When_number_type_setting_is_null_then_double_is_generated()
{
//// Arrange
var json =
@"{
""type"": ""object"",
""properties"": {
""amount"" : {
""type"":""number"",
""nullable"": true
}
}
}";
var schema = await JsonSchema.FromJsonAsync(json);
var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings
{
NumberType = null!
});

//// Act
var code = generator.GenerateFile("MyClass");

//// Assert
Assert.Contains("public double? Amount", code);
}

[Fact]
public async Task When_number_float_type_setting_is_defined_then_setting_type_is_generated()
{
//// Arrange
var json =
@"{
""type"": ""object"",
""properties"": {
""amount"" : {
""type"":""number"",
""format"":""float"",
}
}
}";
var schema = await JsonSchema.FromJsonAsync(json);
var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings
{
NumberFloatType = "customFloatType"
});

//// Act
var code = generator.GenerateFile("MyClass");

//// Assert
Assert.Contains("public customFloatType Amount", code);
}

[Fact]
public async Task When_number_double_type_setting_is_defined_then_setting_type_is_generated()
{
//// Arrange
var json =
@"{
""type"": ""object"",
""properties"": {
""amount"" : {
""type"":""number"",
""format"":""double"",
}
}
}";
var schema = await JsonSchema.FromJsonAsync(json);
var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings
{
NumberDoubleType = "customDoubleType"
});

//// Act
var code = generator.GenerateFile("MyClass");

//// Assert
Assert.Contains("public customDoubleType Amount", code);
}

[Fact]
public async Task When_number_decimal_type_setting_is_defined_then_setting_type_is_generated()
{
//// Arrange
var json =
@"{
""type"": ""object"",
""properties"": {
""amount"" : {
""type"":""number"",
""format"":""decimal"",
}
}
}";
var schema = await JsonSchema.FromJsonAsync(json);
var generator = new CSharpGenerator(schema, new CSharpGeneratorSettings
{
NumberDecimalType = "customDecimalType"
});

//// Act
var code = generator.GenerateFile("MyClass");

//// Assert
Assert.Contains("public customDecimalType Amount", code);
}
}
23 changes: 20 additions & 3 deletions src/NJsonSchema.CodeGeneration.CSharp/CSharpGeneratorSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ public CSharpGeneratorSettings()
DateTimeType = "System.DateTimeOffset";
TimeType = "System.TimeSpan";
TimeSpanType = "System.TimeSpan";


NumberType = "double";
NumberFloatType = "float";
NumberDoubleType = "double";
NumberDecimalType = "decimal";

ArrayType = "System.Collections.Generic.ICollection";
ArrayInstanceType = "System.Collections.ObjectModel.Collection";
ArrayBaseType = "System.Collections.ObjectModel.Collection";
Expand Down Expand Up @@ -78,7 +83,19 @@ public CSharpGeneratorSettings()

/// <summary>Gets or sets the time span .NET type (default: 'TimeSpan').</summary>
public string TimeSpanType { get; set; }


/// <summary>Gets or sets the number .NET type (default: "double").</summary>
public string NumberType { get; set; }

/// <summary>Gets or sets the number with double format .NET type (default: "double").</summary>
public string NumberDoubleType { get; set; }

/// <summary>Gets or sets the number with float format .NET type (default: "float").</summary>
public string NumberFloatType { get; set; }

/// <summary>Gets or sets the number with decimal format .NET type (default: "decimal").</summary>
public string NumberDecimalType { get; set; }

/// <summary>Gets or sets the generic array .NET type (default: 'ICollection').</summary>
public string ArrayType { get; set; }

Expand All @@ -96,7 +113,7 @@ public CSharpGeneratorSettings()

/// <summary>Gets or sets the generic dictionary .NET type which is used as base class (default: 'Dictionary').</summary>
public string DictionaryBaseType { get; set; }

/// <summary>Gets or sets the CSharp class style (default: 'Poco').</summary>
public CSharpClassStyle ClassStyle { get; set; }

Expand Down
42 changes: 25 additions & 17 deletions src/NJsonSchema.CodeGeneration.CSharp/CSharpTypeResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
// <author>Rico Suter, mail@rsuter.com</author>
//-----------------------------------------------------------------------

using NJsonSchema.Annotations;
using System;
using System.Linq;

Expand Down Expand Up @@ -91,9 +90,9 @@ public string Resolve(JsonSchema schema, bool isNullable, string? typeNameHint,
var type = schema.ActualTypeSchema.Type;
if (type == JsonObjectType.None && schema.ActualTypeSchema.IsEnumeration)
{
type = schema.ActualTypeSchema.Enumeration.All(v => v is int) ?
JsonObjectType.Integer :
JsonObjectType.String;
type = schema.ActualTypeSchema.Enumeration.All(v => v is int)
? JsonObjectType.Integer
: JsonObjectType.String;
}

if (type.IsNumber())
Expand Down Expand Up @@ -165,22 +164,30 @@ private string ResolveString(JsonSchema schema, bool isNullable, string? typeNam

if (schema.Format == JsonFormatStrings.Date)
{
return isNullable && Settings.DateType?.ToLowerInvariant() != "string" ? Settings.DateType + "?" : Settings.DateType + nullableReferenceType;
return isNullable && Settings.DateType?.ToLowerInvariant() != "string"
? Settings.DateType + "?"
: Settings.DateType + nullableReferenceType;
}

if (schema.Format == JsonFormatStrings.DateTime)
{
return isNullable && Settings.DateTimeType?.ToLowerInvariant() != "string" ? Settings.DateTimeType + "?" : Settings.DateTimeType + nullableReferenceType;
return isNullable && Settings.DateTimeType?.ToLowerInvariant() != "string"
? Settings.DateTimeType + "?"
: Settings.DateTimeType + nullableReferenceType;
}

if (schema.Format == JsonFormatStrings.Time)
{
return isNullable && Settings.TimeType?.ToLowerInvariant() != "string" ? Settings.TimeType + "?" : Settings.TimeType + nullableReferenceType;
return isNullable && Settings.TimeType?.ToLowerInvariant() != "string"
? Settings.TimeType + "?"
: Settings.TimeType + nullableReferenceType;
}

if (schema.Format is JsonFormatStrings.Duration or JsonFormatStrings.TimeSpan)
{
return isNullable && Settings.TimeSpanType?.ToLowerInvariant() != "string" ? Settings.TimeSpanType + "?" : Settings.TimeSpanType + nullableReferenceType;
return isNullable && Settings.TimeSpanType?.ToLowerInvariant() != "string"
? Settings.TimeSpanType + "?"
: Settings.TimeSpanType + nullableReferenceType;
}

if (schema.Format == JsonFormatStrings.Uri)
Expand Down Expand Up @@ -250,19 +257,20 @@ private string ResolveInteger(JsonSchema schema, bool isNullable, string? typeNa
return isNullable ? "int?" : "int";
}

private static string ResolveNumber(JsonSchema schema, bool isNullable)
private string ResolveNumber(JsonSchema schema, bool isNullable)
{
if (schema.Format == JsonFormatStrings.Decimal)
var numberType = schema.Format switch
{
return isNullable ? "decimal?" : "decimal";
}
JsonFormatStrings.Decimal => Settings.NumberDecimalType,
JsonFormatStrings.Double => Settings.NumberDoubleType,
JsonFormatStrings.Float => Settings.NumberFloatType,
_ => Settings.NumberType
};

if (schema.Format == JsonFormatStrings.Float)
{
return isNullable ? "float?" : "float";
}
if (string.IsNullOrWhiteSpace(numberType))
numberType = "double";

return isNullable ? "double?" : "double";
return isNullable ? numberType + "?" : numberType;
}

private string ResolveArrayOrTuple(JsonSchema schema)
Expand Down

0 comments on commit 0828652

Please sign in to comment.