trevorwang / retrofit.dart

retrofit.dart is an dio client generator using source_gen and inspired by Chopper and Retrofit.
https://mings.in/retrofit.dart/
MIT License
1.08k stars 251 forks source link

Support toJson extension methods for enum conversion in retrofit_generator #711

Open KOREAparksh opened 2 months ago

KOREAparksh commented 2 months ago

Is your feature request related to a problem? Please describe.

I've noticed that retrofit_generator currently uses the toJson method within an enum for conversion when it exists, instead of using .name. I'm wondering if this functionality might be extended to cases where the toJson method is defined as an extension on the enum. It would be really helpful to clarify this behavior.

Describe the solution you'd like

I think it would be great if retrofit_generator could recognize and use toJson methods defined as extensions on enums. This could potentially allow for more flexible and consistent enum serialization across different code structures. Perhaps retrofit_generator could check for extension methods named toJson on enums and use them for conversion when present, similar to how it currently handles in-enum toJson methods?

Describe alternatives you've considered

I've thought about a few alternatives, but they all seem to have some drawbacks:

  1. We could manually implement custom converters for each enum that uses extension methods, but that might be time-consuming.
  2. Another option would be to modify our code structure to always include toJson methods within the enum definition, but that might not always be the most elegant solution.
  3. We could also consider using a different code generation tool that supports extension methods for enum conversion, but we'd prefer to stick with retrofit_generator if possible.

Additional context

To give you an idea of what I'm working with, here's an example of our current code structure:

import 'package:json_annotation/json_annotation.dart';

enum RoomStatusType {
  @JsonValue('Created')
  created,

  @JsonValue('Waiting')
  waiting,

  @JsonValue('Playing')
  playing,

  @JsonValue('Closed')
  closed,
}

extension RoomStatusTypeExtension on RoomStatusType {
  String toJson() {
    switch (this) {
      case RoomStatusType.created:
        return 'Created';
      case RoomStatusType.waiting:
        return 'Waiting';
      case RoomStatusType.playing:
        return 'Playing';
      case RoomStatusType.closed:
        return 'Closed';
    }
  }
}

In this example, we have an enum RoomStatusType with a toJson method defined as an extension. It would be really helpful if retrofit_generator could use this extension method for conversion, just as it does with in-enum toJson methods.

I appreciate any thoughts or feedback you might have on this idea!

YukiAttano commented 2 months ago

I like the idea that the code generator could make use of extension methods, which would require to manually import them in your RestClient file as it otherwise couldn't know how to find them.

But i do have a question about your example. If you have access to the enum, why would you define the toJson() from hand in an extension. And why are you using the JsonValue annotation if you don't access them but type the value by hand in the extension?

KOREAparksh commented 1 month ago

Hello, I apologize for the delayed response šŸ˜„ The reason I raised this issue is because I upgraded the retrofit_generator version from 5 to 7.

Previously, when sending an enum as a query parameter in an API call, even if the toJson function wasn't explicitly defined, it was automatically converted to toJson in the generated g.dart file. To address this, I had directly added a toJson function. (The reason for implementing it as an extension was simply for better readability.)

However, after upgrading to version 7, which now supports enums, .name is appended, resulting in unintended conversion in the URL during API calls. I happened to be using toJson as an extension function for readability, so I thought it would be beneficial if extension functions were also supported. That's why I decided to raise this issue.