Skip to content

Commit 0b4a401

Browse files
committed
[cpp] Fix Nested Map Support
1 parent 44e26b0 commit 0b4a401

22 files changed

Lines changed: 404 additions & 109 deletions

File tree

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

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -201,19 +201,23 @@ private Schema resolveSchema(Schema schema) {
201201
@Override
202202
@SuppressWarnings("rawtypes")
203203
public String getTypeDeclaration(Schema p) {
204-
Schema schema = resolveSchema(p);
205-
String openAPIType = getSchemaType(schema);
204+
// Resolve the schema to check for nested maps/arrays - refs that point to map schemas
205+
Schema resolved = resolveSchema(p);
206+
207+
if (ModelUtils.isArraySchema(resolved)) {
208+
Schema inner = ModelUtils.getSchemaItems(resolved);
209+
return getSchemaType(p) + "<" + getTypeDeclaration(inner) + ">";
210+
} else if (ModelUtils.isMapSchema(resolved)) {
211+
Schema inner = ModelUtils.getAdditionalProperties(resolved);
212+
return getSchemaType(p) + "<QString, " + getTypeDeclaration(inner) + ">";
213+
}
206214

207-
if (ModelUtils.isArraySchema(schema)) {
208-
Schema inner = ModelUtils.getSchemaItems(schema);
209-
return getSchemaType(schema) + "<" + getTypeDeclaration(inner) + ">";
210-
} else if (ModelUtils.isMapSchema(schema)) {
211-
Schema inner = ModelUtils.getAdditionalProperties(schema);
212-
return getSchemaType(schema) + "<QString, " + getTypeDeclaration(inner) + ">";
213-
} else if (ModelUtils.isBinarySchema(schema)) {
214-
return getSchemaType(schema);
215-
} else if (ModelUtils.isFileSchema(schema)) {
216-
return getSchemaType(schema);
215+
// For non-containers, use the original schema to preserve model names
216+
String openAPIType = getSchemaType(p);
217+
if (ModelUtils.isBinarySchema(p)) {
218+
return getSchemaType(p);
219+
} else if (ModelUtils.isFileSchema(p)) {
220+
return getSchemaType(p);
217221
}
218222
if (foundationClasses.contains(openAPIType)) {
219223
return openAPIType;

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

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -388,25 +388,29 @@ private Schema resolveSchema(Schema schema) {
388388
*/
389389
@Override
390390
public String getTypeDeclaration(Schema p) {
391-
Schema schema = resolveSchema(p);
392-
String openAPIType = getSchemaType(schema);
393-
394-
if (ModelUtils.isArraySchema(schema)) {
395-
Schema inner = ModelUtils.getSchemaItems(schema);
396-
return getSchemaType(schema) + "<" + getTypeDeclaration(inner) + ">";
397-
} else if (ModelUtils.isMapSchema(schema)) {
398-
Schema inner = ModelUtils.getAdditionalProperties(schema);
399-
return getSchemaType(schema) + "<utility::string_t, " + getTypeDeclaration(inner) + ">";
400-
} else if (ModelUtils.isFileSchema(schema) || ModelUtils.isBinarySchema(schema)) {
391+
// Resolve the schema to check for nested maps/arrays - refs that point to map schemas
392+
Schema resolved = resolveSchema(p);
393+
394+
if (ModelUtils.isArraySchema(resolved)) {
395+
Schema inner = ModelUtils.getSchemaItems(resolved);
396+
return getSchemaType(p) + "<" + getTypeDeclaration(inner) + ">";
397+
} else if (ModelUtils.isMapSchema(resolved)) {
398+
Schema inner = ModelUtils.getAdditionalProperties(resolved);
399+
return getSchemaType(p) + "<utility::string_t, " + getTypeDeclaration(inner) + ">";
400+
}
401+
402+
// For non-containers, use the original schema to preserve model names
403+
String openAPIType = getSchemaType(p);
404+
if (ModelUtils.isFileSchema(p) || ModelUtils.isBinarySchema(p)) {
401405
return "std::shared_ptr<" + openAPIType + ">";
402-
} else if (ModelUtils.isStringSchema(schema)
403-
|| ModelUtils.isDateSchema(schema) || ModelUtils.isDateTimeSchema(schema)
404-
|| ModelUtils.isFileSchema(schema) || ModelUtils.isUUIDSchema(schema)
406+
} else if (ModelUtils.isStringSchema(p)
407+
|| ModelUtils.isDateSchema(p) || ModelUtils.isDateTimeSchema(p)
408+
|| ModelUtils.isFileSchema(p) || ModelUtils.isUUIDSchema(p)
405409
|| languageSpecificPrimitives.contains(openAPIType)) {
406410
return toModelName(openAPIType);
407-
} else if (ModelUtils.isObjectSchema(schema)) {
411+
} else if (ModelUtils.isObjectSchema(p)) {
408412
return "std::shared_ptr<Object>";
409-
} else if(typeMapping.containsKey(super.getSchemaType(schema))) {
413+
} else if(typeMapping.containsKey(super.getSchemaType(p))) {
410414
return openAPIType;
411415
}
412416

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

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -224,26 +224,6 @@ private Schema resolveSchema(Schema schema) {
224224
return schema;
225225
}
226226

227-
@Override
228-
public String getTypeDeclaration(Schema p) {
229-
Schema schema = resolveSchema(p);
230-
String openAPIType = getSchemaType(schema);
231-
232-
if (ModelUtils.isArraySchema(schema)) {
233-
Schema inner = ModelUtils.getSchemaItems(schema);
234-
return getSchemaType(schema) + "<" + getTypeDeclaration(inner) + ">";
235-
} else if (ModelUtils.isMapSchema(schema)) {
236-
Schema inner = ModelUtils.getAdditionalProperties(schema);
237-
return getSchemaType(schema) + "<std::string, " + getTypeDeclaration(inner) + ">";
238-
}
239-
240-
if (languageSpecificPrimitives.contains(openAPIType)) {
241-
return toModelName(openAPIType);
242-
} else {
243-
return openAPIType;
244-
}
245-
}
246-
247227
private void makeTypeMappings() {
248228
// Types
249229
String cpp_array_type = "std::list";
@@ -293,6 +273,17 @@ public String toInstantiationType(Schema p) {
293273

294274
@Override
295275
public String getTypeDeclaration(Schema p) {
276+
// Only resolve for nested maps - check if a $ref points to a map schema
277+
Schema resolved = resolveSchema(p);
278+
279+
// Handle nested maps: if a $ref resolves to a map schema, build the nested type
280+
if (ModelUtils.isMapSchema(resolved)) {
281+
Schema inner = ModelUtils.getAdditionalProperties(resolved);
282+
return getSchemaType(p) + "<std::string, " + getTypeDeclaration(inner) + ">";
283+
}
284+
285+
// For everything else (including arrays), use the original behavior
286+
// The templates handle adding array item types themselves
296287
String openAPIType = getSchemaType(p);
297288
if (languageSpecificPrimitives.contains(openAPIType)) {
298289
return toModelName(openAPIType);

modules/openapi-generator/src/main/resources/cpp-tiny/model-body.mustache

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,14 +141,14 @@ bourne::json
141141
}
142142

143143
{{#vars}}
144-
{{{dataType}}}
144+
{{#isMap}}{{{dataType}}}{{/isMap}}{{^isMap}}{{dataType}}{{#isArray}}<{{#items}}{{dataType}}{{/items}}>{{/isArray}}{{/isMap}}
145145
{{classname}}::{{getter}}()
146146
{
147147
return {{name}};
148148
}
149149

150150
void
151-
{{classname}}::{{setter}}({{{dataType}}} {{name}})
151+
{{classname}}::{{setter}}({{#isMap}}{{{dataType}}}{{/isMap}}{{^isMap}}{{dataType}}{{#isArray}}<{{#items}}{{dataType}}{{/items}}>{{/isArray}}{{/isMap}} {{name}})
152152
{
153153
this->{{name}} = {{name}};
154154
}

modules/openapi-generator/src/main/resources/cpp-tiny/model-header.mustache

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,22 +51,32 @@ public:
5151
{{#vars}}
5252
/*! \brief Get {{{description}}}
5353
*/
54-
{{{dataType}}} {{getter}}();
54+
{{#isMap}}{{{dataType}}}{{/isMap}}{{^isMap}}{{dataType}}{{#isArray}}<{{#items}}{{dataType}}{{/items}}>{{/isArray}}{{/isMap}} {{getter}}();
5555

5656
/*! \brief Set {{{description}}}
5757
*/
58-
void {{setter}}({{{dataType}}} {{name}});
58+
void {{setter}}({{#isMap}}{{{dataType}}}{{/isMap}}{{^isMap}}{{dataType}}{{#isArray}}<{{#items}}{{dataType}}{{/items}}>{{/isArray}}{{/isMap}} {{name}});
5959
{{/vars}}
6060

6161

6262
private:
6363
{{#vars}}
64+
{{#isMap}}
65+
{{{dataType}}} {{name}};
66+
{{/isMap}}
67+
{{^isMap}}
68+
{{#isArray}}
69+
{{dataType}}<{{#items}}{{dataType}}{{/items}}> {{name}};
70+
{{/isArray}}
71+
{{^isArray}}
6472
{{#isPrimitiveType}}
65-
{{{dataType}}} {{name}}{};
73+
{{dataType}} {{name}}{};
6674
{{/isPrimitiveType}}
6775
{{^isPrimitiveType}}
68-
{{{dataType}}} {{name}};
76+
{{dataType}} {{name}};
6977
{{/isPrimitiveType}}
78+
{{/isArray}}
79+
{{/isMap}}
7080
{{/vars}}
7181
};
7282
{{/model}}

modules/openapi-generator/src/test/resources/3_0/cpp-restsdk/petstore.yaml

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -876,4 +876,24 @@ components:
876876
format: "uuid"
877877
pattern: "[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}"
878878
type: "string"
879-
879+
StringMap:
880+
description: A simple string to string map
881+
type: object
882+
additionalProperties:
883+
type: string
884+
NestedStringMap:
885+
description: A nested map (string to map of string to string)
886+
type: object
887+
additionalProperties:
888+
$ref: '#/components/schemas/StringMap'
889+
PetStatistics:
890+
description: Statistics about a pet including nested map for health records
891+
type: object
892+
properties:
893+
groomingHistory:
894+
description: Map of date to grooming notes
895+
$ref: '#/components/schemas/StringMap'
896+
healthRecords:
897+
description: Nested map - category to (date to record)
898+
$ref: '#/components/schemas/NestedStringMap'
899+

samples/client/petstore/cpp-restsdk/client/.openapi-generator/FILES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ include/CppRestPetstoreClient/model/CreateUserOrPet_request.h
2424
include/CppRestPetstoreClient/model/Order.h
2525
include/CppRestPetstoreClient/model/Page.h
2626
include/CppRestPetstoreClient/model/Pet.h
27+
include/CppRestPetstoreClient/model/PetStatistics.h
2728
include/CppRestPetstoreClient/model/SchemaWithSet.h
2829
include/CppRestPetstoreClient/model/SchemaWithSet_vaccinationBook.h
2930
include/CppRestPetstoreClient/model/Tag.h
@@ -49,6 +50,7 @@ src/model/CreateUserOrPet_request.cpp
4950
src/model/Order.cpp
5051
src/model/Page.cpp
5152
src/model/Pet.cpp
53+
src/model/PetStatistics.cpp
5254
src/model/SchemaWithSet.cpp
5355
src/model/SchemaWithSet_vaccinationBook.cpp
5456
src/model/Tag.cpp
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
* OpenAPI Petstore
3+
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
4+
*
5+
* The version of the OpenAPI document: 1.0.0
6+
*
7+
* NOTE: This class is auto generated by OpenAPI-Generator 7.19.0-SNAPSHOT.
8+
* https://openapi-generator.tech
9+
* Do not edit the class manually.
10+
*/
11+
12+
/*
13+
* PetStatistics.h
14+
*
15+
* Statistics about a pet including nested map for health records
16+
*/
17+
18+
#ifndef ORG_OPENAPITOOLS_CLIENT_MODEL_PetStatistics_H_
19+
#define ORG_OPENAPITOOLS_CLIENT_MODEL_PetStatistics_H_
20+
21+
#include <boost/optional.hpp>
22+
23+
#include "CppRestPetstoreClient/ModelBase.h"
24+
25+
#include <cpprest/details/basic_types.h>
26+
#include <map>
27+
28+
namespace org {
29+
namespace openapitools {
30+
namespace client {
31+
namespace model {
32+
33+
34+
35+
/// <summary>
36+
/// Statistics about a pet including nested map for health records
37+
/// </summary>
38+
class PetStatistics
39+
: public ModelBase
40+
{
41+
public:
42+
PetStatistics();
43+
virtual ~PetStatistics();
44+
45+
/////////////////////////////////////////////
46+
/// ModelBase overrides
47+
48+
void validate() override;
49+
50+
web::json::value toJson() const override;
51+
bool fromJson(const web::json::value& json) override;
52+
53+
void toMultipart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix) const override;
54+
bool fromMultiPart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix) override;
55+
56+
57+
/////////////////////////////////////////////
58+
/// PetStatistics members
59+
60+
61+
/// <summary>
62+
/// A simple string to string map
63+
/// </summary>
64+
std::map<utility::string_t, utility::string_t> getGroomingHistory() const;
65+
bool groomingHistoryIsSet() const;
66+
void unsetGroomingHistory();
67+
void setGroomingHistory(const std::map<utility::string_t, utility::string_t>& value);
68+
69+
/// <summary>
70+
/// A nested map (string to map of string to string)
71+
/// </summary>
72+
std::map<utility::string_t, std::map<utility::string_t, utility::string_t>> getHealthRecords() const;
73+
bool healthRecordsIsSet() const;
74+
void unsetHealthRecords();
75+
void setHealthRecords(const std::map<utility::string_t, std::map<utility::string_t, utility::string_t>>& value);
76+
77+
78+
protected:
79+
std::map<utility::string_t, utility::string_t> m_GroomingHistory;
80+
bool m_GroomingHistoryIsSet;
81+
82+
std::map<utility::string_t, std::map<utility::string_t, utility::string_t>> m_HealthRecords;
83+
bool m_HealthRecordsIsSet;
84+
85+
};
86+
87+
88+
}
89+
}
90+
}
91+
}
92+
93+
#endif /* ORG_OPENAPITOOLS_CLIENT_MODEL_PetStatistics_H_ */

0 commit comments

Comments
 (0)