OpenAPITools / openapi-generator

OpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec (v2, v3)
https://openapi-generator.tech
Apache License 2.0
22.04k stars 6.61k forks source link

v7.0.1 Usage Question: reserved word mapping with custom templates #17368

Open PRTGC opened 11 months ago

PRTGC commented 11 months ago
Description

I have a set of custom templates for generating rust code. It is based of v5.4 rust / request client templates.

Generating code with openapi definition with properties like 'type' works with the standard v7.0.1 generation, but not with my custom template. I have a configuration file with all kinds of options set. Like

# java -jar openapi-generator-cli-5.4.0.jar generate -c d42/OpenAPI_Gen.yml --skip-validate-spec > d42\Generated.out
#  --global-propery apiDocs=false,apiTests=true,modelDocs=false,modelTests=true
generatorName: rust
outputDir: d42
library: reqwest
#direct 
inputSpec: d42/device42.yaml
#inputSpec: d42\spec2.json
templateDir: ../openapi_templates5/
skipFormModel: false
apiDocs: false
apiTests: true
modelDocs: false
modelTests: true
#reserved-words-mappings: type=r#type
files: # https://openapi-generator.tech/docs/customization/
  impl/api_impl.mustache:
    templateType: API
    folder: src/api_impl
    destinationFilename: _impl.rs_
  impl/model_impl.mustache:
    templateType: Model
    folder: src/model_impl
    destinationFilename: _impl.rs_
  impl/errors_impl.mustache:
    templateType: SupportingFiles
    folder: src/model_impl
    destinationFilename: errors_impl.rs_
  impl/api_mod_impl.mustache:
    destinationFilename: mod.rs_
    templateType: SupportingFiles
    folder: src/api_impl
  impl/model_mod_impl.mustache:
    destinationFilename: mod.rs_
    templateType: SupportingFiles
    folder: src/model_impl
  impl/warp_impl.mustache:
    destinationFilename: warp_impl.rs_
    templateType: SupportingFiles
    folder: src
  impl/sensor_impl.mustache:
    destinationFilename: sensor_impl.rs_
    templateType: SupportingFiles
    folder: src
  impl/build.mustache:
    destinationFilename: build.rs_
    templateType: SupportingFiles
  impl/main_impl.mustache:
    destinationFilename: src/main.rs_
    templateType: SupportingFiles
additionalProperties:
  vendorExtensions.x-outputDir: d42
  httpUserAgent: prtgclib_rust
  vendorExtensions.x-gen-exe: prtgc_d42
  supportAsync: true
  supportMultipleResponses: true
  packageName: prtgclib_d42api
  packageVersion: 0.2.33
  vendorExtensions.x-moahclient: true
Exception in thread "main" java.lang.RuntimeException: Could not generate model 'device'
        at org.openapitools.codegen.DefaultGenerator.generateModels(DefaultGenerator.java:583)
        at org.openapitools.codegen.DefaultGenerator.generate(DefaultGenerator.java:960)
        at org.openapitools.codegen.cmd.Generate.execute(Generate.java:511)
        at org.openapitools.codegen.cmd.OpenApiGeneratorCommand.run(OpenApiGeneratorCommand.java:32)
        at org.openapitools.codegen.OpenAPIGenerator.main(OpenAPIGenerator.java:66)
Caused by: java.lang.RuntimeException: reserved word type not allowed

How to I force the generator to use the standard rust reserved word substitution?

openapi-generator version

v 7.0.1

OpenAPI declaration file content or url

https://api.device42.com/device42.yaml

Command line used for generation

java -jar ../openapi-generator-cli-7.0.1.jar generate -c d42/OpenAPI_Gen.yml --skip-validate-spec > d42\Generated.out

Related issues/PRs

https://github.com/OpenAPITools/openapi-generator/pull/16103

wing328 commented 11 months ago

It is based of v5.4 rust / request client templates.

what about upgrading to the latest stable version instead of using an old version released 2 years ago?

