Search code examples
scalapureconfig

Pure config enum


Pure config can't pars capital letters in conf

  sealed trait Occupation extends Product with Serializable


  object Occupation {
    case class Employed(job: String) extends Occupation

    object Employed {
      implicit val employedReader = deriveReader[Employed]
    }

    case object Unemployed extends Occupation {
      implicit val unemployedReader = deriveReader[Unemployed.type]
    }

    case object Student extends Occupation {
      implicit val studentReader = deriveReader[Student.type]
    }

    implicit val occupationReader = deriveReader[Occupation]
  }

  case class WorkingPerson(name: String, surname: String, occupation: Occupation)

  val res = ConfigSource.string("{ name: Isaac, surname: Newton, occupation.type: student }").load[WorkingPerson]

It works, but I need enum value like 'StudenT' and if I do so I got "ConvertFailure(UnexpectedValueForFieldCoproductHint(Unquoted("student"))"


Solution

  • If you want to change how the field is being read you need to provide a hint.

    For sealed families, PureConfig provides a way to customize the conversion without replacing the default ConfigReader. By putting in scope an instance of CoproductHint for that sealed family, we can customize how the disambiguation is made. For example, if type clashes with one of the fields of a case class option, we can use another field.

    import pureconfig.generic.FieldCoproductHint
    implicit val animalConfHint = new FieldCoproductHint[AnimalConf]("kind")
    

    FieldCoproductHint can also be adapted to write class names in a different way. First, define a new FieldCoproductHint in implicit scope:

    implicit val animalConfHint = new FieldCoproductHint[AnimalConf]("type") {
      override def fieldValue(name: String) = name.dropRight("Conf".length)
    }
    

    In this case, adding FieldCoproductHint[Occupation] is what you need to do

    implicit val occupationConfHint = new FieldCoproductHint[Occupation]("type") {
      override def fieldValue(name: String) = name
    }
    

    I created a working example in scastie


    Do you really need to use the Semi-Automatic derivation? You can get the same result just using the automatic one.

    Here is the working example in scatsie

    • build.sbt
    libraryDependencies += "com.github.pureconfig" %% "pureconfig" % "0.14.0"
    
    • main.scala
    import pureconfig._
    import pureconfig.generic.FieldCoproductHint
    import pureconfig.generic.auto._
    
    sealed trait Occupation extends Product with Serializable
    
    implicit val occupationConfHint = new FieldCoproductHint[Occupation]("type") {
      override def fieldValue(name: String) = name
    }
    
    object Occupation {
      case class Employed(job: String) extends Occupation
      case object Unemployed extends Occupation
      case object StudenT extends Occupation
    }
    
    case class WorkingPerson(name: String, surname: String, occupation: Occupation)
    
    val res = ConfigSource.string("{ name: Isaac, surname: Newton, occupation.type: StudenT }").load[WorkingPerson]
    println(res)