Skip to content
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

feat: implement first version of sealed class serialization #1483

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

O-Hannonen
Copy link

Whats included

This PR is a proposal related to #1342. Since the issue asked for a PR only to evaluate if adding this functionality is worth the added complexity, this PR DOES NOT (yet) include:

  • tests for the new functionality
  • documentation for the new functionality
  • and consideration for all the different edge cases (eg. error handling for unsupported config combos)

I'd be happy to contribute towards those too if the maintainers give green light.

Things to discuss / consider

  • Should genericArgumentFactories be supported and how? Or should it warn / throw as invalid config combo?
  • Should there be a UnionKey annotation similar to JsonKey allowing naming change per sealed implementation?
  • Should the generator warn / throw if discriminator is also present as sealed class implementations field? Would lead to conflict in generated toJson method where class fields are added to the output with spread operator

Copy link
Collaborator

@kevmoo kevmoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm impressed, yo. A lot of folks have asked for this.

I think I like your approach. You're absolutely right, the devil is in the details here...lots of overlapping issues.

I'd avoid the generic factories for now. It'll likely be a HUGE mess that won't affect most folks.

If you look at many of my previous PRs, there is usually more code in tests than there is in the actual implementation.

If you're game to run with what you have, I'm happy to support you. Very cool!

/// If [functionBodyParts] has only one element, expression body is used.
///
/// ```dart
/// '''
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't have ''' here. Just the dart code should be fine.

@O-Hannonen
Copy link
Author

Superb! I'll continue working on this over the weekend.

Haven't checked the testing practices of this project at all yet so might need some guidance on those, but let's see

@kevmoo
Copy link
Collaborator

kevmoo commented Apr 3, 2025

I highly recommend looking through other PRs that change something substantial. You'll get inspiration!

Comment on lines +113 to +127
if (element.isSealed) {
sealedSubClasses(element).forEach((sub) {
final annotationConfig = jsonSerializableConfig(sub, _generator);

if (annotationConfig == null) {
throw InvalidGenerationSourceError(
'The class `${element.displayName}` is sealed but its '
'subclass `${sub.displayName}` is not annotated with '
'`JsonSerializable`.',
todo: 'Add `@JsonSerializable` annotation to ${sub.displayName}.',
element: sub,
);
}
});
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the other checks we can do when generating subclass but not this one as the generator will never get there for the subclass if its not annotated. IMO would be cleaner if all the checks would be done with lookups from subclass to superclass (would not need to use the sealedSubClasses method here yet).

Should sealedSubClasses be passed to decode/encode helpers if its already evaluated here? Now its called again in the helpers...

Comment on lines +151 to +152
'SubWithConflictingDiscriminatorWithDefaultNameExt',
'SubWithConflictingDiscriminatorWithDefaultNameImpl',
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is some overlap in these as they test both the use of extends and implements keywords. The analyzer treats them differently within ClassElement (one comes from .interfaces and one from .supertype) so there is a risk that some refactor would break one but not other

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

glad to have both! good thinking!

@O-Hannonen
Copy link
Author

@kevmoo Did I miss any type of tests that would need to be added? Or combos of unsupported configurations?

@O-Hannonen O-Hannonen requested a review from kevmoo April 7, 2025 18:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants