Home > Back-end >  How to generate any protobuf Enum as String with only one TypeMapper?
How to generate any protobuf Enum as String with only one TypeMapper?

Time:02-19

For instance, I have some enums in my proto schema:

enum E1 {
     UNKNOWN = 0;
     OPTION_1 = 1;
     OPTION_2 = 2;
     OPTION_3 = 3;
}

enum E2 {
     UNKNOWN = 0;
     ANOTHER_OPTION_1 = 1;
     ANOTHER_OPTION_2 = 2;
     ANOTHER_OPTION_3 = 3;
}

message M {
    E1 my_enum_1 = 1;
    E2 my_enum_2 = 2;
}

I can generate scala classes with strings instead of enums by providing scalaPB TypeMappers:

TypeMapper(_.name)(E1.fromName(_).get)
TypeMapper(_.name)(E2.fromName(_).get)

But I don't want to copypaste same TypeMappers for any single Enum

Is there any way to make only one TypeMapper for all enums with scalaPB?

CodePudding user response:

Yes, this can be done.

If you want to make ScalaPB use String for all enums within a package, you can add package-scoped options file to tell ScalaPB to set the scala-type for each enum to a String using field transformations:

// options.proto:
syntax = "proto3";

import "scalapb/scalapb.proto";

option (scalapb.options) = {
  scope: PACKAGE,
  field_transformations : [
    {
      when : {
        type: TYPE_ENUM
      }
      set : {[scalapb.field] {type : 'String'}}
    }
}

The next step will be to define a typemapper for all enums. Borrowing from Ivan's answer, this could be defined as follows:

implicit def enumMapper[E <: GeneratedEnum](implicit ec: GeneratedEnumCompanion[E]) =
  TypeMapper[E, String](_.name)(ec.fromName(_).get)

If the above code is added to a package object in the same package as the generated code, or imported using the import option in ScalaPB, the typemapper will be found in implicit search.

CodePudding user response:

You can't completely avoid defining TypeMapper for each enum type you have. But you could create a helper method to create TypeMapper instances.

For example

import scalapb.GeneratedEnum
import scalapb.GeneratedEnumCompanion
import scalapb.TypeMapper

def enumMapper[E <: GeneratedEnum: GeneratedEnumCompanion] = {
  TypeMapper[E, String](_.name)(implicitly[GeneratedEnumCompanion[E]].fromName(_).get)
}

---UPDATE---

Following on @thesamet comment, if you add implicit to the method above and have it available in your implicit context, it will work.

This can be tested with following code that compiles

implicit def enumMapper...

val Enum1Mapper = implicitly[TypeMapper[E1]]

  • Related