diff --git a/README.md b/README.md
index 6572fbd7..bc3423f0 100644
--- a/README.md
+++ b/README.md
@@ -62,6 +62,7 @@ EXAMPLES:
refitter ./openapi.json --use-polymorphic-serialization
refitter ./openapi.json --collection-format Csv
refitter ./openapi.json --simple-output
+ refitter ./openapi.json --no-inline-json-converters
ARGUMENTS:
[URL or input file] URL or file path to OpenAPI Specification file
@@ -132,6 +133,7 @@ OPTIONS:
payloads with (yet) unknown types are offered by newer versions of an API
See https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism for more information
--disposable Generate refit clients that implement IDisposable
+ --no-inline-json-converters Don't inline JsonConverter attributes for enum properties. When disabled, enum properties will not have [JsonConverter(typeof(JsonStringEnumConverter))] attributes
```
To generate code from an OpenAPI specifications file, run the following:
@@ -304,6 +306,7 @@ The following is an example `.refitter` file
"generateNativeRecords": false,
"generateDefaultValues": true,
"inlineNamedAny": false,
+ "inlineJsonConverters": true, // Optional. Default=true. Set to false to not generate JsonConverter attributes for enum properties
"dateFormat": "yyyy-MM-dd",
"dateTimeFormat": "yyyy-MM-dd",
"excludedTypeNames": [
@@ -390,6 +393,7 @@ The following is an example `.refitter` file
- `generateNativeRecords` - Default is false
- `generateDefaultValues` - Default is true
- `inlineNamedAny` - Default is false
+ - `inlineJsonConverters` - Default is true. When set to false, enum properties will not have `[JsonConverter(typeof(JsonStringEnumConverter))]` attributes
- `dateFormat` - Default is null
- `dateTimeFormat` - Default is null
- `excludedTypeNames` - Default is empty
diff --git a/docs/docfx_project/articles/cli-tool.md b/docs/docfx_project/articles/cli-tool.md
index c12a5b84..ac54cbae 100644
--- a/docs/docfx_project/articles/cli-tool.md
+++ b/docs/docfx_project/articles/cli-tool.md
@@ -41,6 +41,7 @@ EXAMPLES:
refitter ./openapi.json --use-polymorphic-serialization
refitter ./openapi.json --collection-format Csv
refitter ./openapi.json --simple-output
+ refitter ./openapi.json --no-inline-json-converters
ARGUMENTS:
[URL or input file] URL or file path to OpenAPI Specification file
@@ -114,7 +115,9 @@ OPTIONS:
Replaces NSwag JsonInheritanceConverter attributes with System.Text.Json JsonPolymorphicAttributes.
To have the native support of inheritance (de)serialization and fallback to base types when
payloads with (yet) unknown types are offered by newer versions of an API
- See https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism for more information --disposable Generate refit clients that implement IDisposable
+ See https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism for more information
+ --disposable Generate refit clients that implement IDisposable
+ --no-inline-json-converters Don't inline JsonConverter attributes for enum properties. When disabled, enum properties will not have [JsonConverter(typeof(JsonStringEnumConverter))] attributes
```
## CLI Tool Output Example
diff --git a/docs/docfx_project/articles/refitter-file-format.md b/docs/docfx_project/articles/refitter-file-format.md
index dd812415..40c9df13 100644
--- a/docs/docfx_project/articles/refitter-file-format.md
+++ b/docs/docfx_project/articles/refitter-file-format.md
@@ -114,6 +114,7 @@ The following is an example `.refitter` file
"generateNativeRecords": false,
"generateDefaultValues": true,
"inlineNamedAny": false,
+ "inlineJsonConverters": true, // Optional. Default=true. Set to false to not generate JsonConverter attributes for enum properties
"dateFormat": "string",
"dateTimeFormat": "string",
"excludedTypeNames": [
@@ -206,6 +207,7 @@ The following is an example `.refitter` file
- `generateNativeRecords` - Default is false
- `generateDefaultValues` - Default is true
- `inlineNamedAny` - Default is false
+ - `inlineJsonConverters` - Default is true. When set to false, enum properties will not have `[JsonConverter(typeof(JsonStringEnumConverter))]` attributes
- `excludedTypeNames` - Default is empty
- `dateFormat` - Default is null
- `dateTimeFormat` - Default is null
diff --git a/src/Refitter.Core/RefitGenerator.cs b/src/Refitter.Core/RefitGenerator.cs
index 8f8a80f6..7f053feb 100644
--- a/src/Refitter.Core/RefitGenerator.cs
+++ b/src/Refitter.Core/RefitGenerator.cs
@@ -109,6 +109,8 @@ public string Generate()
var generator = factory.Create();
var docGenerator = new XmlDocumentationGenerator(settings);
var contracts = generator.GenerateFile();
+ contracts = SanitizeGeneratedContracts(contracts);
+
if (settings.GenerateClients)
{
contracts = RefitInterfaceImports
@@ -153,6 +155,7 @@ public GeneratorOutput GenerateMultipleFiles()
var generator = factory.Create();
var docGenerator = new XmlDocumentationGenerator(settings);
var contracts = generator.GenerateFile();
+ contracts = SanitizeGeneratedContracts(contracts);
IRefitInterfaceGenerator interfaceGenerator = settings.MultipleInterfaces switch
{
@@ -199,6 +202,19 @@ public GeneratorOutput GenerateMultipleFiles()
return new GeneratorOutput(generatedFiles);
}
+ private string SanitizeGeneratedContracts(string contracts)
+ {
+ if (settings.CodeGeneratorSettings is not { InlineJsonConverters: false })
+ {
+ return contracts;
+ }
+
+ const string pattern = @"^\s*\[(System\.Text\.Json\.Serialization\.)?JsonConverter\(typeof\((System\.Text\.Json\.Serialization\.)?JsonStringEnumConverter\)\)\]\s*$";
+ var lines = contracts.Split(["\r\n", "\r", "\n"], StringSplitOptions.None);
+ var filteredLines = lines.Where(line => !Regex.IsMatch(line, pattern)).ToArray();
+ return string.Join(Environment.NewLine, filteredLines);
+ }
+
///
/// Generates the client code based on the specified interface generator.
///
diff --git a/src/Refitter.Core/Settings/CodeGeneratorSettings.cs b/src/Refitter.Core/Settings/CodeGeneratorSettings.cs
index 835a08c9..fd3e7b35 100644
--- a/src/Refitter.Core/Settings/CodeGeneratorSettings.cs
+++ b/src/Refitter.Core/Settings/CodeGeneratorSettings.cs
@@ -257,4 +257,13 @@ Gets or sets a value indicating whether named/referenced any schemas should be i
[Description("Gets or sets a custom IPropertyNameGenerator.")]
[JsonIgnore]
public IPropertyNameGenerator? PropertyNameGenerator { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether to inline JsonConverter attributes for enum properties (default: true).
+ /// When set to false, enum properties will not have [JsonConverter(typeof(JsonStringEnumConverter))] attributes.
+ ///
+ [Description(
+ "Gets or sets a value indicating whether to inline JsonConverter attributes for enum properties (default: true). When set to false, enum properties will not have [JsonConverter(typeof(JsonStringEnumConverter))] attributes."
+ )]
+ public bool InlineJsonConverters { get; set; } = true;
}
diff --git a/src/Refitter.SourceGenerator/README.md b/src/Refitter.SourceGenerator/README.md
index e0e6d533..170a1ae5 100644
--- a/src/Refitter.SourceGenerator/README.md
+++ b/src/Refitter.SourceGenerator/README.md
@@ -116,6 +116,7 @@ The following is an example `.refitter` file
"generateNativeRecords": false,
"generateDefaultValues": true,
"inlineNamedAny": false,
+ "inlineJsonConverters": true, // Optional. Default=true. Set to false to not generate JsonConverter attributes for enum properties
"dateFormat": "yyyy-MM-dd",
"dateTimeFormat": "yyyy-MM-dd",
"excludedTypeNames": [
@@ -193,6 +194,7 @@ The following is an example `.refitter` file
- `generateNativeRecords` - Default is false
- `generateDefaultValues` - Default is true
- `inlineNamedAny` - Default is false
+ - `inlineJsonConverters` - Default is true. When set to false, enum properties will not have `[JsonConverter(typeof(JsonStringEnumConverter))]` attributes
- `dateFormat` - Default is null
- `dateTimeFormat` - Default is null
- `excludedTypeNames` - Default is empty
diff --git a/src/Refitter.Tests/Examples/InlineJsonConvertersTests.cs b/src/Refitter.Tests/Examples/InlineJsonConvertersTests.cs
new file mode 100644
index 00000000..37e4cba2
--- /dev/null
+++ b/src/Refitter.Tests/Examples/InlineJsonConvertersTests.cs
@@ -0,0 +1,155 @@
+using FluentAssertions;
+using FluentAssertions.Execution;
+using Refitter.Core;
+using Refitter.Tests.Build;
+using Refitter.Tests.TestUtilities;
+using Xunit;
+
+namespace Refitter.Tests.Examples;
+
+public class InlineJsonConvertersTests
+{
+ private const string OpenApiSpec = @"
+{
+ ""swagger"": ""2.0"",
+ ""info"": {
+ ""title"": ""Enum Test API"",
+ ""version"": ""1.0.0""
+ },
+ ""host"": ""example.com"",
+ ""basePath"": ""/"",
+ ""schemes"": [
+ ""https""
+ ],
+ ""paths"": {
+ ""/api/pets/{petId}"": {
+ ""get"": {
+ ""summary"": ""Get pet by ID"",
+ ""operationId"": ""getPetById"",
+ ""parameters"": [
+ {
+ ""name"": ""petId"",
+ ""in"": ""path"",
+ ""required"": true,
+ ""type"": ""integer""
+ }
+ ],
+ ""responses"": {
+ ""200"": {
+ ""description"": ""Success"",
+ ""schema"": {
+ ""$ref"": ""#/definitions/Pet""
+ }
+ }
+ }
+ }
+ }
+ },
+ ""definitions"": {
+ ""Pet"": {
+ ""type"": ""object"",
+ ""properties"": {
+ ""id"": {
+ ""type"": ""integer"",
+ ""format"": ""int64""
+ },
+ ""name"": {
+ ""type"": ""string""
+ },
+ ""status"": {
+ ""type"": ""string"",
+ ""enum"": [
+ ""available"",
+ ""pending"",
+ ""sold""
+ ]
+ }
+ }
+ }
+ }
+}
+";
+
+ [Fact]
+ public async Task Can_Generate_Code()
+ {
+ string generatedCode = await GenerateCode();
+ generatedCode.Should().NotBeNullOrWhiteSpace();
+ }
+
+ [Fact]
+ public async Task Can_Build_Generated_Code()
+ {
+ string generatedCode = await GenerateCode();
+ BuildHelper
+ .BuildCSharp(generatedCode)
+ .Should()
+ .BeTrue();
+ }
+
+ [Fact]
+ public async Task Generated_Code_Contains_JsonConverter_By_Default()
+ {
+ string generatedCode = await GenerateCode(inlineJsonConverters: true);
+
+ using (new AssertionScope())
+ {
+ generatedCode.Should().Contain("[JsonConverter(typeof(JsonStringEnumConverter))]");
+ generatedCode.Should().Contain("Status { get; set; }");
+ }
+ }
+
+ [Fact]
+ public async Task Generated_Code_Does_Not_Contain_JsonConverter_When_Disabled()
+ {
+ string generatedCode = await GenerateCode(inlineJsonConverters: false);
+
+ using (new AssertionScope())
+ {
+ generatedCode.Should().NotContain("[JsonConverter(typeof(JsonStringEnumConverter))]");
+ generatedCode.Should().Contain("Status { get; set; }");
+ generatedCode.Should().Contain("public enum PetStatus");
+ }
+ }
+
+ [Fact]
+ public async Task Generated_Code_Without_JsonConverter_Can_Build()
+ {
+ string generatedCode = await GenerateCode(inlineJsonConverters: false);
+ BuildHelper
+ .BuildCSharp(generatedCode)
+ .Should()
+ .BeTrue();
+ }
+
+ private static async Task GenerateCode(bool inlineJsonConverters = true)
+ {
+ string swaggerFile = await SwaggerFileHelper.CreateSwaggerFile(OpenApiSpec);
+ try
+ {
+ var settings = new RefitGeneratorSettings
+ {
+ OpenApiPath = swaggerFile,
+ CodeGeneratorSettings = new CodeGeneratorSettings
+ {
+ InlineJsonConverters = inlineJsonConverters
+ }
+ };
+ var generator = await RefitGenerator.CreateAsync(settings);
+ return generator.Generate();
+ }
+ finally
+ {
+ if (File.Exists(swaggerFile))
+ {
+ File.Delete(swaggerFile);
+ }
+
+ var directory = Path.GetDirectoryName(swaggerFile);
+ if (directory != null && Directory.Exists(directory))
+ {
+ Directory.Delete(directory, true);
+ }
+ }
+ }
+}
diff --git a/src/Refitter/GenerateCommand.cs b/src/Refitter/GenerateCommand.cs
index 92529d97..071eec1a 100644
--- a/src/Refitter/GenerateCommand.cs
+++ b/src/Refitter/GenerateCommand.cs
@@ -308,7 +308,11 @@ private static RefitGeneratorSettings CreateRefitGeneratorSettings(Settings sett
UsePolymorphicSerialization = settings.UsePolymorphicSerialization,
GenerateDisposableClients = settings.GenerateDisposableClients,
CollectionFormat = settings.CollectionFormat,
- GenerateXmlDocCodeComments = !settings.NoXmlDocCodeComments
+ GenerateXmlDocCodeComments = !settings.NoXmlDocCodeComments,
+ CodeGeneratorSettings = new CodeGeneratorSettings
+ {
+ InlineJsonConverters = !settings.NoInlineJsonConverters
+ }
};
}
private static async Task WriteSingleFile(
diff --git a/src/Refitter/README.md b/src/Refitter/README.md
index da6556d3..ff0b3c35 100644
--- a/src/Refitter/README.md
+++ b/src/Refitter/README.md
@@ -43,6 +43,7 @@ EXAMPLES:
refitter ./openapi.json --operation-name-template '{operationName}Async'
refitter ./openapi.json --optional-nullable-parameters
refitter ./openapi.json --use-polymorphic-serialization
+ refitter ./openapi.json --no-inline-json-converters
ARGUMENTS:
[URL or input file] URL or file path to OpenAPI Specification file
@@ -109,7 +110,9 @@ OPTIONS:
Replaces NSwag JsonInheritanceConverter attributes with System.Text.Json JsonPolymorphicAttributes.
To have the native support of inheritance (de)serialization and fallback to base types when
payloads with (yet) unknown types are offered by newer versions of an API
- See https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism for more information --disposable Generate refit clients that implement IDisposable
+ See https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism for more information
+ --disposable Generate refit clients that implement IDisposable
+ --no-inline-json-converters Don't inline JsonConverter attributes for enum properties. When disabled, enum properties will not have [JsonConverter(typeof(JsonStringEnumConverter))] attributes
```
## CLI Tool Output Example
diff --git a/src/Refitter/Settings.cs b/src/Refitter/Settings.cs
index 291a0094..9b4aebf0 100644
--- a/src/Refitter/Settings.cs
+++ b/src/Refitter/Settings.cs
@@ -253,4 +253,9 @@ payloads with (yet) unknown types are offered by newer versions of an API
[CommandOption("--simple-output")]
[DefaultValue(false)]
public bool SimpleOutput { get; set; }
+
+ [Description("Don't inline JsonConverter attributes for enum properties. When disabled, enum properties will not have [JsonConverter(typeof(JsonStringEnumConverter))] attributes")]
+ [CommandOption("--no-inline-json-converters")]
+ [DefaultValue(false)]
+ public bool NoInlineJsonConverters { get; set; }
}