PRTGC commented 11 months ago

Well, that is what I'm trying to do... The issue has been the problems with the reserved words. Every update since 6.0 I tried running it, and got the 'type' exception . The modified templates should be fine as is. The question is why is it not using the reserved word substitution. Is there a parameter or cfg entry to control it ? Or more over, why is it not using the translation ?

wing328 commented 11 months ago

Generating code with openapi definition with properties like 'type' works with the standard v7.0.1 generation, but not with my custom template.

without the custom template, it's pretty much impossible to troublehshoot.

What issue did you run into using the default template? mind sharing with us what you don't like?

wing328 commented 11 months ago

as you probably aware, you can may the property name to something else using the nameMappings option

are you using the latest master? the option was added to rust abstract codegen recenlty if I remember correctly

PRTGC commented 11 months ago

Hi... Thanks for getting back to me..

The only real question I have is... What controls the "reserved word" substitution ? How do I enable/disable the reserved word substitution when generating rust code ? There must be something in my config file that overrides or disables the substitution. (Both command line and config file)

The PR list the command-line arguments for substitution as: --name-mappings type=underscoreType, type=typeWithUnderscore

I tried : --name-mappings type=r#type Which did not work

I did a diff on the v5.4.0 and v7.0.1 templates, there are not much that is different. And nothing that would indicate the difference in substitution.

If there is something in the templates that actually controls the reserved word substitution, I'll have to make a subset that compiles without my internal libraries...

wing328 commented 11 months ago

The PR list the command-line arguments for substitution as:

which version of openapi-generator are you using?

PRTGC commented 11 months ago

I am trying to run v7.0.1 java -jar openapi-generator-cli-7.0.1.jar generate -c d42/OpenAPI_Gen.yml --name-mappings type=r#type

wing328 commented 11 months ago

please try the latest master instead as the name mapping support in rust generators was added after v7.0.1 release

PRTGC commented 11 months ago

I will do that... The crazy thing is that it works with the plain call in the release version. But it does not work with the modified templates

PRTGC commented 11 months ago

same result with: java -jar openapi-generator-cli-7.1.0.jar generate -c d42/OpenAPI_Gen.yml --skip-validate-spec --name-mappings type=r#type

wing328 commented 11 months ago

latest master - not latest stable version

you can find the snapshot version in https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator-cli/7.2.0-SNAPSHOT/

PRTGC commented 11 months ago

I'll try that... Here is another crazy one... When I turn on verbose I get:

[main] WARN  o.o.c.languages.AbstractRustCodegen - type cannot be used as a field/variable name. Renamed to r#type
[main] WARN  o.o.c.languages.AbstractRustCodegen - type cannot be used as a field/variable name. Renamed to r#type
[main] WARN  o.o.c.languages.AbstractRustCodegen - type cannot be used as a field/variable name. Renamed to r#type
[main] WARN  o.o.c.languages.AbstractRustCodegen - type cannot be used as a field/variable name. Renamed to r#type
[main] WARN  o.o.c.languages.AbstractRustCodegen - type cannot be used as a field/variable name. Renamed to r#type
[main] WARN  o.o.c.languages.AbstractRustCodegen - type cannot be used as a field/variable name. Renamed to r#type
[main] WARN  o.o.c.languages.AbstractRustCodegen - type cannot be used as a field/variable name. Renamed to r#type
[main] WARN  o.o.c.languages.AbstractRustCodegen - type cannot be used as a field/variable name. Renamed to r#type
[main] WARN  o.o.c.languages.AbstractRustCodegen - type cannot be used as a field/variable name. Renamed to r#type
[main] WARN  o.o.c.languages.AbstractRustCodegen - where cannot be used as a field/variable name. Renamed to r#where
[main] WARN  o.o.c.languages.AbstractRustCodegen - where cannot be used as a field/variable name. Renamed to r#where
[main] WARN  o.o.c.languages.AbstractRustCodegen - where cannot be used as a field/variable name. Renamed to r#where

