Closed nicolashemonic closed 6 years ago
The exception is thrown by Dart:convert json.encode in redux_persist.dart.
try {
// Encode to JSON
// TODO: add custom serializer
transformedJson = json.encode(versionedState);
} catch (error) {
throw new SerializationException('Save: ${error.toString()}');
}
Following Dart documentation, if value contains objects that are not directly encodable to a JSON string (a value that is not a number, boolean, string, null, list or a map with string keys), the toEncodable function is used to convert it to an object that must be directly encodable.
If toEncodable is omitted, it defaults to a function that returns the result of calling .toJson() on the unencodable object.
The solution to resolve JSON encode exception:
Each object model (that are not map with string keys) must implement .toJson(). My state object models are now like this counter state:
class CounterState {
final int value;
const CounterState({this.value = 0});
CounterState copyWith({int value}) {
return new CounterState(value: value ?? this.value);
}
// ! Add toJson serializer
dynamic toJson() => {'value': value};
}
For more details, Flutter JSON Serialization documentation can help.
@Cretezy I think it would be nice to have more documentation about this and save lot of time of everyone. 😉
Maintaining serialization could be complex when app growth. For anyone search a better solution than writing toJson() manually you can find below an example of how to implement JSON Serializable library with redux_persist.
dependencies:
json_serializable:
dev_dependencies:
build_runner:
import 'package:json_annotation/json_annotation.dart';
import 'counter_state.dart';
part 'app_state.g.dart';
@JsonSerializable()
class AppState extends Object with _$AppStateSerializerMixin {
final CounterState counter;
AppState({this.counter});
factory AppState.fromJson(dynamic json) => _$AppStateFromJson(json);
static AppState fromJsonDecoder(dynamic json) => AppState.fromJson(json);
}
import 'package:json_annotation/json_annotation.dart';
part 'counter_state.g.dart';
@JsonSerializable()
class CounterState extends Object with _$CounterStateSerializerMixin {
final int value;
CounterState({this.value = 0});
CounterState copyWith({int value}) {
return new CounterState(value: value ?? this.value);
}
factory CounterState.fromJson(dynamic json) => _$CounterStateFromJson(json);
}
final persistor = new Persistor<AppState>(
storage: new FlutterStorage("mobile-starter-kit"),
decoder: AppState.fromJsonDecoder);
final store = new Store<AppState>(appReducer,
initialState: new AppState(
counter: new CounterState()
),
middleware: [persistor.createMiddleware()]);
persistor.load(store);
Then, you can generates json serialization code using flutter packages pub run build_runner build
command before flutter run
.
More details in flutter doc.
It definitely needs a better way to serialize things. I was planning on adding module serializers.
I'll try to get to it this weekend, been very busy recently. Let me know of your ideas on implementations
This was added in 0.8.0-rc.0, let me know if that fixes your problem!
Hi,
I installed latest version:
When an action is dispatched the following exception is thrown:
SerializationException: Save: Converting object to an encodable object failed: Instance of 'AppState'
Find below redux_persist implementation.
Main
App State
App Reducer
Thanks for your help !