Skip to content

Commit 7a0e3db

Browse files
Merge pull request #112 from icapps/feature/AllowNullWithDefaults
Feature/allow null with defaults
2 parents 87d23bf + ebe7754 commit 7a0e3db

File tree

14 files changed

+143
-7
lines changed

14 files changed

+143
-7
lines changed

CHANGELOG.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
# Changelog
2+
## [5.9.0] - 2022-03-29
3+
- *POTENTIALLY BREAKING CHANGE*: By default, fields with a default value will now accept 'null' to use their default value
4+
- Add options to control whether fields with default value accepts 'null' or not
5+
- `disallow_null` on fields
6+
- `disallow_null_for_defaults` on the root yml config or the object config
7+
28
## [5.8.1] - 2021-12-09
39
- Detect the current min dart version and use newer features when available. (Fixes #108)
410

511
## [5.8.0] - 2021-11-25
612
- Added `retrofit_compute` option to generate top-level functions compatible with retrofit's compute mode. (Fixes #106)
7-
-
13+
814
## [5.7.1] - 2021-11-13
915
- Fixed issue where default values would still throw missing key exceptions. (Fixes #103)
1016

README.md

+48
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,52 @@ UserModel:
179179
default_value: "'an example quoted string'"
180180
```
181181

182+
### Default values and null
183+
184+
Since version `5.9.0` fields with default values can accept null values in json. In which case the default value will be used instead.
185+
186+
If you wish to control this behaviour, you can add `disallow_null_for_defaults: true` to either the `model_generator` config or the model property. Alternatively you can specify
187+
the behaviour per field by using `disallow_null`.
188+
189+
Example:
190+
191+
```yaml
192+
model_generator:
193+
disallow_null_for_defaults: true
194+
```
195+
196+
Example 2:
197+
198+
```yaml
199+
UserModel:
200+
path: webservice/user
201+
disallow_null_for_defaults: true
202+
properties:
203+
id:
204+
type: int
205+
default_value: 1
206+
name:
207+
type: string
208+
required: true
209+
default_value: "'an example quoted string'"
210+
```
211+
212+
Example 3:
213+
214+
```yaml
215+
UserModel:
216+
path: webservice/user
217+
properties:
218+
id:
219+
type: int
220+
default_value: 1
221+
name:
222+
type: string
223+
required: true
224+
default_value: "'an example quoted string'"
225+
disallow_null: true
226+
```
227+
182228
## Generics support support
183229

184230
If you want your models to generate code that can be used in combination with generics. use this:
@@ -202,9 +248,11 @@ UserModel:
202248
```
203249

204250
## Extends
251+
205252
If you want your models to expand any other model use extends:
206253

207254
*Note: It is not supported to extend custom models*
255+
208256
```yaml
209257
UserDetails:
210258
path: webservice/user

example/.fvm/fvm_config.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"flutterSdkVersion": "2.10.3",
3+
"flavors": {}
4+
}

lib/config/pubspec_config.dart

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class PubspecConfig {
2121
late bool staticCreate;
2222
late bool uppercaseEnums;
2323
late bool retrofitMappers;
24+
late bool disallowNullForDefaults;
2425
LanguageVersion? languageVersion;
2526
final extraImports = <String>[];
2627
final extraAnnotations = <String>[];
@@ -51,6 +52,7 @@ class PubspecConfig {
5152
staticCreate = false;
5253
uppercaseEnums = true;
5354
retrofitMappers = false;
55+
disallowNullForDefaults = false;
5456
return;
5557
}
5658

@@ -64,6 +66,8 @@ class PubspecConfig {
6466
staticCreate = (config['static_create'] ?? false) == true;
6567
uppercaseEnums = (config['uppercase_enums'] ?? true) == true;
6668
retrofitMappers = (config['retrofit_compute'] ?? false) == true;
69+
disallowNullForDefaults =
70+
(config['disallow_null_for_defaults'] ?? false) == true;
6771

6872
final extraImports = config['extra_imports'];
6973
if (extraImports != null) {

lib/config/yml_generator_config.dart

+14-3
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,17 @@ class YmlGeneratorConfig {
122122
));
123123
} else {
124124
final staticCreate = (value['static_create'] ?? false) == true;
125+
final disallowNullForDefaults =
126+
value.containsKey('disallow_null_for_defaults')
127+
? (value['disallow_null_for_defaults'] == true)
128+
: pubspecConfig.disallowNullForDefaults;
125129
final fields = <Field>[];
126130
properties.forEach((propertyKey, propertyValue) {
127131
if (propertyValue is! YamlMap) {
128132
throw Exception('$propertyKey should be an object');
129133
}
130-
fields.add(getField(propertyKey, propertyValue));
134+
fields.add(getField(propertyKey, propertyValue,
135+
disallowNullForDefaults: disallowNullForDefaults));
131136
});
132137
final mappedConverters =
133138
converters?.map((element) => element.toString()).toList();
@@ -146,14 +151,16 @@ class YmlGeneratorConfig {
146151
explicitToJson: value['explicit_to_json'],
147152
generateToString: value['to_string'],
148153
description: description,
154+
disallowNullForDefaults: disallowNullForDefaults,
149155
));
150156
}
151157
});
152158

153159
checkIfTypesAvailable();
154160
}
155161

156-
Field getField(String name, YamlMap property) {
162+
Field getField(String name, YamlMap property,
163+
{required bool disallowNullForDefaults}) {
157164
try {
158165
final required =
159166
property.containsKey('required') && property['required'] == true;
@@ -172,7 +179,10 @@ class YmlGeneratorConfig {
172179
: null;
173180
final type = property['type'];
174181
final skipEquality = property['ignore_equality'] == true;
175-
var defaultValue = property['default_value']?.toString();
182+
final defaultValue = property['default_value']?.toString();
183+
final disallowNull = property.containsKey('disallow_null')
184+
? (property['disallow_null'] == true)
185+
: disallowNullForDefaults;
176186
ItemType itemType;
177187

178188
if (type == null) {
@@ -219,6 +229,7 @@ class YmlGeneratorConfig {
219229
toJson: toJson,
220230
ignoreEquality: skipEquality,
221231
defaultValue: defaultValue,
232+
disallowNull: disallowNull,
222233
);
223234
} catch (e) {
224235
print('Something went wrong with $name:\n\n${e.toString()}');

lib/model/field.dart

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class Field {
1616
final String? toJson;
1717
final bool ignoreEquality;
1818
final String? defaultValue;
19+
final bool disallowNull;
1920

2021
bool get hasDefaultValue => defaultValue != null;
2122

@@ -32,6 +33,7 @@ class Field {
3233
this.fromJson,
3334
this.toJson,
3435
this.defaultValue,
36+
this.disallowNull = false,
3537
String? jsonKey,
3638
}) : serializedName = jsonKey ?? name,
3739
name =

lib/model/model/object_model.dart

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ class ObjectModel extends Model {
99
final bool? explicitToJson;
1010
final bool? generateToString;
1111
final bool? staticCreate;
12+
final bool? disallowNullForDefaults;
1213

1314
ObjectModel({
1415
required String name,
@@ -24,6 +25,7 @@ class ObjectModel extends Model {
2425
this.explicitToJson,
2526
this.generateToString,
2627
this.staticCreate,
28+
this.disallowNullForDefaults,
2729
String? description,
2830
}) : super(
2931
name: name,

lib/writer/object_model_writer.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class ObjectModelWriter {
100100
sb.write(" @JsonKey(name: '${key.serializedName}'");
101101
if (key.isRequired) {
102102
if (key.hasDefaultValue) {
103-
sb.write(', required: false, disallowNullValue: true');
103+
sb.write(', required: false, disallowNullValue: ${key.disallowNull}');
104104
} else {
105105
sb.write(', required: true');
106106
}

pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: model_generator
22
description: Dart tool to automaticly generate models from a yml file to speed up your development flow.
3-
version: 5.8.1
3+
version: 5.9.0
44
homepage: https://github.com/icapps/flutter-model-generator
55

66
environment:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Person:
2+
path: user/person/
3+
type: object
4+
properties:
5+
firstName:
6+
description: A good description
7+
type: string
8+
required: true
9+
default_field: "'test'"
10+
disallow_null: true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import 'package:json_annotation/json_annotation.dart';
2+
3+
part 'person.g.dart';
4+
5+
@JsonSerializable(explicitToJson: true)
6+
class Person {
7+
///A good description
8+
@JsonKey(name: 'firstName', required: false, disallowNullValue: true)
9+
final String firstName;
10+
11+
const Person({
12+
this.firstName = 'test',
13+
});
14+
15+
factory Person.fromJson(Map<String, dynamic> json) => _$PersonFromJson(json);
16+
17+
Map<String, dynamic> toJson() => _$PersonToJson(this);
18+
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
name: model_generator_example
2+
3+
model_generator:
4+
config_path: model_generator/config.yaml

test/writer/object_model_writer/default-field-required/output.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ part 'person.g.dart';
55
@JsonSerializable(explicitToJson: true)
66
class Person {
77
///A good description
8-
@JsonKey(name: 'firstName', required: false, disallowNullValue: true)
8+
@JsonKey(name: 'firstName', required: false, disallowNullValue: false)
99
final String firstName;
1010

1111
const Person({

test/writer/object_model_writer_test.dart

+26
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,32 @@ void main() {
998998
WriterTestHelper.testObjectModelWriter(
999999
model, [], 'default-field-required');
10001000
});
1001+
test('Normal ObjectModelWriter with default required field disallow null',
1002+
() {
1003+
final model = ObjectModel(
1004+
name: 'Person',
1005+
path: 'path_to_my_model',
1006+
baseDirectory: 'base_dir',
1007+
generateForGenerics: false,
1008+
staticCreate: false,
1009+
fields: [
1010+
Field(
1011+
name: 'firstName',
1012+
type: StringType(),
1013+
isRequired: true,
1014+
ignore: false,
1015+
includeIfNull: true,
1016+
ignoreEquality: false,
1017+
nonFinal: false,
1018+
disallowNull: true,
1019+
defaultValue: '\'test\'',
1020+
description: 'A good description'),
1021+
],
1022+
converters: [],
1023+
);
1024+
WriterTestHelper.testObjectModelWriter(
1025+
model, [], 'default-field-required-null-disallowed');
1026+
});
10011027
test('Normal ObjectModelWriter with retrofit compute', () {
10021028
final model = ObjectModel(
10031029
name: 'Person',

0 commit comments

Comments
 (0)