Skip to content

Commit 0bcf9d8

Browse files
authored
patch all property collections (OpenAPITools#15678)
1 parent 1e1e786 commit 0bcf9d8

File tree

1 file changed

+34
-187
lines changed

1 file changed

+34
-187
lines changed

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCSharpCodegen.java

Lines changed: 34 additions & 187 deletions
Original file line numberDiff line numberDiff line change
@@ -519,10 +519,13 @@ public ModelsMap postProcessModels(ModelsMap objs) {
519519
public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs) {
520520
final Map<String, ModelsMap> processed = super.postProcessAllModels(objs);
521521

522-
// TODO: move the logic of these three methods into patchProperty so all CodegenProperty instances get the same treatment
523-
postProcessEnumRefs(processed);
524-
updateValueTypeProperty(processed);
525-
updateNullableTypeProperty(processed);
522+
Map<String, CodegenModel> enumRefs = new HashMap<>();
523+
for (Map.Entry<String, ModelsMap> entry : processed.entrySet()) {
524+
CodegenModel model = ModelUtils.getModelByName(entry.getKey(), processed);
525+
if (model.isEnum) {
526+
enumRefs.put(model.getClassname(), model);
527+
}
528+
}
526529

527530
for (Map.Entry<String, ModelsMap> entry : objs.entrySet()) {
528531
CodegenModel model = ModelUtils.getModelByName(entry.getKey(), objs);
@@ -532,34 +535,52 @@ public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs)
532535
// TODO: why do these collections contain different instances?
533536
// fixing allVars should suffice instead of patching every collection
534537
for (CodegenProperty property : model.allVars) {
535-
patchProperty(model, property);
538+
patchProperty(enumRefs, model, property);
536539
}
537540
for (CodegenProperty property : model.vars) {
538-
patchProperty(model, property);
541+
patchProperty(enumRefs, model, property);
539542
}
540543
for (CodegenProperty property : model.readWriteVars) {
541-
patchProperty(model, property);
544+
patchProperty(enumRefs, model, property);
542545
}
543546
for (CodegenProperty property : model.optionalVars) {
544-
patchProperty(model, property);
547+
patchProperty(enumRefs, model, property);
545548
}
546549
for (CodegenProperty property : model.parentVars) {
547-
patchProperty(model, property);
550+
patchProperty(enumRefs, model, property);
548551
}
549552
for (CodegenProperty property : model.requiredVars) {
550-
patchProperty(model, property);
553+
patchProperty(enumRefs, model, property);
551554
}
552555
for (CodegenProperty property : model.readOnlyVars) {
553-
patchProperty(model, property);
556+
patchProperty(enumRefs, model, property);
554557
}
555558
for (CodegenProperty property : model.nonNullableVars) {
556-
patchProperty(model, property);
559+
patchProperty(enumRefs, model, property);
557560
}
558561
}
559562
return processed;
560563
}
561564

