google/built_value.dart

Supporting multiple keys for the same field during deserialization

sabinbajracharya opened this issue · 2 comments

Problem statement:

I have a model called "Calendar" which needs to parse either the following json

{
    "cid": "101",
    "ut": "20230715",
    "cb": "admin@admin.com",
    "st": 1
  }

or the following one depending on some use cases

{
    "calendar_id": "101",
    "updated_time": "20230715",
    "created_by": "admin@admin.com",
    "status": 1
  }

Basically the value will be the same only difference is the key. The reason for this is that the "Calendar" model has lots of fields and this data is in a file which is kept in the asset folder of the application. So, the fields are shortened to reduce some space taken by the file.

For deserialization, I need to be able to parse the json with both possible keys for the same value. But for serialization I only need the keys shown in the second json so no problem with serialization.

The interim solution that I am using is the following:

  • Extend the "_$CalendarModelSerializer" generated by built_value and override the "deserialize" method to add two cases for each value.
  • Use this extended serializer to decode the json but use the originally generated serializer to serialize the model.
class _$CalendarModelWithMultipleKeySerializer extends _$CalendarModelSerializer {
  @override
  CalendarModel deserialize(
      Serializers serializers, Iterable<Object?> serialized,
      {FullType specifiedType = FullType.unspecified}) {
    final result = CalendarModelBuilder();

    final iterator = serialized.iterator;
    while (iterator.moveNext()) {
      final key = iterator.current! as String;
      iterator.moveNext();
      final Object? value = iterator.current;
      switch (key) {
        case 'calendar_id':
        case 'cid':
          result.calendarId = serializers.deserialize(value,
              specifiedType: const FullType(String))! as String;
          break;
        case 'status'
        case 'st':
          result.status = serializers.deserialize(value,
              specifiedType: const FullType(int))! as int;
          break;
        case 'created_by':
        case 'cb':
          result.createdBy = serializers.deserialize(value,
              specifiedType: const FullType(String))! as String;
          break;
        case 'updated_time':
        case 'ut':
          result.updatedAt = serializers.deserialize(value,
              specifiedType: const FullType(DateTime))! as DateTime;
          break;
      }
    }
    return result.build();
  }
}

So, is there any possible way to add two "wireName" for the same field? Or any workaround so that I don't have to manually add two cases everytime I need to change or add a new field.

I think that this PR

#1119

exactly does what you want by adding an oldWireNames setting that can list multiple alternative wire names for deserializing a field. It does not let you use alternatives for serializing.

--but there hasn't been any update there in a while; let me ask. Thanks.

@davidmorgan That's exactly what I am looking for and it looks like the PR is almost done. Thanks!