mirror of
https://github.com/OpenAPITools/openapi-generator.git
synced 2025-10-13 16:03:43 +00:00
patch all property collections (#15678)
This commit is contained in:
parent
1e1e786a72
commit
0bcf9d8bde
@ -519,10 +519,13 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
|
||||
public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs) {
|
||||
final Map<String, ModelsMap> processed = super.postProcessAllModels(objs);
|
||||
|
||||
// TODO: move the logic of these three methods into patchProperty so all CodegenProperty instances get the same treatment
|
||||
postProcessEnumRefs(processed);
|
||||
updateValueTypeProperty(processed);
|
||||
updateNullableTypeProperty(processed);
|
||||
Map<String, CodegenModel> enumRefs = new HashMap<>();
|
||||
for (Map.Entry<String, ModelsMap> entry : processed.entrySet()) {
|
||||
CodegenModel model = ModelUtils.getModelByName(entry.getKey(), processed);
|
||||
if (model.isEnum) {
|
||||
enumRefs.put(model.getClassname(), model);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, ModelsMap> entry : objs.entrySet()) {
|
||||
CodegenModel model = ModelUtils.getModelByName(entry.getKey(), objs);
|
||||
@ -532,34 +535,52 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
|
||||
// TODO: why do these collections contain different instances?
|
||||
// fixing allVars should suffice instead of patching every collection
|
||||
for (CodegenProperty property : model.allVars) {
|
||||
patchProperty(model, property);
|
||||
patchProperty(enumRefs, model, property);
|
||||
}
|
||||
for (CodegenProperty property : model.vars) {
|
||||
patchProperty(model, property);
|
||||
patchProperty(enumRefs, model, property);
|
||||
}
|
||||
for (CodegenProperty property : model.readWriteVars) {
|
||||
patchProperty(model, property);
|
||||
patchProperty(enumRefs, model, property);
|
||||
}
|
||||
for (CodegenProperty property : model.optionalVars) {
|
||||
patchProperty(model, property);
|
||||
patchProperty(enumRefs, model, property);
|
||||
}
|
||||
for (CodegenProperty property : model.parentVars) {
|
||||
patchProperty(model, property);
|
||||
patchProperty(enumRefs, model, property);
|
||||
}
|
||||
for (CodegenProperty property : model.requiredVars) {
|
||||
patchProperty(model, property);
|
||||
patchProperty(enumRefs, model, property);
|
||||
}
|
||||
for (CodegenProperty property : model.readOnlyVars) {
|
||||
patchProperty(model, property);
|
||||
patchProperty(enumRefs, model, property);
|
||||
}
|
||||
for (CodegenProperty property : model.nonNullableVars) {
|
||||
patchProperty(model, property);
|
||||
patchProperty(enumRefs, model, property);
|
||||
}
|
||||
}
|
||||
return processed;
|
||||
}
|
||||
|
||||
private void patchProperty(CodegenModel model, CodegenProperty property) {
|
||||
private void patchProperty(Map<String, CodegenModel> enumRefs, CodegenModel model, CodegenProperty property) {
|
||||
if (enumRefs.containsKey(property.dataType)) {
|
||||
// Handle any enum properties referred to by $ref.
|
||||
// This is different in C# than most other generators, because enums in C# are compiled to integral types,
|
||||
// while enums in many other languages are true objects.
|
||||
CodegenModel refModel = enumRefs.get(property.dataType);
|
||||
property.allowableValues = refModel.allowableValues;
|
||||
property.isEnum = true;
|
||||
|
||||
// We do these after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#.
|
||||
property.isPrimitiveType = true;
|
||||
}
|
||||
|
||||
if (!property.isContainer && (nullableType.contains(property.dataType) || property.isEnum)) {
|
||||
property.vendorExtensions.put("x-csharp-value-type", true);
|
||||
}
|
||||
|
||||
property.vendorExtensions.put("x-is-value-type", isValueType(property));
|
||||
|
||||
String tmpPropertyName = escapeReservedWord(model, property.name);
|
||||
if (property.name != tmpPropertyName) {
|
||||
// the casing will be wrong if we just set the name to escapeReservedWord
|
||||
@ -646,137 +667,6 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
|
||||
return enumVars;
|
||||
}
|
||||
|
||||
/**
|
||||
* C# differs from other languages in that Enums are not _true_ objects; enums are compiled to integral types.
|
||||
* So, in C#, an enum is considers more like a user-defined primitive.
|
||||
* <p>
|
||||
* When working with enums, we can't always assume a RefModel is a nullable type (where default(YourType) == null),
|
||||
* so this post processing runs through all models to find RefModel'd enums. Then, it runs through all vars and modifies
|
||||
* those vars referencing RefModel'd enums to work the same as inlined enums rather than as objects.
|
||||
*
|
||||
* @param models processed models to be further processed for enum references
|
||||
*/
|
||||
private void postProcessEnumRefs(final Map<String, ModelsMap> models) {
|
||||
Map<String, CodegenModel> enumRefs = new HashMap<>();
|
||||
for (Map.Entry<String, ModelsMap> entry : models.entrySet()) {
|
||||
CodegenModel model = ModelUtils.getModelByName(entry.getKey(), models);
|
||||
if (model.isEnum) {
|
||||
enumRefs.put(model.getClassname(), model);
|
||||
}
|
||||
}
|
||||
|
||||
for (String openAPIName : models.keySet()) {
|
||||
CodegenModel model = ModelUtils.getModelByName(openAPIName, models);
|
||||
if (model != null) {
|
||||
for (CodegenProperty var : model.allVars) {
|
||||
if (enumRefs.containsKey(var.dataType)) {
|
||||
// Handle any enum properties referred to by $ref.
|
||||
// This is different in C# than most other generators, because enums in C# are compiled to integral types,
|
||||
// while enums in many other languages are true objects.
|
||||
CodegenModel refModel = enumRefs.get(var.dataType);
|
||||
var.allowableValues = refModel.allowableValues;
|
||||
var.isEnum = true;
|
||||
|
||||
// We do these after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#.
|
||||
var.isPrimitiveType = true;
|
||||
}
|
||||
}
|
||||
for (CodegenProperty var : model.vars) {
|
||||
if (enumRefs.containsKey(var.dataType)) {
|
||||
// Handle any enum properties referred to by $ref.
|
||||
// This is different in C# than most other generators, because enums in C# are compiled to integral types,
|
||||
// while enums in many other languages are true objects.
|
||||
CodegenModel refModel = enumRefs.get(var.dataType);
|
||||
var.allowableValues = refModel.allowableValues;
|
||||
var.isEnum = true;
|
||||
|
||||
// We do these after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#.
|
||||
var.isPrimitiveType = true;
|
||||
}
|
||||
}
|
||||
for (CodegenProperty var : model.readWriteVars) {
|
||||
if (enumRefs.containsKey(var.dataType)) {
|
||||
// Handle any enum properties referred to by $ref.
|
||||
// This is different in C# than most other generators, because enums in C# are compiled to integral types,
|
||||
// while enums in many other languages are true objects.
|
||||
CodegenModel refModel = enumRefs.get(var.dataType);
|
||||
var.allowableValues = refModel.allowableValues;
|
||||
var.isEnum = true;
|
||||
|
||||
// We do these after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#.
|
||||
var.isPrimitiveType = true;
|
||||
}
|
||||
}
|
||||
for (CodegenProperty var : model.readOnlyVars) {
|
||||
if (enumRefs.containsKey(var.dataType)) {
|
||||
// Handle any enum properties referred to by $ref.
|
||||
// This is different in C# than most other generators, because enums in C# are compiled to integral types,
|
||||
// while enums in many other languages are true objects.
|
||||
CodegenModel refModel = enumRefs.get(var.dataType);
|
||||
var.allowableValues = refModel.allowableValues;
|
||||
var.isEnum = true;
|
||||
|
||||
// We do these after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#.
|
||||
var.isPrimitiveType = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Comment out the following as model.dataType is always the model name, eg. OuterIntegerEnum,
|
||||
* and this will fix the integer enum via #9035.
|
||||
* Only x-enum-byte is used in the template but it won't work due to the bug mentioned above.
|
||||
* A better solution is to introduce isLong, isInteger, etc in the DefaultCodegen
|
||||
* so that there is no need for each generator to post-process model enums.
|
||||
*
|
||||
// We're looping all models here.
|
||||
if (model.isEnum) {
|
||||
// We now need to make allowableValues.enumVars look like the context of CodegenProperty
|
||||
Boolean isString = false;
|
||||
Boolean isInteger = false;
|
||||
Boolean isLong = false;
|
||||
Boolean isByte = false;
|
||||
|
||||
if (model.dataType.startsWith("byte")) {
|
||||
// C# Actually supports byte and short enums, swagger spec only supports byte.
|
||||
isByte = true;
|
||||
model.vendorExtensions.put("x-enum-byte", true);
|
||||
} else if (model.dataType.startsWith("int32")) {
|
||||
isInteger = true;
|
||||
model.vendorExtensions.put("x-enum-integer", true);
|
||||
} else if (model.dataType.startsWith("int64")) {
|
||||
isLong = true;
|
||||
model.vendorExtensions.put("x-enum-long", true);
|
||||
} else {
|
||||
// C# doesn't support non-integral enums, so we need to treat everything else as strings (e.g. to not lose precision or data integrity)
|
||||
isString = true;
|
||||
model.vendorExtensions.put("x-enum-string", true);
|
||||
}
|
||||
|
||||
// Since we iterate enumVars for modelInnerEnum and enumClass templates, and CodegenModel is missing some of CodegenProperty's properties,
|
||||
// we can take advantage of Mustache's contextual lookup to add the same "properties" to the model's enumVars scope rather than CodegenProperty's scope.
|
||||
List<Map<String, String>> enumVars = (ArrayList<Map<String, String>>) model.allowableValues.get("enumVars");
|
||||
List<Map<String, Object>> newEnumVars = new ArrayList<Map<String, Object>>();
|
||||
for (Map<String, String> enumVar : enumVars) {
|
||||
Map<String, Object> mixedVars = new HashMap<String, Object>();
|
||||
mixedVars.putAll(enumVar);
|
||||
|
||||
mixedVars.put("isString", isString);
|
||||
mixedVars.put("isLong", isLong);
|
||||
mixedVars.put("isInteger", isInteger);
|
||||
mixedVars.put("isByte", isByte);
|
||||
|
||||
newEnumVars.add(mixedVars);
|
||||
}
|
||||
|
||||
if (!newEnumVars.isEmpty()) {
|
||||
model.allowableValues.put("enumVars", newEnumVars);
|
||||
}
|
||||
} */
|
||||
} else {
|
||||
LOGGER.warn("Expected to retrieve model %s by name, but no model was found. Check your -Dmodels inclusions.", openAPIName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update codegen property's enum by adding "enumVars" (with name and value)
|
||||
*
|
||||
@ -813,49 +703,6 @@ public abstract class AbstractCSharpCodegen extends DefaultCodegen implements Co
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update property if it is a C# value type
|
||||
*
|
||||
* @param models list of all models
|
||||
*/
|
||||
protected void updateValueTypeProperty(Map<String, ModelsMap> models) {
|
||||
for (String openAPIName : models.keySet()) {
|
||||
CodegenModel model = ModelUtils.getModelByName(openAPIName, models);
|
||||
if (model != null) {
|
||||
for (CodegenProperty var : model.vars) {
|
||||
var.vendorExtensions.put("x-is-value-type", isValueType(var));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update property if it is a C# nullable type
|
||||
*
|
||||
* @param models list of all models
|
||||
*/
|
||||
protected void updateNullableTypeProperty(Map<String, ModelsMap> models) {
|
||||
for (String openAPIName : models.keySet()) {
|
||||
CodegenModel model = ModelUtils.getModelByName(openAPIName, models);
|
||||
if (model != null) {
|
||||
for (CodegenProperty var : model.vars) {
|
||||
if (!var.isContainer && (nullableType.contains(var.dataType) || var.isEnum)) {
|
||||
var.vendorExtensions.put("x-csharp-value-type", true);
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/OpenAPITools/openapi-generator/issues/12324
|
||||
// we should not need to iterate both vars and allVars
|
||||
// the collections dont have the same instance, so we have to do it again
|
||||
for (CodegenProperty var : model.allVars) {
|
||||
if (!var.isContainer && (nullableType.contains(var.dataType) || var.isEnum)) {
|
||||
var.vendorExtensions.put("x-csharp-value-type", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
|
||||
super.postProcessOperationsWithModels(objs, allModels);
|
||||
|
Loading…
x
Reference in New Issue
Block a user