freezed icon indicating copy to clipboard operation
freezed copied to clipboard

Freezed generator doesn't properly skip special characters in @JsonKey annotation

Open KhatibFX opened this issue 4 years ago • 6 comments

Minimal reproducing code:

import 'package:flutter/foundation.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:json_annotation/json_annotation.dart';

part 'worker_history_date.freezed.dart';
part 'worker_history_date.g.dart';

@freezed
abstract class WorkerHistoryDate with _$WorkerHistoryDate {
  const factory WorkerHistoryDate({
    @JsonKey(name: '\u0024numberLong') String numberLong, //\u0024 is $
  }) = _WorkerHistoryDate;
  factory WorkerHistoryDate.fromJson(Map<String, dynamic> json) =>
      _$WorkerHistoryDateFromJson(json);
}

Generated code:

// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named

part of 'worker_history_date.dart';

// **************************************************************************
// FreezedGenerator
// **************************************************************************

T _$identity<T>(T value) => value;
WorkerHistoryDate _$WorkerHistoryDateFromJson(Map<String, dynamic> json) {
  return _WorkerHistoryDate.fromJson(json);
}

class _$WorkerHistoryDateTearOff {
  const _$WorkerHistoryDateTearOff();

  _WorkerHistoryDate call({@JsonKey(name: '$numberLong') String numberLong}) {
    return _WorkerHistoryDate(
      numberLong: numberLong,
    );
  }
}

// ignore: unused_element
const $WorkerHistoryDate = _$WorkerHistoryDateTearOff();

mixin _$WorkerHistoryDate {
  @JsonKey(name: '$numberLong')
  String get numberLong;

  Map<String, dynamic> toJson();
  $WorkerHistoryDateCopyWith<WorkerHistoryDate> get copyWith;
}

abstract class $WorkerHistoryDateCopyWith<$Res> {
  factory $WorkerHistoryDateCopyWith(
          WorkerHistoryDate value, $Res Function(WorkerHistoryDate) then) =
      _$WorkerHistoryDateCopyWithImpl<$Res>;
  $Res call({@JsonKey(name: '$numberLong') String numberLong});
}

class _$WorkerHistoryDateCopyWithImpl<$Res>
    implements $WorkerHistoryDateCopyWith<$Res> {
  _$WorkerHistoryDateCopyWithImpl(this._value, this._then);

  final WorkerHistoryDate _value;
  // ignore: unused_field
  final $Res Function(WorkerHistoryDate) _then;

  @override
  $Res call({
    Object numberLong = freezed,
  }) {
    return _then(_value.copyWith(
      numberLong:
          numberLong == freezed ? _value.numberLong : numberLong as String,
    ));
  }
}

abstract class _$WorkerHistoryDateCopyWith<$Res>
    implements $WorkerHistoryDateCopyWith<$Res> {
  factory _$WorkerHistoryDateCopyWith(
          _WorkerHistoryDate value, $Res Function(_WorkerHistoryDate) then) =
      __$WorkerHistoryDateCopyWithImpl<$Res>;
  @override
  $Res call({@JsonKey(name: '$numberLong') String numberLong});
}

class __$WorkerHistoryDateCopyWithImpl<$Res>
    extends _$WorkerHistoryDateCopyWithImpl<$Res>
    implements _$WorkerHistoryDateCopyWith<$Res> {
  __$WorkerHistoryDateCopyWithImpl(
      _WorkerHistoryDate _value, $Res Function(_WorkerHistoryDate) _then)
      : super(_value, (v) => _then(v as _WorkerHistoryDate));

  @override
  _WorkerHistoryDate get _value => super._value as _WorkerHistoryDate;

  @override
  $Res call({
    Object numberLong = freezed,
  }) {
    return _then(_WorkerHistoryDate(
      numberLong:
          numberLong == freezed ? _value.numberLong : numberLong as String,
    ));
  }
}

@JsonSerializable()
class _$_WorkerHistoryDate
    with DiagnosticableTreeMixin
    implements _WorkerHistoryDate {
  const _$_WorkerHistoryDate({@JsonKey(name: '$numberLong') this.numberLong});

  factory _$_WorkerHistoryDate.fromJson(Map<String, dynamic> json) =>
      _$_$_WorkerHistoryDateFromJson(json);

  @override
  @JsonKey(name: '$numberLong')
  final String numberLong;

  @override
  String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
    return 'WorkerHistoryDate(numberLong: $numberLong)';
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties
      ..add(DiagnosticsProperty('type', 'WorkerHistoryDate'))
      ..add(DiagnosticsProperty('numberLong', numberLong));
  }

  @override
  bool operator ==(dynamic other) {
    return identical(this, other) ||
        (other is _WorkerHistoryDate &&
            (identical(other.numberLong, numberLong) ||
                const DeepCollectionEquality()
                    .equals(other.numberLong, numberLong)));
  }

  @override
  int get hashCode =>
      runtimeType.hashCode ^ const DeepCollectionEquality().hash(numberLong);

  @override
  _$WorkerHistoryDateCopyWith<_WorkerHistoryDate> get copyWith =>
      __$WorkerHistoryDateCopyWithImpl<_WorkerHistoryDate>(this, _$identity);

  @override
  Map<String, dynamic> toJson() {
    return _$_$_WorkerHistoryDateToJson(this);
  }
}