So I guess the question is... why do we still get this one:

Exception in thread "main" java.lang.RuntimeException: Could not generate model 'device'
        at org.openapitools.codegen.DefaultGenerator.generateModels(DefaultGenerator.java:592)
        at org.openapitools.codegen.DefaultGenerator.generate(DefaultGenerator.java:991)
        at org.openapitools.codegen.cmd.Generate.execute(Generate.java:519)
        at org.openapitools.codegen.cmd.OpenApiGeneratorCommand.run(OpenApiGeneratorCommand.java:32)
        at org.openapitools.codegen.OpenAPIGenerator.main(OpenAPIGenerator.java:66)
Caused by: java.lang.RuntimeException: reserved word type not allowed
        at org.openapitools.codegen.DefaultCodegen.escapeReservedWord(DefaultCodegen.java:1732)
        at org.openapitools.codegen.templating.mustache.LowercaseLambda.execute(LowercaseLambda.java:57)
        at com.samskivert.mustache.Mustache$SectionSegment.execute(Mustache.java:949)
        at com.samskivert.mustache.Template.executeSegs(Template.java:170)
        at com.samskivert.mustache.Mustache$IncludedTemplateSegment.execute(Mustache.java:831)
        at com.samskivert.mustache.Mustache$BlockSegment.executeSegs(Mustache.java:920)
        at com.samskivert.mustache.Mustache$SectionSegment.execute(Mustache.java:941)
        at com.samskivert.mustache.Mustache$BlockSegment.executeSegs(Mustache.java:920)
        at com.samskivert.mustache.Mustache$InvertedSegment.execute(Mustache.java:992)
        at com.samskivert.mustache.Mustache$BlockSegment.executeSegs(Mustache.java:920)
        at com.samskivert.mustache.Mustache$InvertedSegment.execute(Mustache.java:988)
        at com.samskivert.mustache.Mustache$BlockSegment.executeSegs(Mustache.java:920)
        at com.samskivert.mustache.Mustache$SectionSegment.execute(Mustache.java:956)
        at com.samskivert.mustache.Mustache$BlockSegment.executeSegs(Mustache.java:920)
        at com.samskivert.mustache.Mustache$SectionSegment.execute(Mustache.java:941)
        at com.samskivert.mustache.Template.executeSegs(Template.java:170)
        at com.samskivert.mustache.Template.execute(Template.java:137)
        at com.samskivert.mustache.Template.execute(Template.java:128)
        at org.openapitools.codegen.templating.MustacheEngineAdapter.compileTemplate(MustacheEngineAdapter.java:65)
        at org.openapitools.codegen.TemplateManager.write(TemplateManager.java:163)
        at org.openapitools.codegen.DefaultGenerator.processTemplateToFile(DefaultGenerator.java:1140)
        at org.openapitools.codegen.DefaultGenerator.processTemplateToFile(DefaultGenerator.java:1127)
        at org.openapitools.codegen.DefaultGenerator.generateModel(DefaultGenerator.java:431)
        at org.openapitools.codegen.DefaultGenerator.generateModels(DefaultGenerator.java:583)
PRTGC commented 11 months ago

Using latest snapshot: generator-cli-7.2.0-20231212.145822-96.jar

  at org.openapitools.codegen.DefaultGenerator.generate(DefaultGenerator.java:1235)
    at org.openapitools.codegen.cmd.Generate.execute(Generate.java:527)
    at org.openapitools.codegen.cmd.OpenApiGeneratorCommand.run(OpenApiGeneratorCommand.java:32)
    at org.openapitools.codegen.OpenAPIGenerator.main(OpenAPIGenerator.java:66)

