Skip to content

Commit 6a8769e

Browse files
committed
added x-is-one-of-interface extension for oneOf interface in mustache template
1 parent 47e24af commit 6a8769e

File tree

3 files changed

+130
-3
lines changed

3 files changed

+130
-3
lines changed

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

Lines changed: 123 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
import io.swagger.v3.oas.models.OpenAPI;
2222
import io.swagger.v3.oas.models.Operation;
2323
import io.swagger.v3.oas.models.PathItem;
24+
import io.swagger.v3.oas.models.media.ComposedSchema;
25+
import io.swagger.v3.oas.models.media.Schema;
26+
import io.swagger.v3.oas.models.parameters.RequestBody;
27+
import org.apache.commons.lang3.StringUtils;
2428
import org.apache.commons.lang3.tuple.Pair;
2529
import org.openapitools.codegen.*;
2630
import org.openapitools.codegen.languages.features.BeanValidationFeatures;
@@ -29,6 +33,8 @@
2933
import org.openapitools.codegen.meta.features.*;
3034
import org.openapitools.codegen.templating.mustache.SplitStringLambda;
3135
import org.openapitools.codegen.templating.mustache.TrimWhitespaceLambda;
36+
import org.openapitools.codegen.utils.ModelUtils;
37+
import org.openapitools.codegen.utils.OneOfImplementorAdditionalData;
3238
import org.openapitools.codegen.utils.URLPathUtils;
3339
import org.slf4j.Logger;
3440
import org.slf4j.LoggerFactory;
@@ -233,7 +239,7 @@ public void processOpts() {
233239
}
234240

235241
super.processOpts();
236-
242+
useOneOfInterfaces = true;
237243
// clear model and api doc template as this codegen
238244
// does not support auto-generated markdown doc at the moment
239245
//TODO: add doc templates
@@ -523,6 +529,58 @@ public void addOperationToGroup(String tag, String resourcePath, Operation opera
523529
}
524530
}
525531

