coursera / courier

Data interchange for the modern web + mobile stack.
http://coursera.github.io/courier/
Apache License 2.0
98 stars 24 forks source link

transform "0" to boolean #53

Open ilijaljubicic opened 7 years ago

ilijaljubicic commented 7 years ago

Hello

I have a case where json has keys with boolean values encoded as strings "0" and "1". It is from external system and cannot influence it.

Did implement coercer and custom type, and managed to get coerced values from "0" or "1" to IntBoolean(false) and IntBoolean(true) but cannot manged to get those values with record.data() nor to get them into avro.

Simple example of what I did is

IntoBooleanRecord.courier

namespace test
record IntBooleanRecord {
  key : IntBoolean
}

IntBooleanCoercer.scala

package test

import com.linkedin.data.template.{Custom, DirectCoercer}

case class IntBoolean(value: Boolean) extends AnyVal

class IntBooleanCoercer extends DirectCoercer[IntBoolean] {

  override def coerceInput(obj: IntBoolean): AnyRef = {
    Boolean.box(obj.value)
  }

  override def coerceOutput(obj: Any): IntBoolean = {
    obj match {
      case value: String =>
        if (value =="0") {
          IntBoolean(false)
        }else if (value =="1") {
            IntBoolean(true)
        } else {
          throw new IllegalArgumentException(s"$value is not 0 or 1")
        }
      case _: Any =>
        throw new IllegalArgumentException(
          s"Field must be string with value 0 or 1, but was ${obj.getClass}"
        )
    }
  }
}

object IntBooleanCoercer {
  registerCoercer()
  def registerCoercer(): Unit = {
    Custom.registerCoercer(new IntBooleanCoercer, classOf[IntBoolean])
  }
}

IntBoolean.courier

namespace test

@scala.class = "test.IntBoolean"
@scala.coercerClass = "test.IntBooleanCoercer"
typeref IntBoolean = boolean

scala code to test

val json=

        """{
        |     "key": "1"
        |}""".stripMargin

  val dataMap = DataTemplates.readDataMap(json)
  val record=IntBooleanRecord(dataMap,DataConversion.SetReadOnly)

  println(record) // IntBooleanRecord(IntBoolean(true))
  println(record.data()) // {key=1}

I was expecting for record.data() to output {key=true}

Is there something I am doing wrong or this is not supposed to function this way? if not, what would be the way to do it? Help would be appreciated.

ilijaljubicic commented 7 years ago

why I think there is a bugs there is because when extracting avro schema from a record this is output: {"type":"record","name":"IntBooleanRecord","namespace":"test","fields":[{"name":"key","type":"boolean"}]}

thus avro schema matches what I would expect record.data to yield