Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
6a8769e
Fix OpenAPITools#5381
codermoderlife Mar 21, 2020
049359c
Fix OpenAPITools#5381
codermoderlife Mar 22, 2020
49f13eb
Fix OpenAPITools#5381
codermoderlife Mar 22, 2020
1a5a484
Fix OpenAPITools#5381
codermoderlife Mar 22, 2020
66a09d2
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
codermoderlife Mar 22, 2020
48a1a4a
Fix OpenAPITools#5381
codermoderlife Mar 24, 2020
a811330
Fix OpenAPITools#5381
codermoderlife Mar 24, 2020
299cdb3
Fix OpenAPITools#5381
codermoderlife Mar 24, 2020
461cbc8
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
codermoderlife Mar 24, 2020
dd0118d
Merge branch 'master' of https://github.com/OpenAPITools/openapi-gene…
codermoderlife Mar 25, 2020
26a95f6
Fix OpenAPITools#5381
codermoderlife Mar 25, 2020
9af7db6
Fix OpenAPITools#5381
codermoderlife Mar 30, 2020
fbfd57d
Fix OpenAPITools#5381
codermoderlife Mar 21, 2020
bfab304
Fix OpenAPITools#5381
codermoderlife Mar 22, 2020
29003d8
Fix OpenAPITools#5381
codermoderlife Apr 1, 2020
d864831
Fix OpenAPITools#5381
codermoderlife Apr 1, 2020
6d54799
Fix OpenAPITools#5381
codermoderlife Apr 2, 2020
c6a5c6b
Merge remote-tracking branch 'super/master' into spring_fix_5381_jb
jburgess Dec 1, 2020
d96cd2e
Merge remote-tracking branch 'super/master' into spring_fix_5381_jb
jburgess Dec 3, 2020
8f09f52
Initial merge of 5.0
jburgess Dec 3, 2020
0d31df4
Aligned with master formatting
jburgess Dec 3, 2020
397e711
Corrected spacing for class names to align with samples.
jburgess Dec 4, 2020
a922217
Merge remote-tracking branch 'source/master' into spring_fix_5381_jb
jburgess Dec 5, 2020
21a98e5
Merge remote-tracking branch 'source/master' into spring_fix_5381_jb
jburgess Aug 11, 2021
1b5964e
Merge remote-tracking branch 'source/master' into spring_fix_5381_jb
jburgess Aug 11, 2021
05105fa
Merged master
jburgess Aug 11, 2021
c89a28b
Updated samples
jburgess Aug 11, 2021
a7bae4e
TAP-232 OneOf fixes
Aug 30, 2021
51e9815
TAP-232 Added tests for issues 2906 and 8647
Sep 10, 2021
302da03
Merge branch 'master' into feature/TAP-232/oneof-fixes
Orachigami Sep 13, 2021
4808e87
Merge branch 'spring_fix_5381_jb' of https://github.com/jburgess/open…
wing328 Sep 14, 2021
2979c38
TAP-232 Fixed inline OneOf, added tests for the majority of cases, ad…
Sep 17, 2021
7358de9
TAP-232 Restart CI builds
Sep 20, 2021
8a1cf1e
TAP-232 Removed unused imports, fixed OneOf generation in response sc…
Sep 20, 2021
790771e
Merge branch 'jburgess-spring_fix_5381_jb' into feature/TAP-232/oneof…
Orachigami Sep 20, 2021
a1cac51
TAP-232 Removed code duplicate
Sep 21, 2021
def7ca4
Merge branch 'master' into feature/TAP-232/oneof-fixes
Orachigami Sep 21, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,7 @@ public void postProcessParameter(CodegenParameter parameter) {
@Override
@SuppressWarnings("unused")
public void preprocessOpenAPI(OpenAPI openAPI) {
if (useOneOfInterfaces) {
if (useOneOfInterfaces && openAPI.getComponents() != null) {
// we process the openapi schema here to find oneOf schemas and create interface models for them
Map<String, Schema> schemas = new HashMap<String, Schema>(openAPI.getComponents().getSchemas());
if (schemas == null) {
Expand Down Expand Up @@ -2424,6 +2424,18 @@ public CodegenModel fromModel(String name, Schema schema) {
m.isAlias = (typeAliases.containsKey(name)
|| isAliasOfSimpleTypes(schema)); // check if the unaliased schema is an alias of simple OAS types
m.setDiscriminator(createDiscriminator(name, schema, this.openAPI));
if (ModelUtils.isComposedSchema(schema)
&& m.discriminator == null
&& schema.getExtensions() != null
&& schema.getExtensions().containsKey("x-one-of-name")) {
m.vendorExtensions.put("x-deduction", true);
List<String> deductionModelNames = new ArrayList<>();
((ComposedSchema) schema).getOneOf().forEach(model -> {
String modelName = ModelUtils.getSimpleRef(model.get$ref());
deductionModelNames.add(toModelName(modelName));
});
m.vendorExtensions.put("x-deduction-model-names", deductionModelNames);
}
if (!this.getLegacyDiscriminatorBehavior()) {
m.addDiscriminatorMappedModelsImports();
}
Expand Down Expand Up @@ -3165,7 +3177,7 @@ protected CodegenDiscriminator createDiscriminator(String schemaName, Schema sch
}
}
// if there are composed oneOf/anyOf schemas, add them to this discriminator
if (ModelUtils.isComposedSchema(schema) && !this.getLegacyDiscriminatorBehavior()) {
if (ModelUtils.isComposedSchema(schema)) {
List<MappedModel> otherDescendants = getOneOfAnyOfDescendants(schemaName, discPropName, (ComposedSchema) schema, openAPI);
for (MappedModel otherDescendant : otherDescendants) {
if (!uniqueDescendants.contains(otherDescendant)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import java.util.regex.Pattern;
import java.util.stream.Stream;

import io.swagger.v3.oas.models.responses.ApiResponse;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
Expand Down Expand Up @@ -81,24 +82,9 @@
import io.swagger.v3.oas.models.parameters.RequestBody;
import io.swagger.v3.oas.models.servers.Server;
import io.swagger.v3.parser.util.SchemaTypeUtil;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.*;
import org.openapitools.codegen.meta.features.*;
import org.openapitools.codegen.utils.ModelUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Stream;

import static org.openapitools.codegen.utils.StringUtils.*;

public abstract class AbstractJavaCodegen extends DefaultCodegen implements CodegenConfig {

Expand Down Expand Up @@ -1319,6 +1305,16 @@ public Map<String, Object> postProcessModels(Map<String, Object> objs) {
}
}

// add implements for serializable/parcelable to all models
List<Map<String, Object>> models = (List<Map<String, Object>>) objs.get("models");
for (Map<String, Object> mo : models) {
CodegenModel cm = (CodegenModel) mo.get("model");
if (this.serializableModel) {
cm.getVendorExtensions().putIfAbsent("x-implements", new ArrayList<String>());
((ArrayList<String>) cm.getVendorExtensions().get("x-implements")).add("Serializable");
}
}

return postProcessModelsEnum(objs);
}

Expand Down Expand Up @@ -1363,8 +1359,23 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
}
for (Operation operation : path.readOperations()) {
LOGGER.info("Processing operation {}", operation.getOperationId());
if (hasBodyParameter(openAPI, operation) || hasFormParameter(openAPI, operation)) {
String defaultContentType = hasFormParameter(openAPI, operation) ? "application/x-www-form-urlencoded" : "application/json";
boolean hasBodyParameter = hasBodyParameter(openAPI, operation);
boolean hasFormParameter = hasFormParameter(openAPI, operation);

// OpenAPI parser do not add Inline One Of models in Operations to Components/Schemas
if (hasBodyParameter) {
Optional.ofNullable(operation.getRequestBody())
.map(RequestBody::getContent)
.ifPresent(this::repairInlineOneOf);
}
if (operation.getResponses() != null) {
operation.getResponses().values().stream().map(ApiResponse::getContent)
.filter(Objects::nonNull)
.forEach(this::repairInlineOneOf);
}

if (hasBodyParameter || hasFormParameter) {
String defaultContentType = hasFormParameter ? "application/x-www-form-urlencoded" : "application/json";
List<String> consumes = new ArrayList<>(getConsumesInfo(openAPI, operation));
String contentType = consumes == null || consumes.isEmpty() ? defaultContentType : consumes.get(0);
operation.addExtension("x-contentType", contentType);
Expand Down Expand Up @@ -1421,6 +1432,33 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
}
}


/**
* Add all OneOf schemas to #/components/schemas and replace them in the original content by ref schema
*
* OpenAPI Parser does not add inline OneOf schemas to models to generate
*
* @param content a 'content' section in the OAS specification.
*/
private void repairInlineOneOf(final Content content) {
content.values().forEach(mediaType -> {
final Schema replacingSchema = mediaType.getSchema();
if (isOneOfSchema(replacingSchema)) {
final String oneOfModelName = (String) replacingSchema.getExtensions().get("x-one-of-name");
final Schema newRefSchema = new Schema<>().$ref("#/components/schemas/" + oneOfModelName);
mediaType.setSchema(newRefSchema);
ModelUtils.getSchemas(openAPI).put(oneOfModelName, replacingSchema);
}
});
}

private static boolean isOneOfSchema(final Schema schema) {
return schema instanceof ComposedSchema
&& ((ComposedSchema) schema).getProperties() == null
&& Optional.ofNullable(schema.getExtensions()).map(m -> m.containsKey("x-one-of-name"))
.orElse(false);
}

private static String getAccept(OpenAPI openAPI, Operation operation) {
String accepts = null;
String defaultContentType = "application/json";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ public JavaClientCodegen() {
artifactId = "openapi-java-client";
apiPackage = "org.openapitools.client.api";
modelPackage = "org.openapitools.client.model";
useOneOfInterfaces = true;
addOneOfInterfaceImports = true;

// cliOptions default redefinition need to be updated
updateOption(CodegenConstants.INVOKER_PACKAGE, this.getInvokerPackage());
Expand Down Expand Up @@ -1027,11 +1029,13 @@ public String toApiVarName(String name) {

@Override
public void addImportsToOneOfInterface(List<Map<String, String>> imports) {
for (String i : Arrays.asList("JsonSubTypes", "JsonTypeInfo")) {
Map<String, String> oneImport = new HashMap<>();
oneImport.put("import", importMapping.get(i));
if (!imports.contains(oneImport)) {
imports.add(oneImport);
if (additionalProperties.containsKey(JACKSON)) {
for (String i : Arrays.asList("JsonSubTypes", "JsonTypeInfo")) {
Map<String, String> oneImport = new HashMap<>();
oneImport.put("import", importMapping.get(i));
if (!imports.contains(oneImport)) {
imports.add(oneImport);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ public SpringCodegen() {
modelPackage = "org.openapitools.model";
invokerPackage = "org.openapitools.api";
artifactId = "openapi-spring";
useOneOfInterfaces = true;
addOneOfInterfaceImports = true;

// clioOptions default redefinition need to be updated
updateOption(CodegenConstants.INVOKER_PACKAGE, this.getInvokerPackage());
Expand Down Expand Up @@ -233,7 +235,7 @@ public void processOpts() {
}

super.processOpts();

useOneOfInterfaces = true;
// clear model and api doc template as this codegen
// does not support auto-generated markdown doc at the moment
//TODO: add doc templates
Expand Down Expand Up @@ -868,6 +870,19 @@ public Map<String, Object> postProcessModelsEnum(Map<String, Object> objs) {
return objs;
}

@Override
public void addImportsToOneOfInterface(List<Map<String, String>> imports) {
if (additionalProperties.containsKey(JACKSON)) {
for (String i : Arrays.asList("JsonSubTypes", "JsonTypeInfo")) {
Map<String, String> oneImport = new HashMap<>();
oneImport.put("import", importMapping.get(i));
if (!imports.contains(oneImport)) {
imports.add(oneImport);
}
}
}
}

public void setUseBeanValidation(boolean useBeanValidation) {
this.useBeanValidation = useBeanValidation;
}
Expand All @@ -880,4 +895,25 @@ public void setPerformBeanValidation(boolean performBeanValidation) {
public void setUseOptional(boolean useOptional) {
this.useOptional = useOptional;
}

@Override
public void postProcessParameter(CodegenParameter p) {
// we use a custom version of this function to remove the l, d, and f suffixes from Long/Double/Float
// defaultValues
// remove the l because our users will use Long.parseLong(String defaultValue)
// remove the d because our users will use Double.parseDouble(String defaultValue)
// remove the f because our users will use Float.parseFloat(String defaultValue)
// NOTE: for CodegenParameters we DO need these suffixes because those defaultValues are used as java value
// literals assigned to Long/Double/Float
if (p.defaultValue == null) {
return;
}
Boolean fixLong = (p.isLong && "l".equals(p.defaultValue.substring(p.defaultValue.length()-1)));
Boolean fixDouble = (p.isDouble && "d".equals(p.defaultValue.substring(p.defaultValue.length()-1)));
Boolean fixFloat = (p.isFloat && "f".equals(p.defaultValue.substring(p.defaultValue.length()-1)));
if (fixLong || fixDouble || fixFloat) {
p.defaultValue = p.defaultValue.substring(0, p.defaultValue.length()-1);
}
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{>typeInfoAnnotation}}{{>xmlAnnotation}}
public interface {{classname}} {{#vendorExtensions.x-implements}}{{#-first}}extends {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} {
{{#discriminator}}
{{^vendorExtensions.x-deduction}}{{#discriminator}}
public {{propertyType}} {{propertyGetter}}();
{{/discriminator}}
{{/discriminator}}{{/vendorExtensions.x-deduction}}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
{{#jackson}}

{{^vendorExtensions.x-deduction}}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "{{{discriminator.propertyBaseName}}}", visible = true)
{{/vendorExtensions.x-deduction}}{{#vendorExtensions.x-deduction}}
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION)
@JsonSubTypes({
{{#vendorExtensions.x-deduction-model-names}}
@JsonSubTypes.Type(value = {{.}}.class, name = "{{.}}"),
{{/vendorExtensions.x-deduction-model-names}}
})
{{/vendorExtensions.x-deduction}}
{{#discriminator.mappedModels}}
{{#-first}}
@JsonSubTypes({
Expand All @@ -13,4 +22,4 @@
{{#isClassnameSanitized}}
@JsonTypeName("{{name}}")
{{/isClassnameSanitized}}
{{/jackson}}
{{/jackson}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{>typeInfoAnnotation}}{{>xmlAnnotation}}
public interface {{classname}} {{#vendorExtensions.x-implements}}{{#-first}}extends {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} {
{{^vendorExtensions.x-deduction}}{{#discriminator}}
public {{propertyType}} {{propertyGetter}}();
{{/discriminator}}{{/vendorExtensions.x-deduction}}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import org.springframework.hateoas.RepresentationModel;
{{>enumOuterClass}}
{{/isEnum}}
{{^isEnum}}
{{>pojo}}
{{#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}}
{{/isEnum}}
{{/model}}
{{/models}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{>typeInfoAnnotation}}{{>xmlAnnotation}}
public interface {{classname}} {{#vendorExtensions.x-implements}}{{#-first}}extends {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{/vendorExtensions.x-implements}} {
{{^vendorExtensions.x-deduction}}{{#discriminator}}
public {{propertyType}} {{propertyGetter}}();
{{/discriminator}}{{/vendorExtensions.x-deduction}}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
*/{{#description}}
@ApiModel(description = "{{{.}}}"){{/description}}
{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}}{{>additionalModelTypeAnnotations}}
public class {{classname}} {{#parent}}extends {{{.}}}{{/parent}}{{^parent}}{{#hateoas}}extends RepresentationModel<{{classname}}> {{/hateoas}}{{/parent}} {{#serializableModel}}implements Serializable{{/serializableModel}} {
public class {{classname}} {{#parent}}extends {{{.}}} {{/parent}}{{^parent}}{{#hateoas}}extends RepresentationModel<{{classname}}> {{/hateoas}}{{/parent}}{{#vendorExtensions.x-implements}}{{#-first}}implements {{{.}}}{{/-first}}{{^-first}}, {{{.}}}{{/-first}}{{#-last}} {{/-last}}{{/vendorExtensions.x-implements}}{
{{#serializableModel}}
private static final long serialVersionUID = 1L;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
{{#jackson}}

{{^vendorExtensions.x-deduction}}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "{{{discriminator.propertyBaseName}}}", visible = true)
{{/vendorExtensions.x-deduction}}{{#vendorExtensions.x-deduction}}
@JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION){{/vendorExtensions.x-deduction}}
@JsonSubTypes({
{{#discriminator.mappedModels}}
@JsonSubTypes.Type(value = {{modelName}}.class, name = "{{^vendorExtensions.x-discriminator-value}}{{mappingName}}{{/vendorExtensions.x-discriminator-value}}{{#vendorExtensions.x-discriminator-value}}{{{vendorExtensions.x-discriminator-value}}}{{/vendorExtensions.x-discriminator-value}}"),
{{/discriminator.mappedModels}}
{{#vendorExtensions.x-deduction-model-names}}
@JsonSubTypes.Type(value = {{.}}.class, name = "{{.}}"),
{{/vendorExtensions.x-deduction-model-names}}
}){{/jackson}}
Original file line number Diff line number Diff line change
Expand Up @@ -1137,10 +1137,15 @@ public void testComposedSchemaAllOfDiscriminatorMapLegacy() {
Assert.assertNull(reptile.discriminator);

// the MyPets discriminator contains Cat and Lizard
List<String> myPetsModelNames = Arrays.asList("Cat", "Lizard");
CodegenDiscriminator myPetDisc = new CodegenDiscriminator();
myPetDisc.setPropertyName(propertyName);
myPetDisc.setPropertyBaseName(propertyBaseName);
hs.clear();
for (String myPetsModelName: myPetsModelNames) {
hs.add(new CodegenDiscriminator.MappedModel(myPetsModelName, codegen.toModelName(myPetsModelName)));
}
myPetDisc.setMappedModels(hs);
modelName = "MyPets";
sc = openAPI.getComponents().getSchemas().get(modelName);
CodegenModel myPets = codegen.fromModel(modelName, sc);
Expand Down
Loading