Search code examples
javascalaavro

Scala Map[String, Int] class cast disaster


Asserting one Map[String, Int] to another in a unit test I get:

Map(bar -> 114, foo -> 5) did not equal Map("foo" -> 5, "bar" -> 114)

Note the keys are not quoted on the left, but are quoted on the right.

The left has round tripped through Kafka with Avro serialization as part of a GenericRecord. The right is the test fixture which I constructed like this:

program_int_args = Map[String, Int]("foo" -> 5, "bar" -> 114)

Once I get it back from Kafka, I decode the Avro message like this:

 val program_int_args_ =
        record.get("program_int_args")
          .asInstanceOf[java.util.Map[String, Integer]]
          .asScala
          .toMap[String, Integer]
          .mapValues(Integer2int(_))

Questions:

  1. Why the absence of quotes after coming from the GenericRecord?
  2. Why the presence of quotes from the constructed map?
  3. How can I make these equal?

Per Thomas Klager's comment, I check the classes of the keys, and indeed they are different:

class org.apache.avro.util.Utf8 did not equal class java.lang.String

So updating the question:

How can the Utf8 type be a key in a Map[String, Int] yet not be equal to the same data as a String?


Solution

  • I think because of type erasure both conversions

    .asInstanceOf[java.util.Map[String, Integer]]
    
    .toMap[String, Integer]
    

    don't really check the type of the keys and values within the map.

    You might try

    val program_int_args_ =
            record.get("program_int_args")
              .asInstanceOf[java.util.Map[Object, Integer]]
              .asScala
              .toMap[Object, Integer]
              .map { case (k, v) => (k.toString, Integer2int(v))}
    

    instead, which converts the keys to String.