Skip to content

Commit

Permalink
fix: preserve type when building dynamic json (#175)
Browse files Browse the repository at this point in the history
  • Loading branch information
octonato authored Jan 27, 2025
1 parent 8e0b53c commit c63c329
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ private[javasdk] final case class ViewClientImpl(
case Some(arg) =>
// Note: not Kalix JSON encoded here, regular/normal utf8 bytes
if (arg.getClass.isPrimitive || primitiveObjects.contains(arg.getClass)) {
val bytes = serializer.encodeDynamicToAkkaByteString(method.getParameters.head.getName, arg.toString)
val bytes = serializer.encodeDynamicToAkkaByteString(method.getParameters.head.getName, arg)
new BytesPayload(bytes, JsonSerializer.JsonContentTypePrefix + "object")
} else if (classOf[java.util.Collection[_]].isAssignableFrom(arg.getClass)) {
val bytes = serializer.encodeDynamicCollectionToAkkaByteString(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,9 +268,35 @@ class JsonSerializer {
typeName.split("#").head
}

private[akka] def encodeDynamicToAkkaByteString(key: String, value: String): ByteString = {
private[akka] def encodeDynamicToAkkaByteString(key: String, value: Any): ByteString = {
try {
val dynamicJson = objectMapper.createObjectNode.put(key, value)
val dynamicJson = {
// match all possible variants of createObjectNode.put method,
// except the one accepting bytes[]
value match {
case v: String => objectMapper.createObjectNode.put(key, v)

case v: Boolean => objectMapper.createObjectNode.put(key, v)
case v: java.lang.Boolean => objectMapper.createObjectNode.put(key, v)

case v: Short => objectMapper.createObjectNode.put(key, v)
case v: java.lang.Short => objectMapper.createObjectNode.put(key, v)

case v: Int => objectMapper.createObjectNode.put(key, v)
case v: java.lang.Integer => objectMapper.createObjectNode.put(key, v)
case v: java.math.BigInteger => objectMapper.createObjectNode.put(key, v)

case v: Long => objectMapper.createObjectNode.put(key, v)
case v: java.lang.Long => objectMapper.createObjectNode.put(key, v)

case v: Float => objectMapper.createObjectNode.put(key, v)
case v: java.lang.Float => objectMapper.createObjectNode.put(key, v)

case v: Double => objectMapper.createObjectNode.put(key, v)
case v: java.lang.Double => objectMapper.createObjectNode.put(key, v)
case v: java.math.BigDecimal => objectMapper.createObjectNode.put(key, v)
}
}
ByteString.fromArrayUnsafe(objectMapper.writeValueAsBytes(dynamicJson))
} catch {
case ex: JsonProcessingException =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,5 +361,64 @@ class JsonSerializationSpec extends AnyWordSpec with Matchers {
failed.getMessage shouldBe "Don't know how to serialize object of type null."
}

"encode a dynamic payload for string" in {
val payload = serializer.encodeDynamicToAkkaByteString("value", "abc")
payload.utf8String shouldBe """{"value":"abc"}"""
}

"encode a dynamic payload for boolean" in {
val payloadPrimitive = serializer.encodeDynamicToAkkaByteString("value", true)
payloadPrimitive.utf8String shouldBe """{"value":true}"""

val payloadObj = serializer.encodeDynamicToAkkaByteString("value", java.lang.Boolean.valueOf(true))
payloadObj.utf8String shouldBe """{"value":true}"""
}

"encode a dynamic payload for short" in {
val payloadPrimitive = serializer.encodeDynamicToAkkaByteString("value", 10.toShort)
payloadPrimitive.utf8String shouldBe """{"value":10}"""

val payloadObj = serializer.encodeDynamicToAkkaByteString("value", java.lang.Short.valueOf(10.toShort))
payloadObj.utf8String shouldBe """{"value":10}"""
}

"encode a dynamic payload for int" in {
val payloadPrimitive = serializer.encodeDynamicToAkkaByteString("value", 10)
payloadPrimitive.utf8String shouldBe """{"value":10}"""

val payloadObject = serializer.encodeDynamicToAkkaByteString("value", java.lang.Integer.valueOf(10))
payloadObject.utf8String shouldBe """{"value":10}"""

val payloadBigOne = serializer.encodeDynamicToAkkaByteString("value", java.math.BigInteger.valueOf(10))
payloadBigOne.utf8String shouldBe """{"value":10}"""
}

"encode a dynamic payload for long" in {
val payloadPrimitive = serializer.encodeDynamicToAkkaByteString("value", 10L)
payloadPrimitive.utf8String shouldBe """{"value":10}"""

val payloadObject = serializer.encodeDynamicToAkkaByteString("value", java.lang.Long.valueOf(10L))
payloadObject.utf8String shouldBe """{"value":10}"""
}

"encode a dynamic payload for float" in {
val payloadPrimitive = serializer.encodeDynamicToAkkaByteString("value", 10f)
payloadPrimitive.utf8String shouldBe """{"value":10.0}"""

val payloadObject = serializer.encodeDynamicToAkkaByteString("value", java.lang.Float.valueOf(10f))
payloadObject.utf8String shouldBe """{"value":10.0}"""
}

"encode a dynamic payload for double" in {
val payloadPrimitive = serializer.encodeDynamicToAkkaByteString("value", 10d)
payloadPrimitive.utf8String shouldBe """{"value":10.0}"""

val payloadObject = serializer.encodeDynamicToAkkaByteString("value", java.lang.Double.valueOf(10d))
payloadObject.utf8String shouldBe """{"value":10.0}"""

val payloadBigOne = serializer.encodeDynamicToAkkaByteString("value", java.math.BigDecimal.valueOf(10d))
payloadBigOne.utf8String shouldBe """{"value":10.0}"""
}

}
}

0 comments on commit c63c329

Please sign in to comment.