Search code examples
scalaavroevent-busavro-tools

create json representation for decimal logical type and byte types for avro schema


I am trying to create JSON string as per below avro schema, for decimal value. https://avro.apache.org/docs/1.8.2/spec.html#Logical+Types

{
 "name": "score",
 "type": "bytes",
 "logicalType": "decimal",
 "precision": 10,
 "scale": 5
 }

value

"score":3.4,

I am getting exception

Caused by: org.apache.avro.AvroTypeException: Expected bytes. Got VALUE_NUMBER_FLOAT.

Instead of 3.4 if I give "\u0000" then it works but this is representation of 0, how I will get representation for 3.4? For now I am creating hard-coded JSON String, but in future I have to convert output into Decimal, how I can do that in scala.

Is there any way to convert value into decimal logical format?


Solution

  • Java code:

    byte[] score = new BigDecimal("3.40000").unscaledValue().tobyteArray();
    for (byte b : score) {​
        System.out.println(String.format("\\u%04x", b));
    }
    

    Will print out following:

    \u00fa
    \u00cf
    \u00e0
    

    You then need to write json score value like this:

    "score":"\u00fa\u00cf\u00e0",
    

    And it should translate to 3.40000. The reason why 3.40000 is because 'scale' in your schema has value 5. If scale would have value 2, then we would have new BigDecimal("3.40")

    Scala function for converting BigDecimal to json so avro will understand it

    def toJsonString(value: java.math.BigDecimal): String = {
        val bytes = value.unscaledValue().toByteArray
        bytes
          .map(_.formatted("\\u%04x"))
          .mkString
    }