|
19 | 19 |
|
20 | 20 | import com.samskivert.mustache.Mustache;
|
21 | 21 | import com.samskivert.mustache.Template;
|
22 |
| -import io.swagger.v3.oas.models.media.ArraySchema; |
23 |
| -import io.swagger.v3.oas.models.media.Schema; |
24 |
| -import io.swagger.v3.oas.models.media.StringSchema; |
| 22 | +import io.swagger.v3.oas.models.media.*; |
25 | 23 | import io.swagger.v3.parser.util.SchemaTypeUtil;
|
26 | 24 | import joptsimple.internal.Strings;
|
27 | 25 | import org.openapitools.codegen.*;
|
|
41 | 39 | import java.math.BigDecimal;
|
42 | 40 | import java.math.BigInteger;
|
43 | 41 | import java.util.*;
|
44 |
| - |
45 |
| -import static org.openapitools.codegen.utils.StringUtils.camelize; |
| 42 | +import java.util.stream.Collectors; |
46 | 43 |
|
47 | 44 | public class RustClientCodegen extends AbstractRustCodegen implements CodegenConfig {
|
48 | 45 | private final Logger LOGGER = LoggerFactory.getLogger(RustClientCodegen.class);
|
@@ -149,11 +146,13 @@ public RustClientCodegen() {
|
149 | 146 | typeMapping.clear();
|
150 | 147 | typeMapping.put("integer", "i32");
|
151 | 148 | typeMapping.put("long", "i64");
|
152 |
| - typeMapping.put("number", "f32"); |
| 149 | + typeMapping.put("number", "f64"); |
153 | 150 | typeMapping.put("float", "f32");
|
154 | 151 | typeMapping.put("double", "f64");
|
155 | 152 | typeMapping.put("boolean", "bool");
|
156 | 153 | typeMapping.put("string", "String");
|
| 154 | + typeMapping.put("array", "Vec"); |
| 155 | + typeMapping.put("map", "std::collections::HashMap"); |
157 | 156 | typeMapping.put("UUID", "uuid::Uuid");
|
158 | 157 | typeMapping.put("URI", "String");
|
159 | 158 | typeMapping.put("date", "string");
|
@@ -205,11 +204,72 @@ public RustClientCodegen() {
|
205 | 204 | setLibrary(REQWEST_LIBRARY);
|
206 | 205 | }
|
207 | 206 |
|
| 207 | + @Override |
| 208 | + public CodegenModel fromModel(String name, Schema model) { |
| 209 | + CodegenModel mdl = super.fromModel(name, model); |
| 210 | + |
| 211 | + // set correct names and baseNames to oneOf in composed-schema to use as enum variant names & mapping |
| 212 | + if (mdl.getComposedSchemas() != null && mdl.getComposedSchemas().getOneOf() != null |
| 213 | + && !mdl.getComposedSchemas().getOneOf().isEmpty()) { |
| 214 | + |
| 215 | + List<CodegenProperty> newOneOfs = mdl.getComposedSchemas().getOneOf().stream() |
| 216 | + .map(CodegenProperty::clone) |
| 217 | + .collect(Collectors.toList()); |
| 218 | + List<Schema> schemas = ModelUtils.getInterfaces(model); |
| 219 | + if (newOneOfs.size() != schemas.size()) { |
| 220 | + // For safety reasons, this should never happen unless there is an error in the code |
| 221 | + throw new RuntimeException("oneOf size does not match the model"); |
| 222 | + } |
| 223 | + |
| 224 | + Map<String, String> refsMapping = Optional.ofNullable(model.getDiscriminator()) |
| 225 | + .map(Discriminator::getMapping).orElse(Collections.emptyMap()); |
| 226 | + |
| 227 | + // Reverse mapped references to use as baseName for oneOF, but different keys may point to the same $ref. |
| 228 | + // Thus, we group them by the value |
| 229 | + Map<String, List<String>> mappedNamesByRef = refsMapping.entrySet().stream() |
| 230 | + .collect(Collectors.groupingBy(Map.Entry::getValue, |
| 231 | + Collectors.mapping(Map.Entry::getKey, Collectors.toList()) |
| 232 | + )); |
| 233 | + |
| 234 | + for (int i = 0; i < newOneOfs.size(); i++) { |
| 235 | + CodegenProperty oneOf = newOneOfs.get(i); |
| 236 | + Schema schema = schemas.get(i); |
| 237 | + |
| 238 | + if (mappedNamesByRef.containsKey(schema.get$ref())) { |
| 239 | + // prefer mapped names if present |
| 240 | + // remove mapping not in order not to reuse for the next occurrence of the ref |
| 241 | + List<String> names = mappedNamesByRef.get(schema.get$ref()); |
| 242 | + String mappedName = names.remove(0); |
| 243 | + oneOf.setBaseName(mappedName); |
| 244 | + oneOf.setName(toModelName(mappedName)); |
| 245 | + } else if (!org.apache.commons.lang3.StringUtils.isEmpty(schema.get$ref())) { |
| 246 | + // use $ref if it's reference |
| 247 | + String refName = ModelUtils.getSimpleRef(schema.get$ref()); |
| 248 | + if (refName != null) { |
| 249 | + String modelName = toModelName(refName); |
| 250 | + oneOf.setName(modelName); |
| 251 | + oneOf.setBaseName(refName); |
| 252 | + } |
| 253 | + } else { |
| 254 | + // In-placed type (primitive), because there is no mapping or ref for it. |
| 255 | + // use camelized `title` if present, otherwise use `type` |
| 256 | + String oneOfName = Optional.ofNullable(schema.getTitle()).orElseGet(schema::getType); |
| 257 | + oneOf.setName(toModelName(oneOfName)); |
| 258 | + } |
| 259 | + } |
| 260 | + |
| 261 | + mdl.getComposedSchemas().setOneOf(newOneOfs); |
| 262 | + } |
| 263 | + |
| 264 | + return mdl; |
| 265 | + } |
| 266 | + |
208 | 267 | @Override
|
209 | 268 | public ModelsMap postProcessModels(ModelsMap objs) {
|
210 | 269 | // Remove the discriminator field from the model, serde will take care of this
|
211 | 270 | for (ModelMap model : objs.getModels()) {
|
212 | 271 | CodegenModel cm = model.getModel();
|
| 272 | + |
213 | 273 | if (cm.discriminator != null) {
|
214 | 274 | String reserved_var_name = cm.discriminator.getPropertyBaseName();
|
215 | 275 |
|
@@ -399,43 +459,9 @@ public String modelDocFileFolder() {
|
399 | 459 |
|
400 | 460 | @Override
|
401 | 461 | public String getTypeDeclaration(Schema p) {
|
| 462 | + // use unaliased schema for client-side |
402 | 463 | Schema unaliasSchema = unaliasSchema(p);
|
403 |
| - if (ModelUtils.isArraySchema(unaliasSchema)) { |
404 |
| - ArraySchema ap = (ArraySchema) unaliasSchema; |
405 |
| - Schema inner = ap.getItems(); |
406 |
| - if (inner == null) { |
407 |
| - LOGGER.warn("{}(array property) does not have a proper inner type defined.Default to string", |
408 |
| - ap.getName()); |
409 |
| - inner = new StringSchema().description("TODO default missing array inner type to string"); |
410 |
| - } |
411 |
| - return "Vec<" + getTypeDeclaration(inner) + ">"; |
412 |
| - } else if (ModelUtils.isMapSchema(unaliasSchema)) { |
413 |
| - Schema inner = ModelUtils.getAdditionalProperties(unaliasSchema); |
414 |
| - if (inner == null) { |
415 |
| - LOGGER.warn("{}(map property) does not have a proper inner type defined. Default to string", unaliasSchema.getName()); |
416 |
| - inner = new StringSchema().description("TODO default missing map inner type to string"); |
417 |
| - } |
418 |
| - return "::std::collections::HashMap<String, " + getTypeDeclaration(inner) + ">"; |
419 |
| - } |
420 |
| - |
421 |
| - // Not using the supertype invocation, because we want to UpperCamelize |
422 |
| - // the type. |
423 |
| - String schemaType = getSchemaType(unaliasSchema); |
424 |
| - if (typeMapping.containsKey(schemaType)) { |
425 |
| - return typeMapping.get(schemaType); |
426 |
| - } |
427 |
| - |
428 |
| - if (typeMapping.containsValue(schemaType)) { |
429 |
| - return schemaType; |
430 |
| - } |
431 |
| - |
432 |
| - if (languageSpecificPrimitives.contains(schemaType)) { |
433 |
| - return schemaType; |
434 |
| - } |
435 |
| - |
436 |
| - // return fully-qualified model name |
437 |
| - // crate::models::{{classnameFile}}::{{classname}} |
438 |
| - return "crate::models::" + toModelName(schemaType); |
| 464 | + return super.getTypeDeclaration(unaliasSchema); |
439 | 465 | }
|
440 | 466 |
|
441 | 467 | @Override
|
|
0 commit comments