Skip to content
This repository has been archived by the owner on Dec 15, 2023. It is now read-only.

Commit

Permalink
Add support for constructors, private variables and getters
Browse files Browse the repository at this point in the history
  • Loading branch information
eredo committed Sep 19, 2018
1 parent 52f3bbf commit 3a4e11f
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 14 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ import 'my_class.dart';
final Dartson<String> serializer = _serializer$dartson.useCodec(json);
```

### Private properties

It's not possible to encode / decode private properties. To set private properties, expose these within the constructor
and provide a getter for encoding the entity.

### Encoding / decoding lists

Expand Down
5 changes: 5 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## 1.0.0-alpha+3

- Add support for final properties
- Add support to skip private properties
- Add support for constructor arguments
- Add support for getters

**Breaking changes**
- `DateTimeParser` is deprecated. The default is now the `json_serializable` implementation and it's no longer necessary
to register a transformer at all.
Expand Down
57 changes: 53 additions & 4 deletions lib/src/generator/entity_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:json_serializable/src/type_helpers/enum_helper.dart';
import 'package:json_serializable/src/type_helpers/iterable_helper.dart';
import 'package:json_serializable/src/type_helpers/map_helper.dart';

import '../annotations.dart';
import 'entity_type_helper.dart';
import 'field_context.dart';
import 'identifier.dart';
Expand Down Expand Up @@ -47,8 +48,9 @@ class EntityGenerator {
.newInstance([]).assignFinal('obj'));

for (var field in _fields) {
final fieldProperty = propertyAnnotation(field);
if (fieldProperty.ignore) {
final fieldProperty = propertyAnnotation(
field.getter.metadata.isNotEmpty ? field.getter : field);
if (field.isPrivate || fieldProperty.ignore) {
continue;
}

Expand Down Expand Up @@ -78,12 +80,59 @@ class EntityGenerator {
}

Method _buildDecoder() {
final constructorParameters = <Expression>[];
final constructorNamedParameters = <String, Expression>{};
final passedConstructorParameters = <String>[];

// Get constructor arguments.
final constructorArguments = _element.constructors?.first?.parameters ?? [];
for (var field in constructorArguments) {
Property fieldProperty;
if (field.isInitializingFormal) {
// Fetch details from matching field.
fieldProperty = propertyAnnotation(
_fields.firstWhere((fe) => fe.name == field.name));

passedConstructorParameters.add(field.displayName);
} else {
// Check for annotations.
fieldProperty = propertyAnnotation(field);
}

if (fieldProperty.ignore && field.isNotOptional) {
// TODO: Throw proper error.
throw 'NotOptional marked as ignored';
}

if (fieldProperty.ignore) {
continue;
}

final fieldContext = FieldContext(true, field.metadata, _helpers);
_fieldContexts.add(fieldContext);

final expression = CodeExpression(Code(fieldContext.deserialize(
field.type, 'data[\'${fieldProperty.name ?? field.displayName}\']')));
if (field.isPositional) {
constructorParameters.add(expression);
} else {
constructorNamedParameters[field.name] = expression;
}
}

final block = BlockBuilder()
..statements.add(Code('if (data == null) { return null; }'))
..addExpression(
refer(_element.displayName).newInstance([]).assignFinal('obj'));
..addExpression(refer(_element.displayName)
.newInstance(constructorParameters, constructorNamedParameters)
.assignFinal('obj'));

for (var field in _fields) {
if (field.isFinal ||
passedConstructorParameters.contains(field.name) ||
field.isPrivate) {
continue;
}

final fieldProperty = propertyAnnotation(field);
if (fieldProperty.ignore) {
continue;
Expand Down
2 changes: 1 addition & 1 deletion lib/src/generator/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:analyzer/src/dart/resolver/inheritance_manager.dart';
import 'package:source_gen/source_gen.dart';
import 'package:dartson/dartson.dart';

Property propertyAnnotation(FieldElement element) {
Property propertyAnnotation(Element element) {
final annotations = TypeChecker.fromRuntime(Property).annotationsOf(element);
if (annotations.isEmpty) {
return Property();
Expand Down
14 changes: 7 additions & 7 deletions test/dartson_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ void main() {
});

test('should encode the object', () {
final result = serializer.encode(MyClass()
final result = serializer.encode(MyClass('test')
..name = 'hello'
..numDouble = 1.0
..subClass = (SubClass()..name = 'test'));
Expand All @@ -53,7 +53,7 @@ void main() {
});

test('should encode lists', () {
final result = serializer.encode(MyClass()
final result = serializer.encode(MyClass('test')
..subClasses = [
SubClass()
..name = '1'
Expand Down Expand Up @@ -91,7 +91,7 @@ void main() {
});

test('should encode maps', () {
final result = serializer.encode(MyClass()
final result = serializer.encode(MyClass('test')
..complexMap = {
't1': SubClass()..name = 't1',
't2': SubClass()..name = 't2',
Expand All @@ -116,8 +116,8 @@ void main() {
});

test('should encode replacements', () {
final result =
serializer.encode(MyClass()..replacement = (MyImpl()..name = 'test'));
final result = serializer
.encode(MyClass('test')..replacement = (MyImpl()..name = 'test'));
expect(result['replacement']['name'], 'test');
});

Expand Down Expand Up @@ -161,8 +161,8 @@ void main() {

test('should encode lists', () {
final result = serializer.encodeList([
MyClass()..name = 'test1',
MyClass()..name = 'test2',
MyClass('test')..name = 'test1',
MyClass('test')..name = 'test2',
]) as List<Map<String, dynamic>>;

expect(result, allOf(isList, hasLength(2)));
Expand Down
9 changes: 9 additions & 0 deletions test/src/my_class.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ enum MyEnum { firstValue, secondValue }
enum SecondEnum { has, nothing }

class MyClass extends BaseClass {
final String finalProp;
String name;
int number;
@Property(name: 'boolean')
Expand All @@ -22,6 +23,14 @@ class MyClass extends BaseClass {
List<SubClass> subClasses;
Map<String, SubClass> complexMap;
MyAbstr replacement;
String _private;

MyClass(this.finalProp,
{this.ignored, @Property(name: 'private') String renamedPrivate})
: _private = renamedPrivate;

@Property(name: 'private')
String get privateGetter => _private;
}

class BaseClass {
Expand Down
5 changes: 4 additions & 1 deletion test/src/serializer.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion test/src/usage.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'serializer.dart';
import 'my_class.dart';

void usage() {
final myClass = MyClass()
final myClass = MyClass('test')
..name = 'test name'
..number = 29
..hasBoolean = true;
Expand Down

0 comments on commit 3a4e11f

Please sign in to comment.