Skip to content

Commit

Permalink
Support for discriminator.mapping (OpenAPITools#536)
Browse files Browse the repository at this point in the history
  • Loading branch information
0v1se authored and jmini committed Jul 18, 2018
1 parent 23bb25b commit e53a58e
Show file tree
Hide file tree
Showing 94 changed files with 1,149 additions and 307 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package org.openapitools.codegen;

import java.util.*;

public class CodegenDiscriminator {
private String propertyName;
private Map<String, String> mapping;
private Set<MappedModel> mappedModels = new LinkedHashSet<>();

public String getPropertyName() {
return propertyName;
}

public void setPropertyName(String propertyName) {
this.propertyName = propertyName;
}

public Map<String, String> getMapping() {
return mapping;
}

public void setMapping(Map<String, String> mapping) {
this.mapping = mapping;
}

public Set<MappedModel> getMappedModels() {
return mappedModels;
}

public void setMappedModels(Set<MappedModel> mappedModels) {
this.mappedModels = mappedModels;
}

public static class MappedModel {
private String mappingName;
private String modelName;

public MappedModel(String mappingName, String modelName) {
this.mappingName = mappingName;
this.modelName = modelName;
}

public String getMappingName() {
return mappingName;
}

public void setMappingName(String mappingName) {
this.mappingName = mappingName;
}

public String getModelName() {
return modelName;
}

public void setModelName(String modelName) {
this.modelName = modelName;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MappedModel that = (MappedModel) o;
return Objects.equals(mappingName, that.mappingName) &&
Objects.equals(modelName, that.modelName);
}

@Override
public int hashCode() {
return Objects.hash(mappingName, modelName);
}
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CodegenDiscriminator that = (CodegenDiscriminator) o;
return Objects.equals(propertyName, that.propertyName) &&
Objects.equals(mapping, that.mapping) &&
Objects.equals(mappedModels, that.mappedModels);
}

@Override
public int hashCode() {
return Objects.hash(propertyName, mapping, mappedModels);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,14 @@
package org.openapitools.codegen;

import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.media.Discriminator;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.Objects;

public class CodegenModel {
public String parent, parentSchema;
Expand All @@ -40,7 +39,7 @@ public class CodegenModel {
public String name, classname, title, description, classVarName, modelJson, dataType, xmlPrefix, xmlNamespace, xmlName;
public String classFilename; // store the class file name, mainly used for import
public String unescapedDescription;
public Discriminator discriminator;
public CodegenDiscriminator discriminator;
public String defaultValue;
public String arrayModelType;
public boolean isAlias; // Is this effectively an alias of another simple type
Expand Down Expand Up @@ -349,15 +348,15 @@ public void setUnescapedDescription(String unescapedDescription) {
this.unescapedDescription = unescapedDescription;
}

public Discriminator getDiscriminator() {
public CodegenDiscriminator getDiscriminator() {
return discriminator;
}

public String getDiscriminatorName() {
return discriminator == null ? null : discriminator.getPropertyName();
}

public void setDiscriminator(Discriminator discriminator) {
public void setDiscriminator(CodegenDiscriminator discriminator) {
this.discriminator = discriminator;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,15 @@
package org.openapitools.codegen;

import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.media.Discriminator;
import io.swagger.v3.oas.models.parameters.RequestBody;
import io.swagger.v3.oas.models.tags.Tag;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Arrays;

public class CodegenOperation {
public final List<CodegenProperty> responseHeaders = new ArrayList<CodegenProperty>();
Expand All @@ -40,7 +38,7 @@ public class CodegenOperation {
isRestful, isDeprecated;
public String path, operationId, returnType, httpMethod, returnBaseType,
returnContainer, summary, unescapedNotes, notes, baseName, defaultResponse;
public Discriminator discriminator;
public CodegenDiscriminator discriminator;
public List<Map<String, String>> consumes, produces, prioritizedContentTypes;
public CodegenParameter bodyParam;
public List<CodegenParameter> allParams = new ArrayList<CodegenParameter>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.examples.Example;
import io.swagger.v3.oas.models.headers.Header;
import io.swagger.v3.oas.models.media.*;
import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.ComposedSchema;
import io.swagger.v3.oas.models.media.Content;
import io.swagger.v3.oas.models.media.MediaType;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.media.StringSchema;
import io.swagger.v3.oas.models.parameters.CookieParameter;
import io.swagger.v3.oas.models.parameters.HeaderParameter;
import io.swagger.v3.oas.models.parameters.Parameter;
Expand All @@ -43,6 +48,7 @@
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.CodegenDiscriminator.MappedModel;
import org.openapitools.codegen.examples.ExampleGenerator;
import org.openapitools.codegen.serializer.SerializerUtils;
import org.openapitools.codegen.utils.ModelUtils;
Expand All @@ -66,6 +72,7 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class DefaultCodegen implements CodegenConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultCodegen.class);
Expand Down Expand Up @@ -1469,6 +1476,10 @@ public CodegenModel fromModel(String name, Schema schema, Map<String, Schema> al

// unalias schema
schema = ModelUtils.unaliasSchema(allDefinitions, schema);
if (schema == null) {
LOGGER.warn("Schema {} not found", name);
return null;
}

CodegenModel m = CodegenModelFactory.newInstance(CodegenModelType.MODEL);

Expand All @@ -1489,7 +1500,7 @@ public CodegenModel fromModel(String name, Schema schema, Map<String, Schema> al
m.getVendorExtensions().putAll(schema.getExtensions());
}
m.isAlias = typeAliases.containsKey(name);
m.discriminator = schema.getDiscriminator();
m.discriminator = createDiscriminator(name, schema, allDefinitions);

if (schema.getXml() != null) {
m.xmlPrefix = schema.getXml().getPrefix();
Expand All @@ -1516,7 +1527,7 @@ public CodegenModel fromModel(String name, Schema schema, Map<String, Schema> al
int modelImplCnt = 0; // only one inline object allowed in a ComposedModel
for (Schema innerModel : composed.getAllOf()) {
if (m.discriminator == null) {
m.discriminator = schema.getDiscriminator();
m.discriminator = createDiscriminator(name, schema, allDefinitions);
}
if (innerModel.getXml() != null) {
m.xmlPrefix = innerModel.getXml().getPrefix();
Expand Down Expand Up @@ -1631,6 +1642,34 @@ public CodegenModel fromModel(String name, Schema schema, Map<String, Schema> al
return m;
}

private CodegenDiscriminator createDiscriminator(String schemaName, Schema schema, Map<String, Schema> allDefinitions) {
if(schema.getDiscriminator() == null) {
return null;
}
CodegenDiscriminator discriminator = new CodegenDiscriminator();
discriminator.setPropertyName(schema.getDiscriminator().getPropertyName());
discriminator.setMapping(schema.getDiscriminator().getMapping());
if(schema.getDiscriminator().getMapping() != null && !schema.getDiscriminator().getMapping().isEmpty()) {
for (Entry<String, String> e : schema.getDiscriminator().getMapping().entrySet()) {
String name = ModelUtils.getSimpleRef(e.getValue());
discriminator.getMappedModels().add(new MappedModel(e.getKey(), name));
}
} else {
allDefinitions.forEach((childName, child) -> {
if (child instanceof ComposedSchema && ((ComposedSchema) child).getAllOf() != null) {
Set<String> parentSchemas = ((ComposedSchema) child).getAllOf().stream()
.filter(s -> s.get$ref() != null)
.map(s -> ModelUtils.getSimpleRef(s.get$ref()))
.collect(Collectors.toSet());
if (parentSchemas.contains(schemaName)) {
discriminator.getMappedModels().add(new MappedModel(childName, childName));
}
}
});
}
return discriminator;
}

protected void addAdditionPropertiesToCodeGenModel(CodegenModel codegenModel, Schema schema) {
addParentContainer(codegenModel, codegenModel.name, schema);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -523,25 +523,6 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
}
}

@SuppressWarnings("unchecked")
@Override
public Map<String, Object> postProcessAllModels(Map<String, Object> objs) {
Map<String, Object> allProcessedModels = super.postProcessAllModels(objs);
if (!additionalProperties.containsKey("gsonFactoryMethod")) {
List<Object> allModels = new ArrayList<Object>();
for (String name : allProcessedModels.keySet()) {
Map<String, Object> models = (Map<String, Object>) allProcessedModels.get(name);
try {
allModels.add(((List<Object>) models.get("models")).get(0));
} catch (Exception e) {
e.printStackTrace();
}
}
additionalProperties.put("parent", modelInheritanceSupportInGson(allModels));
}
return allProcessedModels;
}

@Override
public Map<String, Object> postProcessModelsEnum(Map<String, Object> objs) {
objs = super.postProcessModelsEnum(objs);
Expand All @@ -564,34 +545,6 @@ public Map<String, Object> postProcessModelsEnum(Map<String, Object> objs) {
return objs;
}

public static List<Map<String, Object>> modelInheritanceSupportInGson(List<?> allModels) {
Map<CodegenModel, List<CodegenModel>> byParent = new LinkedHashMap<>();
for (Object model : allModels) {
Map entry = (Map) model;
CodegenModel parent = ((CodegenModel)entry.get("model")).parentModel;
if(null!= parent) {
byParent.computeIfAbsent(parent, k -> new LinkedList<>()).add((CodegenModel)entry.get("model"));
}
}
List<Map<String, Object>> parentsList = new ArrayList<>();
for (CodegenModel parentModel : byParent.keySet()) {
List<Map<String, Object>> childrenList = new ArrayList<>();
Map<String, Object> parent = new HashMap<>();
parent.put("classname", parentModel.classname);
List<CodegenModel> childrenModels = byParent.get(parentModel);
for (CodegenModel model : childrenModels) {
Map<String, Object> child = new HashMap<>();
child.put("name", model.name);
child.put("classname", model.classname);
childrenList.add(child);
}
parent.put("children", childrenList);
parent.put("discriminator", parentModel.discriminator);
parentsList.add(parent);
}
return parentsList;
}

public void setUseRxJava(boolean useRxJava) {
this.useRxJava = useRxJava;
doNotUseRx = false;
Expand Down
13 changes: 6 additions & 7 deletions modules/openapi-generator/src/main/resources/Java/JSON.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -60,21 +60,20 @@ public class JSON {

public static GsonBuilder createGson() {
GsonFireBuilder fireBuilder = new GsonFireBuilder()
{{#parent}}
.registerTypeSelector({{classname}}.class, new TypeSelector() {
{{#models}}{{#model}}{{#discriminator}} .registerTypeSelector({{classname}}.class, new TypeSelector() {
@Override
public Class getClassForElement(JsonElement readElement) {
Map classByDiscriminatorValue = new HashMap();
{{#children}}
classByDiscriminatorValue.put("{{name}}".toUpperCase(), {{classname}}.class);
{{/children}}
{{#mappedModels}}
classByDiscriminatorValue.put("{{mappingName}}".toUpperCase(), {{modelName}}.class);
{{/mappedModels}}
classByDiscriminatorValue.put("{{classname}}".toUpperCase(), {{classname}}.class);
return getClassByDiscriminator(
classByDiscriminatorValue,
getDiscriminatorValue(readElement, "{{{discriminatorName}}}"));
getDiscriminatorValue(readElement, "{{{propertyName}}}"));
}
})
{{/parent}}
{{/discriminator}}{{/model}}{{/models}}
;
GsonBuilder builder = fireBuilder.createGsonBuilder();
{{#disableHtmlEscaping}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,20 @@ public class JSON {

public static GsonBuilder createGson() {
GsonFireBuilder fireBuilder = new GsonFireBuilder()
{{#parent}}
.registerTypeSelector({{classname}}.class, new TypeSelector() {
{{#models}}{{#model}}{{#discriminator}} .registerTypeSelector({{classname}}.class, new TypeSelector() {
@Override
public Class getClassForElement(JsonElement readElement) {
Map classByDiscriminatorValue = new HashMap();
{{#children}}
classByDiscriminatorValue.put("{{name}}".toUpperCase(), {{classname}}.class);
{{/children}}
{{#mappedModels}}
classByDiscriminatorValue.put("{{mappingName}}".toUpperCase(), {{modelName}}.class);
{{/mappedModels}}
classByDiscriminatorValue.put("{{classname}}".toUpperCase(), {{classname}}.class);
return getClassByDiscriminator(
classByDiscriminatorValue,
getDiscriminatorValue(readElement, "{{{discriminatorName}}}"));
getDiscriminatorValue(readElement, "{{{propertyName}}}"));
}
})
{{/parent}}
{{/discriminator}}{{/model}}{{/models}}
;
return fireBuilder.createGsonBuilder();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{{#jackson}}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "{{{discriminatorName}}}", visible = true )

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "{{{discriminatorName}}}", visible = true)
@JsonSubTypes({
{{#children}}
@JsonSubTypes.Type(value = {{classname}}.class, name = "{{^vendorExtensions.x-discriminator-value}}{{name}}{{/vendorExtensions.x-discriminator-value}}{{#vendorExtensions.x-discriminator-value}}{{{vendorExtensions.x-discriminator-value}}}{{/vendorExtensions.x-discriminator-value}}"),
{{/children}}
{{#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}}
}){{/jackson}}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{{#jackson}}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "{{{discriminatorName}}}", visible = true )

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "{{{discriminatorName}}}", visible = true)
@JsonSubTypes({
{{#children}}
@JsonSubTypes.Type(value = {{classname}}.class, name = "{{^vendorExtensions.x-discriminator-value}}{{name}}{{/vendorExtensions.x-discriminator-value}}{{#vendorExtensions.x-discriminator-value}}{{{vendorExtensions.x-discriminator-value}}}{{/vendorExtensions.x-discriminator-value}}"),
{{/children}}
{{#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}}
}){{/jackson}}
Loading

0 comments on commit e53a58e

Please sign in to comment.