562-
private void patchProperty(CodegenModel model, CodegenProperty property) {
565+
private void patchProperty(Map<String, CodegenModel> enumRefs, CodegenModel model, CodegenProperty property) {
566+
if (enumRefs.containsKey(property.dataType)) {
567+
// Handle any enum properties referred to by $ref.
568+
// This is different in C# than most other generators, because enums in C# are compiled to integral types,
569+
// while enums in many other languages are true objects.
570+
CodegenModel refModel = enumRefs.get(property.dataType);
571+
property.allowableValues = refModel.allowableValues;
572+
property.isEnum = true;
573+
574+
// We do these after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#.
575+
property.isPrimitiveType = true;
576+
}
577+
578+
if (!property.isContainer && (nullableType.contains(property.dataType) || property.isEnum)) {
579+
property.vendorExtensions.put("x-csharp-value-type", true);
580+
}
581+
582+
property.vendorExtensions.put("x-is-value-type", isValueType(property));
583+
563584
String tmpPropertyName = escapeReservedWord(model, property.name);
564585
if (property.name != tmpPropertyName) {
565586
// the casing will be wrong if we just set the name to escapeReservedWord
@@ -646,137 +667,6 @@ protected List<Map<String, Object>> buildEnumVars(List<Object> values, String da
646667
return enumVars;
647668
}
648669

649-
/**
650-
* C# differs from other languages in that Enums are not _true_ objects; enums are compiled to integral types.
651-
* So, in C#, an enum is considers more like a user-defined primitive.
652-
* <p>
653-
* When working with enums, we can't always assume a RefModel is a nullable type (where default(YourType) == null),
654-
* so this post processing runs through all models to find RefModel'd enums. Then, it runs through all vars and modifies
655-
* those vars referencing RefModel'd enums to work the same as inlined enums rather than as objects.
656-
*
657-
* @param models processed models to be further processed for enum references
658-
*/
659-
private void postProcessEnumRefs(final Map<String, ModelsMap> models) {
660-
Map<String, CodegenModel> enumRefs = new HashMap<>();
661-
for (Map.Entry<String, ModelsMap> entry : models.entrySet()) {
662-
CodegenModel model = ModelUtils.getModelByName(entry.getKey(), models);
663-
if (model.isEnum) {
664-
enumRefs.put(model.getClassname(), model);
665-
}
666-
}
667-
668-
for (String openAPIName : models.keySet()) {
669-
CodegenModel model = ModelUtils.getModelByName(openAPIName, models);
670-
if (model != null) {
671-
for (CodegenProperty var : model.allVars) {
672-
if (enumRefs.containsKey(var.dataType)) {
673-
// Handle any enum properties referred to by $ref.
674-
// This is different in C# than most other generators, because enums in C# are compiled to integral types,
675-
// while enums in many other languages are true objects.
676-
CodegenModel refModel = enumRefs.get(var.dataType);
677-
var.allowableValues = refModel.allowableValues;
678-
var.isEnum = true;
679-
680-
// We do these after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#.
681-
var.isPrimitiveType = true;
682-
}
683-
}
684-
for (CodegenProperty var : model.vars) {
685-
if (enumRefs.containsKey(var.dataType)) {
686-
// Handle any enum properties referred to by $ref.
687-
// This is different in C# than most other generators, because enums in C# are compiled to integral types,
688-
// while enums in many other languages are true objects.
689-
CodegenModel refModel = enumRefs.get(var.dataType);
690-
var.allowableValues = refModel.allowableValues;
691-
var.isEnum = true;
692-
693-
// We do these after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#.
694-
var.isPrimitiveType = true;
695-
}
696-
}
697-
for (CodegenProperty var : model.readWriteVars) {
698-
if (enumRefs.containsKey(var.dataType)) {
699-
// Handle any enum properties referred to by $ref.
700-
// This is different in C# than most other generators, because enums in C# are compiled to integral types,
701-
// while enums in many other languages are true objects.
702-
CodegenModel refModel = enumRefs.get(var.dataType);
703-
var.allowableValues = refModel.allowableValues;
704-
var.isEnum = true;
705-
706-
// We do these after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#.
707-
var.isPrimitiveType = true;
708-
}
709-
}
710-
for (CodegenProperty var : model.readOnlyVars) {
711-
if (enumRefs.containsKey(var.dataType)) {
712-
// Handle any enum properties referred to by $ref.
713-
// This is different in C# than most other generators, because enums in C# are compiled to integral types,
714-
// while enums in many other languages are true objects.
715-
CodegenModel refModel = enumRefs.get(var.dataType);
716-
var.allowableValues = refModel.allowableValues;
717-
var.isEnum = true;
718-
719-
// We do these after updateCodegenPropertyEnum to avoid generalities that don't mesh with C#.
720-
var.isPrimitiveType = true;
721-
}
722-
}
723-
724-
/* Comment out the following as model.dataType is always the model name, eg. OuterIntegerEnum,
725-
* and this will fix the integer enum via #9035.
726-
* Only x-enum-byte is used in the template but it won't work due to the bug mentioned above.
727-
* A better solution is to introduce isLong, isInteger, etc in the DefaultCodegen
728-
* so that there is no need for each generator to post-process model enums.
729-
*
730-
// We're looping all models here.
731-
if (model.isEnum) {
732-
// We now need to make allowableValues.enumVars look like the context of CodegenProperty
733-
Boolean isString = false;
734-
Boolean isInteger = false;
735-
Boolean isLong = false;
736-
Boolean isByte = false;
737-
738-
if (model.dataType.startsWith("byte")) {
739-
// C# Actually supports byte and short enums, swagger spec only supports byte.
740-
isByte = true;
741-
model.vendorExtensions.put("x-enum-byte", true);
742-
} else if (model.dataType.startsWith("int32")) {
743-
isInteger = true;
744-
model.vendorExtensions.put("x-enum-integer", true);
745-
} else if (model.dataType.startsWith("int64")) {
746-
isLong = true;
747-
model.vendorExtensions.put("x-enum-long", true);
748-
} else {
749-
// 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)
750-
isString = true;
751-
model.vendorExtensions.put("x-enum-string", true);
752-
}
753-
754-
// Since we iterate enumVars for modelInnerEnum and enumClass templates, and CodegenModel is missing some of CodegenProperty's properties,
755-
// 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.
756-
List<Map<String, String>> enumVars = (ArrayList<Map<String, String>>) model.allowableValues.get("enumVars");
757-
List<Map<String, Object>> newEnumVars = new ArrayList<Map<String, Object>>();
758-
for (Map<String, String> enumVar : enumVars) {
759-
Map<String, Object> mixedVars = new HashMap<String, Object>();
760-
mixedVars.putAll(enumVar);
761-
762-
mixedVars.put("isString", isString);
763-
mixedVars.put("isLong", isLong);
764-
mixedVars.put("isInteger", isInteger);
765-
mixedVars.put("isByte", isByte);
766-
767-
newEnumVars.add(mixedVars);
768-
}
769-
770-
if (!newEnumVars.isEmpty()) {
771-
model.allowableValues.put("enumVars", newEnumVars);
772-
}
773-
} */
774-
} else {
775-
LOGGER.warn("Expected to retrieve model %s by name, but no model was found. Check your -Dmodels inclusions.", openAPIName);
776-
}
777-
}
778-
}
779-
780670
/**
781671
* Update codegen property's enum by adding "enumVars" (with name and value)
782672
*
@@ -813,49 +703,6 @@ public void updateCodegenPropertyEnum(CodegenProperty var) {
813703
}
814704
}
815705

816-
/**
817-
* Update property if it is a C# value type
818-
*
819-
* @param models list of all models
820-
*/
821-
protected void updateValueTypeProperty(Map<String, ModelsMap> models) {
822-
for (String openAPIName : models.keySet()) {
823-
CodegenModel model = ModelUtils.getModelByName(openAPIName, models);
824-
if (model != null) {
825-
for (CodegenProperty var : model.vars) {
826-
var.vendorExtensions.put("x-is-value-type", isValueType(var));
827-
}
828-
}
829-
}
830-
}
831-
832-
/**
833-
* Update property if it is a C# nullable type
834-
*
835-
* @param models list of all models
836-
*/
837-
protected void updateNullableTypeProperty(Map<String, ModelsMap> models) {
838-
for (String openAPIName : models.keySet()) {
839-
CodegenModel model = ModelUtils.getModelByName(openAPIName, models);
840-
if (model != null) {
841-
for (CodegenProperty var : model.vars) {
842-
if (!var.isContainer && (nullableType.contains(var.dataType) || var.isEnum)) {
843-
var.vendorExtensions.put("x-csharp-value-type", true);
844-
}
845-
}
846-
847-
// https://github.com/OpenAPITools/openapi-generator/issues/12324
848-
// we should not need to iterate both vars and allVars
849-
// the collections dont have the same instance, so we have to do it again
850-
for (CodegenProperty var : model.allVars) {
851-
if (!var.isContainer && (nullableType.contains(var.dataType) || var.isEnum)) {
852-
var.vendorExtensions.put("x-csharp-value-type", true);
853-
}
854-
}
855-
}
856-
}
857-
}
858-
859706
@Override
860707
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
861708
super.postProcessOperationsWithModels(objs, allModels);

0 commit comments

Comments
 (0)