532+
@Override
533+
public void addOneOfInterfaceModel(ComposedSchema cs, String name) {
534+
CodegenModel codegenModel = new CodegenModel();
535+
536+
for (Schema o : cs.getOneOf()) {
537+
codegenModel.oneOf.add(toModelName(ModelUtils.getSimpleRef(o.get$ref())));
538+
}
539+
codegenModel.name = name;
540+
codegenModel.classname = name;
541+
codegenModel.vendorExtensions.put("isOneOfInterface", true);
542+
codegenModel.discriminator = createDiscriminator("", (Schema) cs);
543+
codegenModel.interfaceModels = new ArrayList<CodegenModel>();
544+
545+
for(Schema schema : cs.getOneOf()){
546+
String[] split = schema.get$ref().split("/");
547+
String singleSchemaType = split[split.length-1];
548+
CodegenProperty codegenProperty = fromProperty(singleSchemaType, schema);
549+
codegenProperty.setBaseName(singleSchemaType.toLowerCase(Locale.getDefault()));
550+
codegenModel.vars.add(codegenProperty);
551+
}
552+
addOneOfInterfaces.add(codegenModel);
553+
}
554+
555+
@Override
556+
public CodegenParameter fromRequestBody(RequestBody body, Set<String> imports, String bodyParameterName) {
557+
CodegenParameter codegenParameter = super.fromRequestBody(body, imports, bodyParameterName);
558+
Schema schema = ModelUtils.getSchemaFromRequestBody(body);
559+
CodegenProperty codegenProperty = fromProperty("property", schema);
560+
561+
List<String> oneOfClassNames = new ArrayList<>();
562+
if (codegenProperty != null && codegenProperty.getComplexType() != null && schema instanceof ComposedSchema) {
563+
// will be set with imports.add(codegenParameter.baseType); in defaultcodegen
564+
imports.clear();
565+
ComposedSchema composedSchema = (ComposedSchema) schema;
566+
for(Schema oneOfSchema: composedSchema.getOneOf()){
567+
String[] split = oneOfSchema.get$ref().split("/");
568+
oneOfClassNames.add(split[split.length - 1]);
569+
}
570+
String codegenModelName = createOneOfClassName(oneOfClassNames);
571+
imports.add(codegenModelName);
572+
codegenParameter.baseName = codegenModelName;
573+
codegenParameter.paramName = toParamName(codegenParameter.baseName);
574+
codegenParameter.baseType = codegenParameter.baseName;
575+
codegenParameter.dataType = getTypeDeclaration(codegenModelName);
576+
codegenParameter.description = codegenProperty.getDescription();
577+
codegenProperty.setComplexType(codegenModelName);
578+
codegenProperty.setBaseName(codegenModelName);
579+
codegenProperty.setDatatype(codegenModelName);
580+
}
581+
return codegenParameter;
582+
}
583+
526584
@Override
527585
public void preprocessOpenAPI(OpenAPI openAPI) {
528586
super.preprocessOpenAPI(openAPI);
@@ -629,6 +687,57 @@ public void setReturnContainer(final String returnContainer) {
629687
return objs;
630688
}
631689

690+
@Override
691+
public Map<String, Object> postProcessAllModels(Map<String, Object> objs) {
692+
super.postProcessAllModels(objs);
693+
Map<String, OneOfImplementorAdditionalData> additionalDataMap = new HashMap<>();
694+
for (Map.Entry modelsEntry : objs.entrySet()) {
695+
Map<String, Object> modelsAttrs = (Map<String, Object>) modelsEntry.getValue();
696+
List<Object> models = (List<Object>) modelsAttrs.get("models");
697+
List<Map<String, String>> modelsImports = (List<Map<String, String>>) modelsAttrs
698+
.getOrDefault("imports", new ArrayList<Map<String, String>>());
699+
for (Object _mo : models) {
700+
Map<String, Object> mo = (Map<String, Object>) _mo;
701+
CodegenModel cm = (CodegenModel) mo.get("model");
702+
if (cm.oneOf.size() > 0) {
703+
cm.vendorExtensions.put("isOneOfInterface", true);
704+
// if this is oneOf interface, make sure we include the necessary jackson imports for it
705+
for (String classToImport : Arrays
706+
.asList("JsonTypeInfo", "JsonSubTypes", "JsonProperty",
707+
"ApiModelProperty")) {
708+
Map<String, String> i = new HashMap<String, String>() {{
709+
put("import", importMapping.get(classToImport));
710+
}};
711+
if (!modelsImports.contains(i)) {
712+
modelsImports.add(i);
713+
}
714+
}
715+
List<String> oneOfClassNames = new ArrayList<>();
716+
717+
for (String one : cm.oneOf) {
718+
if (!additionalDataMap.containsKey(one)) {
719+
additionalDataMap.put(one, new OneOfImplementorAdditionalData(one));
720+
additionalDataMap.get(one).addFromInterfaceModel(cm, modelsImports);
721+
}
722+
oneOfClassNames.add(one);
723+
}
724+
String codegenModelName = createOneOfClassName(oneOfClassNames);
725+
cm.name = codegenModelName;
726+
cm.classname = codegenModelName;
727+
Object value = modelsEntry.getValue();
728+
objs.remove(modelsEntry.getKey());
729+
objs.put(codegenModelName, value);
730+
}
731+
}
732+
}
733+
return objs;
734+
}
735+
736+
private String createOneOfClassName(List<String> oneOfClassNames) {
737+
oneOfClassNames.sort(String::compareToIgnoreCase);
738+
return "OneOf" + StringUtils.join(oneOfClassNames, "");
739+
}
740+
632741
private interface DataTypeAssigner {
633742
void setReturnType(String returnType);
634743

@@ -898,4 +1007,16 @@ public void postProcessParameter(CodegenParameter p) {
8981007
}
8991008
}
9001009

901-
}
1010+
@Override
1011+
public void addImportsToOneOfInterface(List<Map<String, String>> imports) {
1012+
for (String i : Arrays.asList("JsonSubTypes", "JsonTypeInfo")) {
1013+
Map<String, String> oneImport = new HashMap<String, String>() {{
1014+
put("import", importMapping.get(i));
1015+
}};
1016+
if (!imports.contains(oneImport)) {
1017+
imports.add(oneImport);
1018+
}
1019+
}
1020+
}
1021+
1022+
}

modules/openapi-generator/src/main/resources/JavaSpring/model.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import org.springframework.hateoas.RepresentationModel;
3535
{{>enumOuterClass}}
3636
{{/isEnum}}
3737
{{^isEnum}}
38-
{{>pojo}}
38+
{{#vendorExtensions.x-is-one-of-interface}}{{>oneof_interface}}{{/vendorExtensions.x-is-one-of-interface}}{{^vendorExtensions.x-is-one-of-interface}}{{>pojo}}{{/vendorExtensions.x-is-one-of-interface}}
3939
{{/isEnum}}
4040
{{/model}}
4141
{{/models}}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{>typeInfoAnnotation}}{{>xmlAnnotation}}
2+
public interface {{classname}} {{#vendorExtensions.x-implements}}{{#-first}}extends {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} {
3+
{{#discriminator}}
4+
public {{propertyType}} {{propertyGetter}}();
5+
{{/discriminator}}
6+
}

0 commit comments

Comments
 (0)