Сериализация Enumeratum Circe - PullRequest
1 голос
/ 28 мая 2020

У меня есть простой класс case, например:

case class ColumnMetadata(name: String,
                          displayName: String,
                          description: Option[String],
                          attributeType: AttributeType)

sealed trait AttributeType extends EnumEntry

case object AttributeType extends Enum[AttributeType] with CirceEnum[AttributeType] {

 val values: immutable.IndexedSeq[AttributeType] = findValues

  case object Number extends AttributeType
  case object Text extends AttributeType
  case object Percentage extends AttributeType
}

И полуавтоматический кодировщик:

package object circe {

  implicit val config: Configuration = Configuration.default.withSnakeCaseMemberNames


  implicit val columnMetaDecoder: Decoder[ColumnMetadata] = deriveConfiguredDecoder
  implicit val columnMetaEncoder: Encoder[ColumnMetadata] = deriveConfiguredEncoder

  implicit val columnTypeDecoder: Decoder[AttributeType] = deriveConfiguredDecoder
  implicit val columnTypeEncoder: Encoder[AttributeType] = deriveConfiguredEncoder
}

Однако, когда я провожу тест сериализации:

  ColumnMetadata("column1", "Column 1", Some("column1"), 
    AttributeType.withName("Text")).asJson

Я получаю:

  {
    "name" : "column1",
    "display_name" : "Column 1",
    "description" : "column1",
    "attribute_type" : {
      "Text": {}
    }
  }

Когда я хочу:

  {
    "name" : "column1",
    "display_name" : "Column 1",
    "description" : "column1",
    "attribute_type" : "Text"
  } 

Он работает, когда я использую автоматическое c деривацию, но я хочу использовать полуавтоматическое деривацию, поэтому Я могу использовать такую ​​функцию, как withSnakeCaseMemberNames.

1 Ответ

2 голосов
/ 28 мая 2020

Это ваша ошибка:


  implicit val columnTypeDecoder: Decoder[AttributeType] = deriveConfiguredDecoder
  implicit val columnTypeEncoder: Encoder[AttributeType] = deriveConfiguredEncoder

Это приведет к получению новых кодеков, рассматривая AttributeType как любую другую запечатанную черту, поэтому он будет использовать значение дискриминации (полуавтоматический режим всегда игнорирует существующие кодеки того типа, который они являются производными!).

Итак, вы создаете новые AttributeType кодеки, помещаете их в область, в которой они используются, и таким образом делаете эти новые реализации более приоритетными, чем те, которые получены из сопутствующего объекта. Более близкое неявное всегда побеждает.

Если вы не будете выводить кодеки (потому что уже существуют реализации, предоставляемые чертой CirceEnum), тогда он будет работать так, как вы ожидаете. делая это:

  implicit val columnMetaDecoder: Decoder[ColumnMetadata] = deriveConfiguredDecoder
  implicit val columnMetaEncoder: Encoder[ColumnMetadata] = deriveConfiguredEncoder

вы можете просто сделать это:

// make sure that Configuration is in scope by e.g. importing it
// or putting it in package object in the same package as case class
@ConfiguredJsonCodec
case class ColumnMetadata(name: String,
                          displayName: String,
                          description: Option[String],
                          attributeType: AttributeType)

Это избавит вас от усилий по созданию пакета кодеков и их ручному импорту везде, где они вам нужны. Например,

// imports

package object models_package {

  private[models_package] implicit val config: Configuration = Configuration.default.withSnakeCaseMemberNames
}
package models_package

// imports

@ConfiguredJsonCodec
case class ColumnMetadata(name: String,
                          displayName: String,
                          description: Option[String],
                          attributeType: AttributeType)

sealed trait AttributeType extends EnumEntry
object AttributeType extends Enum[AttributeType] with CirceEnum[AttributeType] {

 val values: immutable.IndexedSeq[AttributeType] = findValues

  case object Number extends AttributeType
  case object Text extends AttributeType
  case object Percentage extends AttributeType
}
...