Skip to content

Commit

Permalink
V8 (#97)
Browse files Browse the repository at this point in the history
* initial cut of version 8

* passing all existing tests now

* fix for array copies and enhancing changelog for migration.

* add model and api deprecation drop support

* swap to an RC

* [maven-release-plugin] prepare release openapi-dart-generator-8.1-RC1

* [maven-release-plugin] prepare for next development iteration

* increase minimum version of opendart_dart_common

* fix issue where arrays/maps with no defaults were still getting them

* fix issue with non-nullable arrays and late init

* [maven-release-plugin] prepare release openapi-dart-generator-8.1-RC2

* [maven-release-plugin] prepare for next development iteration

* fix issue with required fields

* goosed up the array handling and central half-baked the release

* [maven-release-plugin] prepare release openapi-dart-generator-8.1-RC4

* [maven-release-plugin] prepare for next development iteration

* 8.1 ready for use

* [maven-release-plugin] prepare release openapi-dart-generator-8.1

* [maven-release-plugin] prepare for next development iteration
  • Loading branch information
rvowles authored Jan 23, 2024
1 parent 0472adc commit 4e04e87
Show file tree
Hide file tree
Showing 32 changed files with 618 additions and 562 deletions.
31 changes: 31 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
@@ -1,5 +1,36 @@
= Changelog

== 8.x Series is based on OpenAPI 7.x+

- The OpenAPI base now shifts to version 7 and Java 11.
- It also shifts to a more strict interpretation of nullable (a field can have a null value) vs required (a field
is required, but can be null or non null). A field is REQUIRED is it is marked as required, or if it is *not nullable*
and has no default (otherwise Dart doesn't know what to do with it).
- We drop support for pre-Dart 2.12 code (i.e. non-null safe code)
- We add the ability to drop deprecated APIs (additional property `filter-deprecated-apis`)
- We add the ability to drop deprecated Models (additional property `filter-deprecated-models`)


If you want to support something like Person? then you need something like this:

----
SomeClass:
properties:
person: # do not include a description or the API changes code generation
nullable: true
allOf:
- $ref: "#/components/schemas/Person"
----

This text snippet does not change the API, you get a `Person? person` field. If you add a description,
OpenAPI will automatically generate a new class which is outside of our control, and you will get a new
class likely called `SomeClassPerson` so it can hold the description.

If you put `nullable: true` on the definition of the object itself, it inherently turns the object to
always be nullable, so you get things like `List<Person?> people`.



== 7.x Series is based on OpenAPI 6.2+

The OpenAPI crew broke the API in weird ways in 6.2, so we go to a new major
Expand Down
2 changes: 1 addition & 1 deletion README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
This plugin was originally designed for use by the OpenAPi v3 Maven Plugin, but works with the
command line generator and the Gradle plugin. it generates _excellent_ Dart code and uses Dio.

NOTE: we are currently using 6.4.0 of the OpenAPI Maven Plugin.
NOTE: we are currently using 7.0.1 of the OpenAPI Maven Plugin.

== Sponsors

Expand Down
8 changes: 4 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
<artifactId>openapi-dart-generator</artifactId>
<packaging>jar</packaging>
<name>openapi-dart-generator</name>
<version>7.3-SNAPSHOT</version>
<version>8.2-SNAPSHOT</version>

<description>
dart2 generator from openapi 3.x spec files. Changing to openapitools dependencies.
dart2 generator from openapi 3.x spec files.
</description>

<url>https://www.bluetrainsoftware.com</url>
Expand All @@ -34,14 +34,14 @@
</scm>

<properties>
<openapi-codegen-version>6.4.0</openapi-codegen-version>
<openapi-codegen-version>7.0.1</openapi-codegen-version>
<maven.compiler.target>1.11</maven.compiler.target>
<maven.compiler.source>1.11</maven.compiler.source>
<kotlin.version>1.8.10</kotlin.version>
</properties>

<prerequisites>
<maven>3.5</maven>
<maven>3.8</maven>
</prerequisites>

<dependencies>
Expand Down
65 changes: 38 additions & 27 deletions sample-app/SampleRunner/test/api_tests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ main() {
print(w);
print(x);
print("codes ${w.hashCode} vs ${x.hashCode}");
expect(true, w.hashCode > 0, reason: '${w.hashCode} should be > 0');
print("empty array -> ${[].hashCode}");
expect(true, w.hashCode == x.hashCode);
expect(true, w.hashCode == x.hashCode,
reason:
'w hashcode: ${w.hashCode} should equal x hashcode: ${x.hashCode}');
var z = w.copyWith(types: [GeocodedWaypointTypesEnum.ADDRESS]);
expect(false, w == z);
expect(false, w.hashCode == z.hashCode);
Expand Down Expand Up @@ -54,19 +57,16 @@ main() {
test(
'hashing an object which has two fields of the same type is still different',
() {
var ht = HashTest()
..fieldOne = false
..fieldTwo = true;
var ht1 = HashTest()
..fieldOne = true
..fieldTwo = false;
var ht = HashTest(fieldOne: false, fieldTwo: true);
var ht1 = HashTest(fieldTwo: false, fieldOne: true);
expect(false, ht.hashCode == ht1.hashCode);
});

test('additional properties mappings', () {
const addProp = {
'discrim': 'fred',
'readings': {'one': 1, 'two': 2.3},
'extra': {},
'dependencies': {
'deps1': ['a', 34.2, true],
'deps2': [17.8, false, 'b']
Expand Down Expand Up @@ -97,24 +97,24 @@ main() {

var ap = AddProps3.fromJson(addProp);
expect(ap.discrim, 'fred');
expect(ap.readings.length, 2);
expect(ap.readings['one'], 1);
expect(ap.readings['two'], 2.3);
expect(ap.dependencies['deps1'], ['a', 34.2, true]);
expect(ap.dependencies['deps2'], [17.8, false, 'b']);
expect(ap.otherDeps['name'], ['tom', 'dick', 'harry']);
expect(ap.otherDeps['height'], [1.7, 1.3, 1.4]);
expect(ap.otherDeps['info'], 'this is top secret');
expect(ap.yetMoreAdditional['sList'], ['a', 'b', 'c']);
expect(ap.readings!.length, 2);
expect(ap.readings!['one'], 1);
expect(ap.readings!['two'], 2.3);
expect(ap.dependencies!['deps1'], ['a', 34.2, true]);
expect(ap.dependencies!['deps2'], [17.8, false, 'b']);
expect(ap.otherDeps!['name'], ['tom', 'dick', 'harry']);
expect(ap.otherDeps!['height'], [1.7, 1.3, 1.4]);
expect(ap.otherDeps!['info'], 'this is top secret');
expect(ap.yetMoreAdditional!['sList'], ['a', 'b', 'c']);
expect(
ap.mapWithComplexObject['c1']?[0],
Event()
..status = EventStatus.STREAMING
..id = 'xx'
..title = 'Scully'
..img = 'img'
..imageUrl = 'http://blah');
expect(ap.mapWithEnums['statuses'],
ap.mapWithComplexObject!['c1']?[0],
Event(
status: EventStatus.STREAMING,
id: 'xx',
title: 'Scully',
img: 'img',
imageUrl: 'http://blah'));
expect(ap.mapWithEnums!['statuses'],
[EventStatus.STREAMING, EventStatus.CLOSED]);
});

Expand All @@ -136,6 +136,7 @@ main() {
'basicInt': 2.6,
'basicDouble': 1,
'intList': [1, 2.6],
'int64Int': 33,
'intMap': {'one': 1, 'two': 2.7},
'doubleList': [1, 2.6],
'doubleMap': {'one': 1, 'two': 2.7},
Expand All @@ -145,16 +146,26 @@ main() {
expect(data.basicDouble, 1.0);
expect(data.basicInt, 2);
expect(data.intList, [1, 2]);
expect(data.int64Int, 33);
expect(data.intMap, {'one': 1, 'two': 2});
expect(data.doubleList, [1.0, 2.6]);
expect(data.doubleMap, {'one': 1.0, 'two': 2.7});
});
test('data serialisation', () {
final data = DoubleAndIntConversion(
basicInt: 43, basicDouble: 26.2, intList: [], doubleMap: {});
int64Int: 0,
intMap: {},
basicInt: 43,
basicDouble: 26.2,
intList: [],
doubleMap: {});
expect(data.toJson(), {
'basicInt': 43, 'basicDouble': 26.2, 'intList': [],
'doubleList': [], // because we can't tell between null and empty
'basicInt': 43,
'int64Int': 0,
'basicDouble': 26.2,
'intList': [],
'intMap': {},
'doubleList': [], // because it is not nullable
'doubleMap': {}
});
});
Expand Down
2 changes: 1 addition & 1 deletion src/it/k8s_null/lib/int_or_string.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class IntOrString {
return IntOrString()..value = this.value;
}

dynamic? toJson() {
dynamic toJson() {
return this.value;
}

Expand Down
2 changes: 1 addition & 1 deletion src/it/k8s_null/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>6.4.0</version>
<version>7.0.1</version>
<dependencies>
<dependency>
<groupId>com.bluetrainsoftware.maven</groupId>
Expand Down
2 changes: 2 additions & 0 deletions src/it/k8s_null/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ components:
int64Int:
type: integer
format: int64
default: 0
basicDouble:
type: number
format: double
Expand All @@ -390,6 +391,7 @@ components:
type: integer
doubleList:
type: array
default: []
items:
type: number
format: double
Expand Down
86 changes: 51 additions & 35 deletions src/it/k8s_null/test/api_tests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ main() {
print(w);
print(x);
print("codes ${w.hashCode} vs ${x.hashCode}");
expect(true, w.hashCode > 0, reason: '${w.hashCode} should be > 0');
print("empty array -> ${[].hashCode}");
expect(true, w.hashCode == x.hashCode);
expect(true, w.hashCode == x.hashCode, reason: 'w hashcode: ${w.hashCode} should equal x hashcode: ${x.hashCode}');
var z = w.copyWith(types: [GeocodedWaypointTypesEnum.ADDRESS]);
expect(false, w == z);
expect(false, w.hashCode == z.hashCode);
Expand All @@ -33,20 +34,37 @@ main() {
expect(encodeDecode, w);
});

test('basic inheritance', () {
final wld = WithListDerived.fromJson({
"list": [
{"id": 1, "name": "one"},
{"id": 2, "name": "two"}
],
"id": 7,
"name": "entity",
"nullableList": []
});

expect(wld.id, 7);
expect(wld.name, "entity");
expect(wld.list.length, 2);
});

// previous hashing mechanism if you swapped the adjacent field values
// it wouldn't change the hash
test(
'hashing an object which has two fields of the same type is still different',
() {
var ht = HashTest(fieldOne: false, fieldTwo: true);
var ht1 = HashTest(fieldOne: true, fieldTwo: false);
var ht1 = HashTest(fieldTwo: false, fieldOne: true);
expect(false, ht.hashCode == ht1.hashCode);
});

test('additional properties mappings', () {
const addProp = {
'discrim': 'fred',
'readings': {'one': 1, 'two': 2.3},
'extra': {},
'dependencies': {
'deps1': ['a', 34.2, true],
'deps2': [17.8, false, 'b']
Expand Down Expand Up @@ -77,24 +95,24 @@ main() {

var ap = AddProps3.fromJson(addProp);
expect(ap.discrim, 'fred');
expect(ap.readings?.length, 2);
expect(ap.readings?['one'], 1);
expect(ap.readings?['two'], 2.3);
expect(ap.dependencies?['deps1'], ['a', 34.2, true]);
expect(ap.dependencies?['deps2'], [17.8, false, 'b']);
expect(ap.otherDeps?['name'], ['tom', 'dick', 'harry']);
expect(ap.otherDeps?['height'], [1.7, 1.3, 1.4]);
expect(ap.otherDeps?['info'], 'this is top secret');
expect(ap.yetMoreAdditional?['sList'], ['a', 'b', 'c']);
expect(ap.readings!.length, 2);
expect(ap.readings!['one'], 1);
expect(ap.readings!['two'], 2.3);
expect(ap.dependencies!['deps1'], ['a', 34.2, true]);
expect(ap.dependencies!['deps2'], [17.8, false, 'b']);
expect(ap.otherDeps!['name'], ['tom', 'dick', 'harry']);
expect(ap.otherDeps!['height'], [1.7, 1.3, 1.4]);
expect(ap.otherDeps!['info'], 'this is top secret');
expect(ap.yetMoreAdditional!['sList'], ['a', 'b', 'c']);
expect(
ap.mapWithComplexObject?['c1']?[0],
ap.mapWithComplexObject!['c1']?[0],
Event(
status: EventStatus.STREAMING,
id: 'xx',
title: 'Scully',
img: 'img',
imageUrl: 'http://blah'));
expect(ap.mapWithEnums?['statuses'],
expect(ap.mapWithEnums!['statuses'],
[EventStatus.STREAMING, EventStatus.CLOSED]);
});

Expand All @@ -116,6 +134,7 @@ main() {
'basicInt': 2.6,
'basicDouble': 1,
'intList': [1, 2.6],
'int64Int': 33,
'intMap': {'one': 1, 'two': 2.7},
'doubleList': [1, 2.6],
'doubleMap': {'one': 1, 'two': 2.7},
Expand All @@ -125,35 +144,33 @@ main() {
expect(data.basicDouble, 1.0);
expect(data.basicInt, 2);
expect(data.intList, [1, 2]);
expect(data.int64Int, 33);
expect(data.intMap, {'one': 1, 'two': 2});
expect(data.doubleList, [1.0, 2.6]);
expect(data.doubleMap, {'one': 1.0, 'two': 2.7});
});

test('basic inheritance', () {
final wld = WithListDerived.fromJson({
"list": [ {"id": 1, "name": "one"}, {"id": 2, "name": "two"} ],
"id": 7, "name": "entity",
"nullableList": []
});

expect(wld.id, 7);
expect(wld.name, "entity");
expect(wld.list.length, 2);
});

test('data serialisation', () {
final data = DoubleAndIntConversion(
basicInt: 43, basicDouble: 26.2, intList: [], doubleMap: {});
expect(data.toJson(),
{'basicInt': 43, 'basicDouble': 26.2, 'intList': [], 'doubleMap': {}});
int64Int: 0,
intMap: {},
basicInt: 43,
basicDouble: 26.2,
intList: [],
doubleMap: {});
expect(data.toJson(), {
'basicInt': 43,
'int64Int': 0,
'basicDouble': 26.2,
'intList': [],
'intMap': {},
'doubleList': [], // because it is not nullable
'doubleMap': {}
});
});

test("int enums being generated with correct type", () {
expect(IntTypeEnum.number1.toJson(), 1);
expect(IntTypeEnum.number1, IntTypeEnumExtension.fromJson(1));
});

test(
"enums included in a model via allOf with reference will be treated as"
"enums and generate valid code ", () {
Expand All @@ -162,7 +179,6 @@ main() {
expect(testO.name, "foobar");
expect(testO.enumFieldAllOf, NumericAndSpacedEnum.n667);
});

test("generating 2d array in a correct way", () {
const json = {
"coordinates": [
Expand All @@ -172,10 +188,10 @@ main() {
};
final geometry = PointGeometry.fromJson(json);
expect(geometry.coordinates, hasLength(2));
final firstPair = geometry.coordinates?.first;
final firstPair = geometry.coordinates.first;
expect(firstPair, hasLength(2));
expect(firstPair?[0], -27.6307582);
expect(firstPair?[1], 153.0401564);
expect(firstPair[0], -27.6307582);
expect(firstPair[1], 153.0401564);
});
}

Expand Down
Loading

0 comments on commit 4e04e87

Please sign in to comment.