Caused by: java.lang.RuntimeException: reserved word type not allowed at org.openapitools.codegen.DefaultCodegen.escapeReservedWord(DefaultCodegen.java:1752) at org.openapitools.codegen.templating.mustache.LowercaseLambda.execute(LowercaseLambda.java:57) at com.samskivert.mustache.Mustache$SectionSegment.execute(Mustache.java:949) at com.samskivert.mustache.Template.executeSegs(Template.java:170) at com.samskivert.mustache.Mustache$IncludedTemplateSegment.execute(Mustache.java:831) at com.samskivert.mustache.Mustache$BlockSegment.executeSegs(Mustache.java:920) at com.samskivert.mustache.Mustache$SectionSegment.execute(Mustache.java:941) at com.samskivert.mustache.Mustache$BlockSegment.executeSegs(Mustache.java:920) at com.samskivert.mustache.Mustache$InvertedSegment.execute(Mustache.java:992) at com.samskivert.mustache.Mustache$BlockSegment.executeSegs(Mustache.java:920) at com.samskivert.mustache.Mustache$InvertedSegment.execute(Mustache.java:988) at com.samskivert.mustache.Mustache$BlockSegment.executeSegs(Mustache.java:920) at com.samskivert.mustache.Mustache$SectionSegment.execute(Mustache.java:956)

wing328 commented 11 months ago

at org.openapitools.codegen.DefaultCodegen.escapeReservedWord(DefaultCodegen.java:1752) at org.openapitools.codegen.templating.mustache.LowercaseLambda.execute(LowercaseLambda.java:57)

my guess is that you're using {{baseName}} (instead of {{name}}) inside the lower case lambda mustache handler

again without the custom templates, hard to tell the exact cause.

PRTGC commented 11 months ago

