Creating Custom built_value Serializers with BuiltValueSerializer

Photo by Patrick Tomasso on Unsplash

When using built_value for JSON serializing and deserializing, we might have some cases that go beyond the capabilities of StandardJsonPlugin.

Imagine the following problem: you have an API endpoint that can give you two different types of data structures for the same value as shown in the following example:

In our flutter app, we might want to have an object that can have both values, and then we decide what we show in our Widgets.

So, how can we map the String value to singleValue and the array of Strings to multipleValues? With a CustomSerialize.

If we inspect the Serializer class, it’s stated:

Since our data structure is not a primitive object, we’ll have to create a class that implements StructuredSerializer.

Let’s inspect each method we need to implement:

types are the types of objects that can be serialized. When using built_value, it will generate an internal type called _$CustomValue that must also be serialized, so we have:

wirenameis the name of the class we want to serialize

Finally, we must implement the serializeand deserialize methods. Here we will be able to check if the value that we receive is of type String or type List and map it to the correct value of CustomValue. To do this, we need to check how the generated code of a similar class is structured, and adjust it to fit our needs. In this case, when we are checking the value field, we are not assigning it directly, but checking first which type to attribute to the variable, to either assign it to String value or List<String> values.

However, since we are using built_value, the type of list we will be dealing with comes from the built_collection package, hence we will be declaring it as BuiltList<String> values

Now, since we have our CustomValueSerializer class, we can start working on the CustomValue class.

The setup of the class is equal to a class that uses the StandardJsonPlugin, the only difference being in the way we declare the serializer. In this case, we can use the new annotation @BuiltValueSerializer to say to the serializer “hey, we are using a custom serializer, don’t generate one for this class”

What’s missing?

Our Serializers class that declares all the classes to be serialized in the project. For the case of custom serializers, we don’t need to put additional information in this class, so we can initialize it as we usually do.

Finally, we can run build_runnerin the terminal to generate all the new files:

flutter packages pub run build_runner watch

Et voilá! We have successfully used a custom serializer with built_value! 🎉

As a bonus, we can guarantee that everything is working by writing some good-old-fashioned unit tests:

All tests pass, and we are good to go.

You can see the full example in the GitHub Repo.