abstract class _WorkerHistoryDate implements WorkerHistoryDate {
  const factory _WorkerHistoryDate(
      {@JsonKey(name: '$numberLong') String numberLong}) = _$_WorkerHistoryDate;

  factory _WorkerHistoryDate.fromJson(Map<String, dynamic> json) =
      _$_WorkerHistoryDate.fromJson;

  @override
  @JsonKey(name: '$numberLong')
  String get numberLong;
  @override
  _$WorkerHistoryDateCopyWith<_WorkerHistoryDate> get copyWith;
}

Analyzer error: const_with_non_constant_argument

Arguments of a constant creation must be constant expressions.

Flutter doctor:

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel beta, v1.17.0-3.2.pre, on Mac OS X 10.15.3 19D76, locale en-AE)
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[✓] Xcode - develop for iOS and macOS (Xcode 11.4.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 3.6)
[✓] Connected device (2 available)

Running latest 0.10.7 Freezed and 0.7.1 freezed generator

By the way, thanks for this awesome library! Managing API responses with this is a breeze!

KhatibFX avatar Apr 26 '20 09:04 KhatibFX

I came across the same issue using the appwrite SDK account API and parsing the returned user that has a field '$id'.

flutcon avatar Jun 06 '20 08:06 flutcon

I've also encountered a similar problem when using the Appwrite SDK account API and parsing the returned user that has a field $id or $createAt. It's causing some problems with the parsing process, and I'm unsure of the best way to handle it. Have you found any solutions or workarounds that might be helpful? I'd appreciate any advice or insights you might have on this issue. Thank you!"

freezer log

An error FormatterException occurred while formatting the generated source for `` which was output to ``. This may indicate an issue in the generator, the input source code, or in the source formatter. Could not format because the source could not be parsed

aliazimoshan avatar May 03 '23 06:05 aliazimoshan

@aliazimoshan Do you have a reproducible example for your issue? Because on latest freezed using unicode or rawString both work fine:

import 'dart:convert';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'foo_bar.freezed.dart';
part 'foo_bar.g.dart';

@freezed
class FooBar with _$FooBar {
  const factory FooBar({
    @JsonKey(name: '\u0024foo') required String foo, // unicode $
    @JsonKey(name: r'$bar') required int bar, // raw String
  }) = _FooBar;

  factory FooBar.fromJson(Map<String, dynamic> json) => _$FooBarFromJson(json);
}

void main() async {
  final jsonMap = json.decode(r'{"$foo": "someString", "$bar": 1}') as Map<String, dynamic>;
  print(jsonMap); // {$foo: someString, $bar: 1}
  final fooBar = FooBar.fromJson(jsonMap);
  print(fooBar);  // FooBar(foo: someString, bar: 1)
}

SunlightBro avatar May 03 '23 07:05 SunlightBro

@SunlightBro Thanks for your help, Your response was incredibly helpful and worked in the latest version of Freezed.

aliazimoshan avatar May 03 '23 08:05 aliazimoshan

I have a problem that is similar like this, I guess.

Producing code:


@freezed
class TimeslotForTheDay with _$TimeslotForTheDay {
  const TimeslotForTheDay._();

  factory TimeslotForTheDay({
    required String id,
    @JsonKey(name: 'planned_quantity') int? plannedQuantity,
    @JsonKey(name: 'fact_quantity') int? factQuantity,
    @JsonKey(name: 'start_time', toJson: _toJson, fromJson: _fromJson) required DateTime startTime,
    @JsonKey(name: 'end_time', toJson: _toJson, fromJson: _fromJson) required DateTime endTime,
  }) = _TimeslotForTheDay;

  static int _toJson(DateTime value) => value.millisecondsSinceEpoch;

  static DateTime _fromJson(int value) => DateTime.fromMillisecondsSinceEpoch(value);

  factory TimeslotForTheDay.fromJson(Map<String, dynamic> json) => _$TimeslotForTheDayFromJson(json);
}

It will generate an .freezed.dart with errors 'Arguments of a constant creation must be constant expressions.'

abikko avatar Apr 23 '24 09:04 abikko

Feel free to make a PR :)

rrousselGit avatar Apr 23 '24 09:04 rrousselGit