Qualifiers: Different Encodings for the Same Type
Sometimes you need to encode the same data type in different ways within the same JSON object. For example, an int might represent a simple number in one field but a hex color string (e.g., "#ff0000") in another.
Moshi uses qualifier annotations to solve this problem. A qualifier is a custom annotation that you create, which is itself annotated with @JsonQualifier.
Example: A Hex Color Adapter
Let's build an adapter that serializes an int as a hex color string.
The Problem
Consider this class representing a rectangle:
data class Rectangle(
val width: Int,
val height: Int,
val color: Int
)
By default, Moshi will serialize this to:
{
"width": 1024,
"height": 768,
"color": 16711680
}
We want the color field to be a hex string like "#ff0000".
Step 1: Define a Qualifier Annotation
First, create your own annotation and annotate it with @JsonQualifier. The annotation must have RUNTIME retention.
import com.squareup.moshi.JsonQualifier
import kotlin.annotation.Retention
@Retention(AnnotationRetention.RUNTIME)
@JsonQualifier
annotation class HexColor
Step 2: Apply the Qualifier to the Property
Next, apply your new @HexColor annotation to the color property.
data class Rectangle(
val width: Int,
val height: Int,
@HexColor val color: Int
)
This tells Moshi that the color field requires a special adapter—one that is associated with the @HexColor qualifier.
Step 3: Create a Qualified Adapter
Now, create a custom adapter whose @ToJson and @FromJson methods are also annotated with @HexColor. This links the adapter to the property.
class ColorAdapter {
@ToJson
fun toJson(@HexColor rgb: Int): String {
return "#%06x".format(rgb)
}
@FromJson
@HexColor
fun fromJson(rgb: String): Int {
return rgb.substring(1).toInt(16)
}
}
- The
@ToJsonmethod takes anintannotated with@HexColorand returns aString. - The
@FromJsonmethod takes aStringand returns anint, and the method itself is annotated with@HexColorto signify what it produces.
Step 4: Register the Adapter
Finally, add an instance of your ColorAdapter to your Moshi.Builder.
val moshi = Moshi.Builder()
.add(ColorAdapter())
.addLast(KotlinJsonAdapterFactory())
.build()
val adapter = moshi.adapter(Rectangle::class.java)
Now, when Moshi serializes or deserializes a Rectangle, it will use the default Int adapter for width and height, but it will use your special ColorAdapter for the @HexColor-annotated color property.
Resulting JSON:
{
"width": 1024,
"height": 768,
"color": "#ff0000"
}