Yes I am... It is needed to make sure I cover all the labels names, since enums and fieldnames may be renamed..

    #[serde(rename = "{{{baseName}}}", alias = "{{#lambda.lowercase}}{{{baseName}}}{{/lambda.lowercase}}"{{^required}}{{#vendorExtensions.x-memberPrefix}}, alias = "{{{.}}}{{{name}}}"{{/vendorExtensions.x-memberPrefix}}, 
                    alias = "{{{nameInCamelCase}}}", alias = "{{nameInSnakeCase}}"{{^isEnum}}{{#isNumeric}}, 
                deserialize_with = "serde_utils::deserialize_{{#lambda.lowercase}}{{{baseType}}}{{/lambda.lowercase}}_or_string{{^required}}_opt{{/required}}"{{^required}}, 
                default = "serde_utils::default_{{#lambda.lowercase}}{{{baseType}}}{{/lambda.lowercase}}_opt"{{/required}} {{/isNumeric}}{{/isEnum}}, 
                skip_serializing_if = "Option::is_none"{{#isDate}}, 
                deserialize_with = "{{#vendorExtensions.x-datetime_serialize_opt_with}}{{{.}}}{{/vendorExtensions.x-datetime_serialize_opt_with}}{{^vendorExtensions.x-datetime_serialize_opt_with}}serde_utils::deserialize_chrono_any_opt{{/vendorExtensions.x-datetime_serialize_opt_with}}"{{/isDate}}{{#isDateTime}}, 
                deserialize_with = "{{#vendorExtensions.x-datetime_serialize_opt_with}}{{{.}}}{{/vendorExtensions.x-datetime_serialize_opt_with}}{{^vendorExtensions.x-datetime_serialize_opt_with}}serde_utils::deserialize_chrono_any_opt{{/vendorExtensions.x-datetime_serialize_opt_with}}"{{/isDateTime}}{{/required}}{{#required}}{{^isEnum}}{{#isDateTime}}, 
                deserialize_with = "{{#vendorExtensions.x-datetime_serialize_with}}{{{.}}}{{/vendorExtensions.x-datetime_serialize_with}}{{^vendorExtensions.x-datetime_serialize_with}}serde_utils::deserialize_chrono_any{{/vendorExtensions.x-datetime_serialize_with}}"{{#vendorExtensions.x-datetime_serialize_with}}, 
                serialize_with = "{{{.}}}"{{/vendorExtensions.x-datetime_serialize_with}}{{/isDateTime}}{{/isEnum}}{{#isString}}{{#vendorExtensions.x-string_deserialize_any}}, 
                deserialize_with = "{{{.}}}"{{/vendorExtensions.x-string_deserialize_any}}{{/isString}}{{#isEnum}}, default{{/isEnum}}{{/required}})]{{#vendorExtensions.x-getset_prefix}}
PRTGC commented 11 months ago

@wing328 , Is there an alternate way of getting "basename" or the attribute name as specified in the spec without generating an error ?

wing328 commented 11 months ago

looks like rust generators do not override the escapeReservedWord method at the moment.

What should be the best way to escape the reserved word in rust? prefix with _ ?

wing328 commented 11 months ago

FYI I've filed https://github.com/OpenAPITools/openapi-generator/pull/17403 to not check reserved words in the lambda but likely it will take some time to review and test to confirm it's safe to merge without too much impact on the output.

PRTGC commented 11 months ago

Hi...

I believe the best option is to prefix with reserved words with "r#", which it currently does and that should work fine. Optimally, that should be a an option, like "keyword_prefix=r#"...

I bump into a lot of cases that require using and manipulating the raw name. I keep forgetting to extract them into my testcase, and I'll have to do that. Most are related to enum values and complex or composed types ( like Vec).

But there has to be a way to get the raw value as specified in the definition. The easiest and most straight forward, would be to not throw exception when it is invalid. Print an error message, and move on... (I would probably make that an configuration option as well "keyword_invalid_action=Warn|Error|Trhow")

I've added a lot of convenience generation to my templates that I can probably contribute if you will accept PR's.. I generate test cases, enum conversion, model get/set(key, json), inline documentation etc... I generate using Strum, serde_as, derive_more enum:

#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(AsRefStr, IntoStaticStr, EnumString, EnumMessage, EnumIter)]
#[strum(ascii_case_insensitive)]
#[serde_as]
#[derive(SerializeDisplay, DeserializeFromStr)]
#[allow(non_camel_case_types)]
pub enum ApplianceMode { 
    #[strum(to_string = "standby", serialize = "Standby", message="standby")] //{name=Standby, isString=true, value=standby} 
    Standby,
    #[strum(to_string = "production", serialize = "Production", message="production")] //{name=Production, isString=true, value=production} 
    Production,
     #[strum(to_string = "_EInvalid", serialize = "", default)]
    _EInvalid(String),
    #[strum(to_string = "_EUninitialized")]
    _EUninitialized,
}

struct: Serde,serde_as,

and a whole lot of other stuff

I must say, that one of the biggest problems I have is that there are a lot of incomplete or poorly written swagger/openapi definitions. About 15-20% don't even pass the Online Swagger editor Syntax checker...

wing328 commented 11 months ago

I've filed https://github.com/OpenAPITools/openapi-generator/pull/17440.

can you please pull the branch, build the project locally and test to confirm you no longer encounter the exception using your specs?

PRTGC commented 11 months ago

Hi @wing328,

Thanks for looking into it...

It worked, it stopped throwing exceptions. Though the result was not optimal... from this

    /** {{#description}}{{{.}}}
    {{/description}}{{>partial_Var_type_comment}} 
    */ {{#complexType}}
    /// ComplexType: {{complexType}} // {{#example}}Example: "{{example}}{{/example}}"
    //#[serde_as(as = "{{^required}}Option<{{/required}}{{{dataType}}}{{^required}}>{{/required}}")]{{/complexType}}{{^complexType}} {{^defaultValue}}{{#required}}{{^isNullable}}{{#isDateTime}}
    #[derivative(Default(value = "{{^required}}Some({{/required}}crate::get_datetime_default(){{^required}}){{/required}}"))]{{/isDateTime}}
    {{/isNullable}}{{/required}}{{/defaultValue}}{{#defaultValue}} // &&##&& Default values does not work correctly
    #[derivative(Default(value = "{{^required}}Some({{/required}}{{#isBoolean}}{{#defaultValue}}{{defaultValue}}{{/defaultValue}}{{^defaultValue}}false{{/defaultValue}}{{/isBoolean}}{{#isString}}{{#isEnum}}
            {{{datatypeWithEnum}}}::default(){{/isEnum}}{{^isEnum}}
            String::from(\"{{defaultValue}}\"){{/isEnum}}{{/isString}}{{#isUuid}}
            uuid::Uuid::parse_str(\"{{defaultValue}}\").unwrap_or(uuid::Uuid::default()){{/isUuid}}{{#isDateTime}}
            crate::parse_datetime(\"{{defaultValue}}\"){{/isDateTime}}{{#isModel}}
            Box::new({{dataType}}::default()){{/isModel}}{{#isModel}} //  {{complexType}}{{/isModel}}{{^required}}){{/required}}"{{^required}}
        // {{#isEnum}}{{#isArray}}Vec::new(){{/isArray}}{{^isArray}}{{{datatypeWithEnum}}}::default(){{/isArray}}{{/isEnum}} {{^isEnum}}{{#isArray}}Vec::new(){{/isArray}}{{#isMap}}Hashmap::new(){{/isMap}}{{#isString}}String::from(\"\"){{/isString}}{{#isInteger}}-1{{/isInteger}}{{#isLong}}-1{{/isLong}}{{#isFloat}}f32::NAN{{/isFloat}}{{#isDouble}}f64::NAN{{/isDouble}}{{^isArray}}{{#isUuid}}uuid::Uuid::default(){{/isUuid}}{{#isDateTime}}crate::get_datetime_default(){{/isDateTime}}{{^isString}}{{^isInteger}}{{^isLong}}{{^isFloat}}{{^isDouble}}{{^isMap}}{{^isUuid}}{{^isDateTime}}{{#isModel}}Box::new({{/isModel}}{{DataType}}::default(){{#isModel}}){{/isModel}}{{/isDateTime}}{{/isUuid}}{{/isMap}}{{/isDouble}}{{/isFloat}}{{/isLong}}{{/isInteger}}{{/isString}}{{/isArray}}{{/isEnum}}
        ){{/required}})] 
    {{/defaultValue}}{{^isPrimitiveType}}
    //#[serde_as(as = "{{^required}}Option<{{/required}}{{#isNullable}}Option<{{/isNullable}}{{#isArray}}Vec<{{/isArray}}{{{dataType}}}{{#isArray}}>{{/isArray}}{{^required}}>{{/required}}")]{{/isPrimitiveType}}{{/complexType}}{{#isEnum}}
    #[serde_as(as = "{{^required}}Option<{{/required}}{{#isArray}}Vec<{{/isArray}}DisplayFromStr{{#isArray}}>{{/isArray}}{{^required}}>{{/required}}")] // serde_as combined with deserialize_with is error{{/isEnum}}
    #[serde(rename = "{{{baseName}}}", alias = "{{#lambda.lowercase}}{{{baseName}}}{{/lambda.lowercase}}"{{^required}}{{#vendorExtensions.x-memberPrefix}}, alias = "{{{.}}}{{{name}}}"{{/vendorExtensions.x-memberPrefix}}, 
                    alias = "{{{nameInCamelCase}}}", alias = "{{nameInSnakeCase}}"{{^isEnum}}{{#isNumeric}}, 
                deserialize_with = "serde_utils::deserialize_{{#lambda.lowercase}}{{{baseType}}}{{/lambda.lowercase}}_or_string{{^required}}_opt{{/required}}"{{^required}}, 
                default = "serde_utils::default_{{#lambda.lowercase}}{{{baseType}}}{{/lambda.lowercase}}_opt"{{/required}} {{/isNumeric}}{{/isEnum}}, 
                skip_serializing_if = "Option::is_none"{{#isDate}}, 
                deserialize_with = "{{#vendorExtensions.x-datetime_serialize_opt_with}}{{{.}}}{{/vendorExtensions.x-datetime_serialize_opt_with}}{{^vendorExtensions.x-datetime_serialize_opt_with}}serde_utils::deserialize_chrono_any_opt{{/vendorExtensions.x-datetime_serialize_opt_with}}"{{/isDate}}{{#isDateTime}}, 
                deserialize_with = "{{#vendorExtensions.x-datetime_serialize_opt_with}}{{{.}}}{{/vendorExtensions.x-datetime_serialize_opt_with}}{{^vendorExtensions.x-datetime_serialize_opt_with}}serde_utils::deserialize_chrono_any_opt{{/vendorExtensions.x-datetime_serialize_opt_with}}"{{/isDateTime}}{{/required}}{{#required}}{{^isEnum}}{{#isDateTime}}, 
                deserialize_with = "{{#vendorExtensions.x-datetime_serialize_with}}{{{.}}}{{/vendorExtensions.x-datetime_serialize_with}}{{^vendorExtensions.x-datetime_serialize_with}}serde_utils::deserialize_chrono_any{{/vendorExtensions.x-datetime_serialize_with}}"{{#vendorExtensions.x-datetime_serialize_with}}, 
                serialize_with = "{{{.}}}"{{/vendorExtensions.x-datetime_serialize_with}}{{/isDateTime}}{{/isEnum}}{{#isString}}{{#vendorExtensions.x-string_deserialize_any}}, 
                deserialize_with = "{{{.}}}"{{/vendorExtensions.x-string_deserialize_any}}{{/isString}}{{#isEnum}}, default{{/isEnum}}{{/required}})]{{#vendorExtensions.x-getset_prefix}}
    #[get = "pub with_prefix"]{{/vendorExtensions.x-getset_prefix}}
    pub {{#vendorExtensions.x-memberPrefix}}{{{.}}}{{/vendorExtensions.x-memberPrefix}}{{{name}}}: {{#required}}{{#isNullable}}Option<{{/isNullable}}{{/required}}{{^required}}Option<{{/required}}{{#isEnum}}{{{datatypeWithEnum}}}{{/isEnum}}{{^isEnum}}{{#isDateTime}}ChronoDateTime{{/isDateTime}}{{#isDate}}ChronoDateTime{{/isDate}}{{^isDateTime}}{{^isDate}}{{#isModel}}Box<{{/isModel}}{{{dataType}}}{{#isModel}}>{{/isModel}}{{/isDate}}{{/isDateTime}}{{/isEnum}}{{#required}}{{#isNullable}}>{{/isNullable}}{{/required}}{{^required}}>{{/required}},

Now I get:

    /** // Var: "r#type/"/"type" DT["serde_json::Value"/"serde_json::Value"], Option, FreeFormObject  
    */  
    //#[serde_as(as = "Option<serde_json::Value>")]
    #[serde(rename = "type", alias = "r#type", alias = "m_r#type", 
                    alias = "R#type", alias = "R#TYPE", 
                skip_serializing_if = "Option::is_none")]
    #[get = "pub with_prefix"]
    pub m_r#type: Option<serde_json::Value>,

This also demonstrates a couple of issues...

1) A flag indicating it is a reserved word would be better, like:

{{#vendorExtensions.x-memberPrefix}}{{{.}}}{{/vendorExtensions.x-memberPrefix}}{{^vendorExtensions.x-memberPrefix}}{{#isReservedWord}}r#{{/isReservedWord}}{{/vendorExtensions.x-memberPrefix}}{{name}}

2) The default type... Is there a way to specify the default type for the ones that may use a different crate or aliased name... ? Like: default_json_type: MySpecialJsonValueWrapper

3) I went through and changed all the {{name}} to {{basename}} to get arround the "m_r#type" problems. But it broke down when there was a field that had a '-' in it:

    #[serde(rename = "core-app", alias = "core-app", alias = "m_core-app", 
                    alias = "CoreApp", alias = "CORE_APP", 
                skip_serializing_if = "Option::is_none")]
    #[get = "pub with_prefix"]
    pub m_core-app: Option<crate::models::Status>,