json_serializable.dart icon indicating copy to clipboard operation
json_serializable.dart copied to clipboard

final fields are not written during serialization

Open MatrixDev opened this issue 3 years ago • 5 comments

Source code

@JsonSerializable
class MyClass {
  @JsonKey(name: 'value1')
  var value1 = '';

  @JsonKey(name: 'value2')
  final value2 = 'must always be this';
}

Generated code:

MyClass _$MyClassFromJson(Map<String, dynamic> json) {
  return MyClass()..value1 = json['value1'] as String;
}

Map<String, dynamic> _$MyClassToJson(MyClass instance) => <String, dynamic>{
      'value1': instance.value1,
    };

Actual result

vars are written, finals are not

Expected result

all fields must be written - vars and finals

Versions

Flutter 2.0.6
json_annotation: ^4.0.0
json_serializable: ^4.1.0

MatrixDev avatar May 12 '21 15:05 MatrixDev

This is by design. We only "round-trip" values that can be provided when we create the value.

You can always wrap the generated value and add in the final value.

See https://github.com/google/json_serializable.dart/issues/274

kevmoo avatar May 14 '21 19:05 kevmoo

@kevmoo is there any reasoning for this? it is very strange that explicitly saying that I want to serialize something does nothing. At very least codegen should throw an error if this is the case. Explicit stuff cannot be simply ignored, it took me some time to find why API calls where not working because of this.

MatrixDev avatar May 17 '21 09:05 MatrixDev

This is bizarre... we have a type, we need to write it into our payload so the server knows what class this is.

I don't understand the rationale.

class Address {
  final String street;

  const Address({
    this.street = '',
    this.street2 = '',
    this.city = '',
    this.state = '',
    this.postalCode = '',
    this.country = '',
  });

  final String type= "Address"; // We need this in the payload... why is this not a valid use case?
}

This is the elegant approach, not being able to do this leads to a can of worms... we can't be const anymore, which causes all kinds of issues with Dart and constructors, or we violate seperation of concerns and have a bunch of hacky hard to maintain code that injects types into payloads, which gets even harder with nesting, for example serializing Customer(address: Address()) where Address needs a key injected... big hassle.

Why not at least give us JsonKey(include: true) or an option to includeFinal for the project as a whole?

esDotDev avatar Jun 09 '21 18:06 esDotDev

I'll reopen this issue. PR's are welcome!

kevmoo avatar Jun 10 '21 23:06 kevmoo

This sounds crazy. Are you saying this won't work:

I haven't tried json_serializable yet, I'm looking for a replacement for simple_json (which is the best, but not being updated)

I can't have finals?

class AnnotationModel { AnnotationModel({ required this.containerId, required this.content, required this.createdAt, required this.id, required this.modifiedAt, required this.status, });

final String containerId; final String content; final DateTime createdAt; final String id; final DateTime modifiedAt; final String status; }

sgehrman avatar Jun 30 '21 00:06 sgehrman