具有Scala枚举字段的案例类的自动类型派生

时间:2016-12-07 20:25:52

标签: scala typeclass shapeless

我编写了自动类型类派生,以便为case类自动生成elasticsearch Json映射。 为此,我在无形状中使用TypeClass类型。 我遇到的问题是我们使用的case类中的许多字段都是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"))
  }

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

以下是推导代码:

  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)
        }
      }
    }
  }

1 个答案:

答案 0 :(得分:0)

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

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是一些枚举类型。