Skip to content

Would like a way to specify a type supports toJson and fromJson #53758

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
eseidel opened this issue Oct 15, 2023 · 2 comments
Open

Would like a way to specify a type supports toJson and fromJson #53758

eseidel opened this issue Oct 15, 2023 · 2 comments
Labels
area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-convert type-enhancement A request for a change that isn't a bug

Comments

@eseidel
Copy link
Contributor

eseidel commented Oct 15, 2023

Would like a way to specify a type supports toJson and fromJson

Maybe this is related to #34415 or #35693?

Specifying a type supports toJson or fromJson may also be separate bugs. Say you wanted to offer an generic storage class which used json as the storage medium.
One such example from code I've written:
https://github.com/eseidel/space_traders/blob/8fc555e6d5e9c7a3749a3d5e9ca41de55ce9a4ff/packages/cli/lib/cache/json_store.dart
https://github.com/eseidel/space_traders/blob/8fc555e6d5e9c7a3749a3d5e9ca41de55ce9a4ff/packages/cli/lib/cache/json_list_store.dart

e.g.

class JsonStore<T> {
...
}

You have no way to specify that T supports toJson and fromJson (again, possibly separate problems). The best workaround I know of is to have all subclasses pass down toJson and fromJson functions to the superclass, e.g.

class JsonStore<T> {
  JsonStore(Map<String, dynamic> Function(T) toJson, T Function(Map<String, dynamic) fromJson)...
} 

(Yes, maybe those signature are supposed to take/return dynamic instead of Map<String, dynamic>.)

You could work-around the toJson case, by casting T to dynamic and calling toJson on dynamic? (I think that would work?)

But I know of no way to work around passing fromJson since that's typically a factory method.

In C++ you might handle this by having a separate Traits definition that you instantiated within your superclass to provide extra metadata (including toJson/fromJson functions) for T.

In Rust, you could restrict the type T to only those having a Trait "JsonSerializable" or similar. I don't think such is possible in Dart?

@eseidel
Copy link
Contributor Author

eseidel commented Oct 15, 2023

It's also hard to use toJson and fromJson in generics in other contexts.

For example (due to some OpenAPI bugs) I need to write a copy method which goes through Json serialization. I'd love to be able to do that generically, but I can't due to it not being possible to access fromJson from within a generic, so instead I have:

extension on OpenAPIClass {
  OpenAPIClass deepCopy() {
    // OpenAPIClass.toJson doesn't recurse (openapi gen bug), so use jsonEncode.
    return OpenAPIClass.fromJson(jsonDecode(jsonEncode(toJson())))!;
  }
}

Would love to be able to write:

T copyViaJson<T is Jsonable>(T object) {
  return T.fromJson(jsonDecode(jsonEncode(toJson())));
}

I guess to do that, I'd need Rust-style traits, since in this case, fromJson isn't universally defined (for example OpenAPI defines their fromJson as T? T.fromJson(dynamic) instead of the typical T T.fromJson(dynamic) so you'd want to be able to do this generically. 😮‍💨

@lrhn
Copy link
Member

lrhn commented Oct 15, 2023

Dart currently has no way to support the fromJson use-case because you can't abstract over static properties of a class declaration.
There is a number of issues asking for such a feature, called things like abstract static methods, virtual static methods or meta-classes, like #34415. Generally, that has to be a language issue, which means in the language repository, so I'm keeping this issue for the toJson part.

For toJson it's just a matter of someone declaring an interface with a method Object? ToJson().
We could declare it on the platform libraries, but it would be more appropriate to declare it alongside the code that will call the method.

I'd probably never use such a method myself, creating an intermediate data structure seems like unnecessary overhead. It's almost certainly going to be converted to something else again afterwards, #35693 is a better approach, but doesn't work directly with a toJson member.

@lrhn lrhn added area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-convert type-enhancement A request for a change that isn't a bug labels Oct 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-convert type-enhancement A request for a change that isn't a bug
Projects
None yet
Development

No branches or pull requests

2 participants