WE ENABLE CLOUD-NATIVE ORGANIZATIONS
meshBlog

Learn more about Cloud, Multi-Cloud and Software Delivery

In the last post we looked at how to persist JSR-363 types like Quantity<q> with Spring Data using a pair of converters to serialize a Quantity to string and back. In this post we will look at how to serialize Quantity to JSON using a similar trick. This allows us to use Quantities and Units in a REST API.

The JacksonQuantityModule

Jackson offers the module SPI to allow consumers to register various hooks for JSON serialization and deserialization. For example, the Jackson Kotlin module uses this mechanism to help Jackson better serialize Kotlin specific types like Pair<T, U>.

So here's our JacksonQuantityModule:

@Suppress("unused")
class JacksonQuantityModule : SimpleModule(PackageVersion.VERSION) {
companion object {
private val serialVersionUID = 1L
}

override fun setupModule(context: SetupContext) {
addSerializer(Quantity::class.java, QuantitySerializer)
addDeserializer(Quantity::class.java, QuantityDeserializer)

super.setupModule(context)

}

object QuantitySerializer : JsonSerializer<Quantity<*>>() {
override fun handledType(): Class<Quantity<*>> {
return Quantity::class.java
}

override fun serialize(value: Quantity<*>, gen: JsonGenerator, serializers: SerializerProvider?) {
val formatted = QuantityFormatting.QuantityToStringConverter.convert(value)
gen.writeString(formatted)
}
}

object QuantityDeserializer : JsonDeserializer<Quantity<*>>() {
override fun handledType(): Class<Quantity<*>> {
return Quantity::class.java
}

override fun deserialize(p: JsonParser, ctxt: DeserializationContext?): Quantity<*>? {
val source = p.valueAsString
return QuantityFormatting.StringToQuantityConverter.convert(source)
}
}
}

If you want to auto-register this module with Jackson through the SPI mechanism, just add a text file as a resource at META-INF/services/com.fasterxml.jackson.databind.Module with the fully qualified classname of our module as its content:

my.package.JacksonQuantityModule

Unit Tests for JacksonQuantityModule

Let's add some quick unit tests for this module to verify SPI auto-registration and the module implementation work as expected:

val sut = ObjectMapper().apply {
findAndRegisterModules()
}

@Test
fun handlesQuantities() {
verify(ObjectWithQuantity(1.mega.byte), """{"q":"1 MBy"}""")
}

@Test
fun handlesNullQuantities() {
verify(ObjectWithQuantity(null), """{"q":null}""")
}

private inline fun verify(obj: T, expectedJson: String) {
val json = sut.writeValueAsString(obj)
Assert.assertEquals(expectedJson, json)

val result = sut.readValue(json)
Assert.assertEquals(obj, result)
}

Both tests pass, mission accomplished.

One response to “JSR-363 Units of Measurement API in Practice – JSON Serialization”

  1. […] 1) Persisting Quantities with Spring Data 2) Supporting Binary and SI Prefixes 3) Supporting JSON Serialization for REST APIs […]

Leave a Reply to JSR-363 Units of Measurement API in Practice – Blogpost Series Introduction – Meshcloud Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.