带有 Scala 枚举字段的 case classes 的自动类型 class 推导

Automatic type class derivation for case classes with Scala Enumeration fields

我已经编写了自动类型 class 推导,以便为案例 classes 自动生成 elasticsearch Json 映射。 为此,我在 shapeless 中使用 TypeClass 类型 class。 我遇到的问题是,我们使用的 classes 中的许多字段都是 Scala 枚举。 例如

  object ConnectionState extends Enumeration {
    type ConnectionState = Value
    val ordering, requested, pending, available, down, deleting, deleted, rejected = Value
  }

object ProductCodeType extends Enumeration {
    type ProductCodeType = Value
    val devpay, marketplace = Value
  }

看来我必须为每个定义的枚举定义一个特定的隐式实例,以便自动推导将其拾取(例如,ConnectionStateProductCodeType)。 我不能有一个 implicit def 用于枚举,例如

  implicit def enumerationMapping: MappingEncoder[Enumeration] = new MappingEncoder[Enumeration] {
    def toMapping = jSingleObject("type", jString("text"))
  }

这将适用于所有枚举类型。 我尝试使类型 class 协变,以及其他一些东西,但没有任何帮助。 有什么想法吗?

这里是推导代码:

  object Mapping {
    trait MappingEncoder[T] {
      def toMapping: Json
    }
    object MappingEncoder extends LabelledProductTypeClassCompanion[MappingEncoder] {
      implicit val stringMapping: MappingEncoder[String] = new MappingEncoder[String] {
        def toMapping = jSingleObject("type", jString("text"))
      }
      implicit val intMapping: MappingEncoder[Int] = new MappingEncoder[Int] {
        def toMapping = jSingleObject("type", jString("integer"))
      }
      implicit def seqMapping[T: MappingEncoder]: MappingEncoder[Seq[T]] = new MappingEncoder[Seq[T]] {
        def toMapping = implicitly[MappingEncoder[T]].toMapping
      }
      implicit def optionMapping[T: MappingEncoder]: MappingEncoder[Option[T]] = new MappingEncoder[Option[T]] {
        def toMapping = implicitly[MappingEncoder[T]].toMapping
      }
      object typeClass extends LabelledProductTypeClass[MappingEncoder] {
        def emptyProduct = new MappingEncoder[HNil] {
          def toMapping = jEmptyObject
        }

        def product[F, T <: HList](name: String, sh: MappingEncoder[F], st: MappingEncoder[T]) = new MappingEncoder[F :: T] {
          def toMapping = {
            val head = sh.toMapping
            val tail = st.toMapping
            (name := head) ->: tail
          }
        }
        def project[F, G](instance: => MappingEncoder[G], to: F => G, from: G => F) = new MappingEncoder[F] {
          def toMapping = jSingleObject("properties", instance.toMapping)
        }
      }
    }
  }

我能够通过向范围添加额外的隐式定义来解决问题:

implicit def enumerationMapping[T <: Enumeration#Value]: MappingEncoder[T] = new MappingEncoder[T] {
  def toMapping = jSingleObject("type", jString("text"))
}
implicit def enumerationSeqMapping[T <: Enumeration#Value]: MappingEncoder[Seq[T]] = new MappingEncoder[Seq[T]] {
  def toMapping = jSingleObject("type", jString("text"))
}

需要第二个隐式,因为某些情况下 类 具有 Seq[T] 类型的成员,其中 T 是某种枚举类型。