Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
11 changes: 11 additions & 0 deletions bin/configs/dart-dio-anyof.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
generatorName: dart-dio
outputDir: samples/openapi3/client/petstore/dart-dio/anyof
inputSpec: modules/openapi-generator/src/test/resources/3_0/anyOf.yaml
templateDir: modules/openapi-generator/src/main/resources/dart/libraries/dio
typeMappings:
Client: "ModelClient"
File: "ModelFile"
EnumClass: "ModelEnumClass"
additionalProperties:
hideGenerationTimestamp: "true"
enumUnknownDefaultCase: "true"
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ private void configureSerializationLibrary(String srcFolder) {
private void configureSerializationLibraryBuiltValue(String srcFolder) {
supportingFiles.add(new SupportingFile("serialization/built_value/serializers.mustache", srcFolder, "serializers.dart"));
supportingFiles.add(new SupportingFile("serialization/built_value/api_util.mustache", srcFolder, "api_util.dart"));
supportingFiles.add(new SupportingFile("serialization/built_value/serializers_util.mustache", srcFolder, "serializers_util.dart"));

typeMapping.put("Array", "BuiltList");
typeMapping.put("array", "BuiltList");
Expand Down Expand Up @@ -557,6 +558,9 @@ private void adaptToDartInheritance(Map<String, ModelsMap> objs) {
interfaceImports.addAll(cm.allOf);
interfaceImports.addAll(cm.oneOf);
interfaceImports.addAll(cm.anyOf);
if(!cm.oneOf.isEmpty() || !cm.anyOf.isEmpty()) {
interfaceImports.add("package:" + pubName + "/" + sourceFolder + "/serializers_util.dart");
}
cm.imports.addAll(rewriteImports(interfaceImports, true));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
{{/allowableValues}}

{{/vendorExtensions.x-self-only-props}}{{#anyOf}}{{#-first}} /// Any Of {{#anyOf}}[{{{.}}}]{{^-last}}, {{/-last}}{{/anyOf}}
AnyOf get anyOf;
AnyOf{{anyOf.size}}<{{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}> get anyOf;

{{/-first}}{{/anyOf}}{{#oneOf}}{{#-first}} /// One Of {{#oneOf}}[{{{.}}}]{{^-last}}, {{/-last}}{{/oneOf}}
OneOf get oneOf;
OneOf{{oneOf.size}}<{{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}> get oneOf;

{{/-first}}{{/oneOf}}{{#discriminator}} static const String discriminatorFieldName = r'{{propertyBaseName}}';{{#hasDiscriminatorWithNonEmptyMapping}}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,9 @@ class _${{classname}}Serializer implements PrimitiveSerializer<{{classname}}> {
throw UnsupportedError("Couldn't deserialize oneOf for the discriminator value: ${discValue}");
{{/vendorExtensions.x-is-parent}}
}
result.oneOf = OneOfDynamic(typeIndex: oneOfTypes.indexOf(oneOfType), types: oneOfTypes, value: oneOfResult);
result.oneOf = oneOfFactory(
OneOfDynamic(typeIndex: oneOfTypes.indexOf(oneOfType), types: oneOfTypes, value: oneOfResult)
)<{{#mappedModels}}{{modelName}}{{^-last}}, {{/-last}}{{/mappedModels}}{{#vendorExtensions.x-is-parent}}{{#mappedModels}}, {{/mappedModels}}${{classname}}{{/vendorExtensions.x-is-parent}}>();
{{/discriminator}}
{{/hasDiscriminatorWithNonEmptyMapping}}
{{^hasDiscriminatorWithNonEmptyMapping}}
Expand All @@ -173,7 +175,7 @@ class _${{classname}}Serializer implements PrimitiveSerializer<{{classname}}> {
{{! has no probs at all, pass the serialized as is }}
oneOfDataSrc = serialized;
{{/vendorExtensions.x-has-self-and-ancestor-only-props}}
result.oneOf = serializers.deserialize(oneOfDataSrc, specifiedType: targetType) as OneOf;
result.oneOf = oneOfFactory(serializers.deserialize(oneOfDataSrc, specifiedType: targetType) as OneOfDynamic)<{{#composedSchemas}}{{#oneOf}}{{{datatypeWithEnum}}}{{^-last}}, {{/-last}}{{/oneOf}}{{/composedSchemas}}>();
{{/hasDiscriminatorWithNonEmptyMapping}}
return result.build();
{{/-first}}
Expand Down Expand Up @@ -225,7 +227,9 @@ class _${{classname}}Serializer implements PrimitiveSerializer<{{classname}}> {
throw UnsupportedError("Couldn't deserialize anyOf for the discriminator value: ${discValue}");
{{/vendorExtensions.x-is-parent}}
}
result.anyOf = AnyOfDynamic(values: {anyOfTypes.indexOf(anyOfType): anyOfResult}, types: anyOfTypes);
result.anyOf = anyOfFactory(
AnyOfDynamic(values: {anyOfTypes.indexOf(anyOfType): anyOfResult}, types: anyOfTypes)
)<{{#mappedModels}}{{modelName}}{{^-last}}, {{/-last}}{{/mappedModels}}{{#vendorExtensions.x-is-parent}}{{#mappedModels}}, {{/mappedModels}}${{classname}}{{/vendorExtensions.x-is-parent}}>();
{{/discriminator}}
{{/hasDiscriminatorWithNonEmptyMapping}}
{{^hasDiscriminatorWithNonEmptyMapping}}
Expand All @@ -250,7 +254,7 @@ class _${{classname}}Serializer implements PrimitiveSerializer<{{classname}}> {
{{! has no probs at all, pass the serialized as is }}
anyOfDataSrc = serialized;
{{/vendorExtensions.x-has-self-and-ancestor-only-props}}
result.anyOf = serializers.deserialize(anyOfDataSrc, specifiedType: targetType) as AnyOf;
result.anyOf = anyOfFactory(serializers.deserialize(anyOfDataSrc, specifiedType: targetType) as AnyOfDynamic)<{{#composedSchemas}}{{#anyOf}}{{{datatypeWithEnum}}}{{^-last}}, {{/-last}}{{/anyOf}}{{/composedSchemas}}>();
{{/hasDiscriminatorWithNonEmptyMapping}}
return result.build();
{{/-first}}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import 'package:one_of/any_of.dart';
import 'package:one_of/one_of.dart';

Function oneOfFactory(OneOfDynamic oneOf) {
switch (oneOf.types.length) {
case 1:
return <T0>() => OneOf1<T0>(value: oneOf.value as T0);
case 2:
return <T0, T1>() => OneOf2<T0, T1>(
value: oneOf.value,
typeIndex: oneOf.typeIndex,
);
case 3:
return <T0, T1, T2>() => OneOf3<T0, T1, T2>(
value: oneOf.value,
typeIndex: oneOf.typeIndex,
);
case 4:
return <T0, T1, T2, T3>() => OneOf4<T0, T1, T2, T3>(
value: oneOf.value,
typeIndex: oneOf.typeIndex,
);
case 5:
return <T0, T1, T2, T3, T4>() => OneOf5<T0, T1, T2, T3, T4>(
value: oneOf.value,
typeIndex: oneOf.typeIndex,
);
case 6:
return <T0, T1, T2, T3, T4, T5>() => OneOf6<T0, T1, T2, T3, T4, T5>(
value: oneOf.value,
typeIndex: oneOf.typeIndex,
);
case 7:
return <T0, T1, T2, T3, T4, T5, T6>() =>
OneOf7<T0, T1, T2, T3, T4, T5, T6>(
value: oneOf.value,
typeIndex: oneOf.typeIndex,
);
}
throw ArgumentError('Invalid number of types: ${oneOf.types.length}');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

meant here

Copy link
Contributor Author

@fa0311 fa0311 Mar 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can maintain backward compatibility, but a simple replacement won't work.
If we simply return OneOfDynamic, it will fail when casting to OneOfx (OneOf{{oneOf.size}}), resulting in an error.
A slightly more involved approach would be to introduce a flag for cases with seven or more oneof values—if set to true, it would use OneOfDynamic.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest, I never really liked the idea of fitting infinitely large oneof/anyof cases into a single variable

The approach I followed here #18970 is much cleaner, and is similar to what protobuf does

}

Function anyOfFactory(AnyOfDynamic anyOf) {
switch (anyOf.types.length) {
case 1:
return <T0>() => AnyOf1<T0>(value: anyOf.values[0] as T0);
case 2:
return <T0, T1>() => AnyOf2<T0, T1>(
values: anyOf.values,
);
case 3:
return <T0, T1, T2>() => AnyOf3<T0, T1, T2>(
values: anyOf.values,
);
case 4:
return <T0, T1, T2, T3>() => AnyOf4<T0, T1, T2, T3>(
values: anyOf.values,
);
case 5:
return <T0, T1, T2, T3, T4>() => AnyOf5<T0, T1, T2, T3, T4>(
values: anyOf.values,
);
case 6:
return <T0, T1, T2, T3, T4, T5>() => AnyOf6<T0, T1, T2, T3, T4, T5>(
values: anyOf.values,
);
case 7:
return <T0, T1, T2, T3, T4, T5, T6>() =>
AnyOf7<T0, T1, T2, T3, T4, T5, T6>(
values: anyOf.values,
);
}
throw ArgumentError('Invalid number of types: ${anyOf.types.length}');
}
41 changes: 41 additions & 0 deletions samples/openapi3/client/petstore/dart-dio/anyof/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# See https://dart.dev/guides/libraries/private-files

# Files and directories created by pub
.dart_tool/
.buildlog
.packages
.project
.pub/
build/
**/packages/

# Files created by dart2js
# (Most Dart developers will use pub build to compile Dart, use/modify these
# rules if you intend to use dart2js directly
# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
# differentiate from explicit Javascript files)
*.dart.js
*.part.js
*.js.deps
*.js.map
*.info.json

# Directory created by dartdoc
doc/api/

# Don't commit pubspec lock file
# (Library packages only! Remove pattern if developing an application package)
pubspec.lock

# Don’t commit files and directories created by other development environments.
# For example, if your development environment creates any of the following files,
# consider putting them in a global ignore file:

# IntelliJ
*.iml
*.ipr
*.iws
.idea/

# Mac
.DS_Store
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator

# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.

# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs

# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux

# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux

# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.gitignore
README.md
analysis_options.yaml
doc/Apple.md
doc/Banana.md
doc/DefaultApi.md
doc/Fruit.md
lib/openapi.dart
lib/src/api.dart
lib/src/api/default_api.dart
lib/src/api_util.dart
lib/src/auth/api_key_auth.dart
lib/src/auth/auth.dart
lib/src/auth/basic_auth.dart
lib/src/auth/bearer_auth.dart
lib/src/auth/oauth.dart
lib/src/date_serializer.dart
lib/src/model/apple.dart
lib/src/model/banana.dart
lib/src/model/date.dart
lib/src/model/fruit.dart
lib/src/serializers.dart
lib/src/serializers_util.dart
pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
7.13.0-SNAPSHOT
85 changes: 85 additions & 0 deletions samples/openapi3/client/petstore/dart-dio/anyof/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# openapi (EXPERIMENTAL)
No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)

This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:

- API version: 0.0.1
- Generator version: 7.13.0-SNAPSHOT
- Build package: org.openapitools.codegen.languages.DartDioClientCodegen

## Requirements

* Dart 2.15.0+ or Flutter 2.8.0+
* Dio 5.0.0+ (https://pub.dev/packages/dio)

## Installation & Usage

### pub.dev
To use the package from [pub.dev](https://pub.dev), please include the following in pubspec.yaml
```yaml
dependencies:
openapi: 1.0.0
```

### Github
If this Dart package is published to Github, please include the following in pubspec.yaml
```yaml
dependencies:
openapi:
git:
url: https://github.com/GIT_USER_ID/GIT_REPO_ID.git
#ref: main
```

### Local development
To use the package from your local drive, please include the following in pubspec.yaml
```yaml
dependencies:
openapi:
path: /path/to/openapi
```

## Getting Started

Please follow the [installation procedure](#installation--usage) and then run the following:

```dart
import 'package:openapi/openapi.dart';


final api = Openapi().getDefaultApi();

try {
final response = await api.rootGet();
print(response);
} catch on DioException (e) {
print("Exception when calling DefaultApi->rootGet: $e\n");
}

```

## Documentation for API Endpoints

All URIs are relative to *http://localhost*

Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
[*DefaultApi*](doc/DefaultApi.md) | [**rootGet**](doc/DefaultApi.md#rootget) | **GET** / |


## Documentation For Models

- [Apple](doc/Apple.md)
- [Banana](doc/Banana.md)
- [Fruit](doc/Fruit.md)


## Documentation For Authorization

Endpoints do not require authorization.


## Author



Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
analyzer:
language:
strict-inference: true
strict-raw-types: true
strict-casts: false
exclude:
- test/*.dart
errors:
deprecated_member_use_from_same_package: ignore
15 changes: 15 additions & 0 deletions samples/openapi3/client/petstore/dart-dio/anyof/doc/Apple.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# openapi.model.Apple

## Load the model package
```dart
import 'package:openapi/api.dart';
```

## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**kind** | **String** | | [optional]

[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)


15 changes: 15 additions & 0 deletions samples/openapi3/client/petstore/dart-dio/anyof/doc/Banana.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# openapi.model.Banana

## Load the model package
```dart
import 'package:openapi/api.dart';
```

## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**count** | **num** | | [optional]

[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)


Loading
Loading