Open PRTGC opened 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?
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 ?
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?
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
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...
The PR list the command-line arguments for substitution as:
which version of openapi-generator are you using?
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
please try the latest master instead as the name mapping support in rust generators was added after v7.0.1 release
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
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
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/
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)
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)
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.
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}}
@wing328 , Is there an alternate way of getting "basename" or the attribute name as specified in the spec without generating an error ?
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 _
?
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.
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...
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?
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>,
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
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