[dart-dio] Fix non legacy discriminator behavior (#14291)

* override createDiscriminator

* assign discriminator = null to remove duplicates

* added discriminatorValue extension

* added _defaults

* formatting

* samples

* use gitter instead

* remove comment

* updated samples

* revert formatting changes

* update samples

* change file permissions

* remove discriminator check for anyOf

* add comment to createDiscriminator
This commit is contained in:
Ahmed Fwela
2023-01-02 12:59:33 +02:00
committed by GitHub
parent 16a7fb8acd
commit da8d984ea4
19 changed files with 227 additions and 30 deletions

View File

@@ -19,10 +19,13 @@ package org.openapitools.codegen.languages;
import com.google.common.collect.Sets;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.media.Discriminator;
import io.swagger.v3.oas.models.media.Schema;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.*;
import org.openapitools.codegen.CodegenDiscriminator.MappedModel;
import org.openapitools.codegen.api.TemplatePathLocator;
import org.openapitools.codegen.config.GlobalSettings;
import org.openapitools.codegen.meta.GeneratorMetadata;
@@ -44,6 +47,7 @@ import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -275,7 +279,7 @@ public class DartDioClientCodegen extends AbstractDartCodegen {
imports.put("Uint8List", "dart:typed_data");
imports.put("MultipartFile", DIO_IMPORT);
}
private void configureDateLibrary(String srcFolder) {
switch (dateLibrary) {
case DATE_LIBRARY_TIME_MACHINE:
@@ -400,6 +404,7 @@ public class DartDioClientCodegen extends AbstractDartCodegen {
private final String kHasAncestorOnlyProps = "x-has-ancestor-only-props";
private final String kSelfAndAncestorOnlyProps = "x-self-and-ancestor-only-props";
private final String kHasSelfAndAncestorOnlyProps = "x-has-self-and-ancestor-only-props";
private final String kParentDiscriminator = "x-parent-discriminator";
// adapts codegen models and property to dart rules of inheritance
private void adaptToDartInheritance(Map<String, ModelsMap> objs) {
@@ -449,6 +454,14 @@ public class DartDioClientCodegen extends AbstractDartCodegen {
cm.vendorExtensions.put(kIsChild, isChild);
cm.vendorExtensions.put(kIsParent, isParent);
cm.vendorExtensions.put(kIsPure, isPure);
if (!isParent && (cm.oneOf == null || cm.oneOf.isEmpty())) {
//discriminator has no meaning here
if (cm.discriminator!=null) {
cm.vendorExtensions.put(kParentDiscriminator, cm.discriminator);
cm.discriminator=null;
}
}
// when pure:
// vars = allVars = selfOnlyProperties = kSelfAndAncestorOnlyProps
// ancestorOnlyProps = empty
@@ -541,6 +554,30 @@ public class DartDioClientCodegen extends AbstractDartCodegen {
}
}
/// override the default behavior of createDiscriminator
/// to remove extra mappings added as a side effect of setLegacyDiscriminatorBehavior(false)
/// this ensures 1-1 schema mapping instead of 1-many
@Override
protected CodegenDiscriminator createDiscriminator(String schemaName, Schema schema, OpenAPI openAPI) {
CodegenDiscriminator sub = super.createDiscriminator(schemaName, schema, openAPI);
Discriminator originalDiscriminator = schema.getDiscriminator();
if (originalDiscriminator!=null) {
Map<String,String> originalMapping = originalDiscriminator.getMapping();
if (originalMapping != null && !originalMapping.isEmpty()) {
//we already have a discriminator mapping, remove everything else
for (MappedModel currentMappings : new HashSet<>(sub.getMappedModels())) {
if (originalMapping.containsKey(currentMappings.getMappingName())) {
//all good
} else {
sub.getMapping().remove(currentMappings.getMappingName());
sub.getMappedModels().remove(currentMappings);
}
}
}
}
return sub;
}
@Override
public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs) {
objs = super.postProcessAllModels(objs);

View File

@@ -10,7 +10,9 @@ part '{{classFilename}}.g.dart';
{{>serialization/built_value/class_header}} {
{{>serialization/built_value/class_members}}
}
{{#discriminator}}{{#hasDiscriminatorWithNonEmptyMapping}}
{{>serialization/built_value/class_discriminator}}
{{/hasDiscriminatorWithNonEmptyMapping}}{{/discriminator}}
{{>serialization/built_value/class_serializer}}{{#vendorExtensions.x-is-parent}}
{{>serialization/built_value/class_concrete}}{{/vendorExtensions.x-is-parent}}

View File

@@ -0,0 +1,20 @@
extension {{classname}}DiscriminatorExt on {{classname}} {
String? get discriminatorValue {
{{#mappedModels}}
if (this is {{modelName}}) {
return r'{{mappingName}}';
}
{{/mappedModels}}
return null;
}
}
extension {{classname}}BuilderDiscriminatorExt on {{classname}}Builder {
String? get discriminatorValue {
{{#mappedModels}}
if (this is {{modelName}}Builder) {
return r'{{mappingName}}';
}
{{/mappedModels}}
return null;
}
}

View File

@@ -28,7 +28,7 @@
factory {{classname}}([void updates({{classname}}Builder b)]) = _${{classname}};
@BuiltValueHook(initializeBuilder: true)
static void _defaults({{{classname}}}Builder b) => b{{#vendorExtensions.x-self-and-ancestor-only-props}}{{#defaultValue}}
static void _defaults({{{classname}}}Builder b) => b{{#vendorExtensions.x-parent-discriminator}}..{{propertyName}}=b.discriminatorValue{{/vendorExtensions.x-parent-discriminator}}{{#vendorExtensions.x-self-and-ancestor-only-props}}{{#defaultValue}}
..{{{name}}} = {{#isEnum}}{{^isContainer}}const {{{enumName}}}._({{/isContainer}}{{/isEnum}}{{{defaultValue}}}{{#isEnum}}{{^isContainer}}){{/isContainer}}{{/isEnum}}{{/defaultValue}}{{/vendorExtensions.x-self-and-ancestor-only-props}};
{{/vendorExtensions.x-is-parent}} @BuiltValueSerializer(custom: true)

View File

@@ -32,14 +32,12 @@ abstract class Bar implements Entity, Built<Bar, BarBuilder> {
@BuiltValueField(wireName: r'barPropA')
String? get barPropA;
static const String discriminatorFieldName = r'@type';
Bar._();
factory Bar([void updates(BarBuilder b)]) = _$Bar;
@BuiltValueHook(initializeBuilder: true)
static void _defaults(BarBuilder b) => b;
static void _defaults(BarBuilder b) => b..atType=b.discriminatorValue;
@BuiltValueSerializer(custom: true)
static Serializer<Bar> get serializer => _$BarSerializer();

View File

@@ -32,14 +32,12 @@ abstract class BarCreate implements Entity, Built<BarCreate, BarCreateBuilder> {
@BuiltValueField(wireName: r'barPropA')
String? get barPropA;
static const String discriminatorFieldName = r'@type';
BarCreate._();
factory BarCreate([void updates(BarCreateBuilder b)]) = _$BarCreate;
@BuiltValueHook(initializeBuilder: true)
static void _defaults(BarCreateBuilder b) => b;
static void _defaults(BarCreateBuilder b) => b..atType=b.discriminatorValue;
@BuiltValueSerializer(custom: true)
static Serializer<BarCreate> get serializer => _$BarCreateSerializer();

View File

@@ -19,14 +19,12 @@ part 'bar_ref.g.dart';
/// * [atType] - When sub-classing, this defines the sub-class Extensible name
@BuiltValue()
abstract class BarRef implements EntityRef, Built<BarRef, BarRefBuilder> {
static const String discriminatorFieldName = r'@type';
BarRef._();
factory BarRef([void updates(BarRefBuilder b)]) = _$BarRef;
@BuiltValueHook(initializeBuilder: true)
static void _defaults(BarRefBuilder b) => b;
static void _defaults(BarRefBuilder b) => b..atType=b.discriminatorValue;
@BuiltValueSerializer(custom: true)
static Serializer<BarRef> get serializer => _$BarRefSerializer();

View File

@@ -42,6 +42,29 @@ abstract class BarRefOrValue implements Built<BarRefOrValue, BarRefOrValueBuilde
static Serializer<BarRefOrValue> get serializer => _$BarRefOrValueSerializer();
}
extension BarRefOrValueDiscriminatorExt on BarRefOrValue {
String? get discriminatorValue {
if (this is Bar) {
return r'Bar';
}
if (this is BarRef) {
return r'BarRef';
}
return null;
}
}
extension BarRefOrValueBuilderDiscriminatorExt on BarRefOrValueBuilder {
String? get discriminatorValue {
if (this is BarBuilder) {
return r'Bar';
}
if (this is BarRefBuilder) {
return r'BarRef';
}
return null;
}
}
class _$BarRefOrValueSerializer implements PrimitiveSerializer<BarRefOrValue> {
@override
final Iterable<Type> types = const [BarRefOrValue, _$BarRefOrValue];

View File

@@ -41,6 +41,53 @@ abstract class Entity implements Addressable, Extensible {
static Serializer<Entity> get serializer => _$EntitySerializer();
}
extension EntityDiscriminatorExt on Entity {
String? get discriminatorValue {
if (this is Bar) {
return r'Bar';
}
if (this is BarCreate) {
return r'Bar_Create';
}
if (this is Foo) {
return r'Foo';
}
if (this is Pasta) {
return r'Pasta';
}
if (this is Pizza) {
return r'Pizza';
}
if (this is PizzaSpeziale) {
return r'PizzaSpeziale';
}
return null;
}
}
extension EntityBuilderDiscriminatorExt on EntityBuilder {
String? get discriminatorValue {
if (this is BarBuilder) {
return r'Bar';
}
if (this is BarCreateBuilder) {
return r'Bar_Create';
}
if (this is FooBuilder) {
return r'Foo';
}
if (this is PastaBuilder) {
return r'Pasta';
}
if (this is PizzaBuilder) {
return r'Pizza';
}
if (this is PizzaSpezialeBuilder) {
return r'PizzaSpeziale';
}
return null;
}
}
class _$EntitySerializer implements PrimitiveSerializer<Entity> {
@override
final Iterable<Type> types = const [Entity];

View File

@@ -43,6 +43,29 @@ abstract class EntityRef implements Addressable, Extensible {
static Serializer<EntityRef> get serializer => _$EntityRefSerializer();
}
extension EntityRefDiscriminatorExt on EntityRef {
String? get discriminatorValue {
if (this is BarRef) {
return r'BarRef';
}
if (this is FooRef) {
return r'FooRef';
}
return null;
}
}
extension EntityRefBuilderDiscriminatorExt on EntityRefBuilder {
String? get discriminatorValue {
if (this is BarRefBuilder) {
return r'BarRef';
}
if (this is FooRefBuilder) {
return r'FooRef';
}
return null;
}
}
class _$EntityRefSerializer implements PrimitiveSerializer<EntityRef> {
@override
final Iterable<Type> types = const [EntityRef];

View File

@@ -27,14 +27,12 @@ abstract class Foo implements Entity, Built<Foo, FooBuilder> {
@BuiltValueField(wireName: r'fooPropB')
String? get fooPropB;
static const String discriminatorFieldName = r'@type';
Foo._();
factory Foo([void updates(FooBuilder b)]) = _$Foo;
@BuiltValueHook(initializeBuilder: true)
static void _defaults(FooBuilder b) => b;
static void _defaults(FooBuilder b) => b..atType=b.discriminatorValue;
@BuiltValueSerializer(custom: true)
static Serializer<Foo> get serializer => _$FooSerializer();

View File

@@ -23,14 +23,12 @@ abstract class FooRef implements EntityRef, Built<FooRef, FooRefBuilder> {
@BuiltValueField(wireName: r'foorefPropA')
String? get foorefPropA;
static const String discriminatorFieldName = r'@type';
FooRef._();
factory FooRef([void updates(FooRefBuilder b)]) = _$FooRef;
@BuiltValueHook(initializeBuilder: true)
static void _defaults(FooRefBuilder b) => b;
static void _defaults(FooRefBuilder b) => b..atType=b.discriminatorValue;
@BuiltValueSerializer(custom: true)
static Serializer<FooRef> get serializer => _$FooRefSerializer();

View File

@@ -42,6 +42,29 @@ abstract class FooRefOrValue implements Built<FooRefOrValue, FooRefOrValueBuilde
static Serializer<FooRefOrValue> get serializer => _$FooRefOrValueSerializer();
}
extension FooRefOrValueDiscriminatorExt on FooRefOrValue {
String? get discriminatorValue {
if (this is Foo) {
return r'Foo';
}
if (this is FooRef) {
return r'FooRef';
}
return null;
}
}
extension FooRefOrValueBuilderDiscriminatorExt on FooRefOrValueBuilder {
String? get discriminatorValue {
if (this is FooBuilder) {
return r'Foo';
}
if (this is FooRefBuilder) {
return r'FooRef';
}
return null;
}
}
class _$FooRefOrValueSerializer implements PrimitiveSerializer<FooRefOrValue> {
@override
final Iterable<Type> types = const [FooRefOrValue, _$FooRefOrValue];

View File

@@ -23,14 +23,12 @@ abstract class Pasta implements Entity, Built<Pasta, PastaBuilder> {
@BuiltValueField(wireName: r'vendor')
String? get vendor;
static const String discriminatorFieldName = r'@type';
Pasta._();
factory Pasta([void updates(PastaBuilder b)]) = _$Pasta;
@BuiltValueHook(initializeBuilder: true)
static void _defaults(PastaBuilder b) => b;
static void _defaults(PastaBuilder b) => b..atType=b.discriminatorValue;
@BuiltValueSerializer(custom: true)
static Serializer<Pasta> get serializer => _$PastaSerializer();

View File

@@ -34,6 +34,23 @@ abstract class Pizza implements Entity {
static Serializer<Pizza> get serializer => _$PizzaSerializer();
}
extension PizzaDiscriminatorExt on Pizza {
String? get discriminatorValue {
if (this is PizzaSpeziale) {
return r'PizzaSpeziale';
}
return null;
}
}
extension PizzaBuilderDiscriminatorExt on PizzaBuilder {
String? get discriminatorValue {
if (this is PizzaSpezialeBuilder) {
return r'PizzaSpeziale';
}
return null;
}
}
class _$PizzaSerializer implements PrimitiveSerializer<Pizza> {
@override
final Iterable<Type> types = const [Pizza];

View File

@@ -23,14 +23,12 @@ abstract class PizzaSpeziale implements Pizza, Built<PizzaSpeziale, PizzaSpezial
@BuiltValueField(wireName: r'toppings')
String? get toppings;
static const String discriminatorFieldName = r'@type';
PizzaSpeziale._();
factory PizzaSpeziale([void updates(PizzaSpezialeBuilder b)]) = _$PizzaSpeziale;
@BuiltValueHook(initializeBuilder: true)
static void _defaults(PizzaSpezialeBuilder b) => b;
static void _defaults(PizzaSpezialeBuilder b) => b..atType=b.discriminatorValue;
@BuiltValueSerializer(custom: true)
static Serializer<PizzaSpeziale> get serializer => _$PizzaSpezialeSerializer();

View File

@@ -34,6 +34,29 @@ abstract class Animal {
static Serializer<Animal> get serializer => _$AnimalSerializer();
}
extension AnimalDiscriminatorExt on Animal {
String? get discriminatorValue {
if (this is Cat) {
return r'Cat';
}
if (this is Dog) {
return r'Dog';
}
return null;
}
}
extension AnimalBuilderDiscriminatorExt on AnimalBuilder {
String? get discriminatorValue {
if (this is CatBuilder) {
return r'Cat';
}
if (this is DogBuilder) {
return r'Dog';
}
return null;
}
}
class _$AnimalSerializer implements PrimitiveSerializer<Animal> {
@override
final Iterable<Type> types = const [Animal];

View File

@@ -18,14 +18,12 @@ part 'cat.g.dart';
/// * [declawed]
@BuiltValue()
abstract class Cat implements Animal, CatAllOf, Built<Cat, CatBuilder> {
static const String discriminatorFieldName = r'className';
Cat._();
factory Cat([void updates(CatBuilder b)]) = _$Cat;
@BuiltValueHook(initializeBuilder: true)
static void _defaults(CatBuilder b) => b
static void _defaults(CatBuilder b) => b..className=b.discriminatorValue
..color = 'red';
@BuiltValueSerializer(custom: true)

View File

@@ -18,14 +18,12 @@ part 'dog.g.dart';
/// * [breed]
@BuiltValue()
abstract class Dog implements Animal, DogAllOf, Built<Dog, DogBuilder> {
static const String discriminatorFieldName = r'className';
Dog._();
factory Dog([void updates(DogBuilder b)]) = _$Dog;
@BuiltValueHook(initializeBuilder: true)
static void _defaults(DogBuilder b) => b
static void _defaults(DogBuilder b) => b..className=b.discriminatorValue
..color = 'red';
@BuiltValueSerializer(custom: true)