JsonNamingStrategy

Represents naming strategy — a transformer for serial names in a Json format. Transformed serial names are used for both serialization and deserialization. A naming strategy is always applied globally in the Json configuration builder (see JsonBuilder.namingStrategy).

Actual transformation happens in the serialNameForJson function. It is possible to apply additional filtering inside the transformer using the descriptor parameter in serialNameForJson.

Original serial names are never used after transformation, so they are ignored in a Json input. If the original serial name is present in the Json input but transformed is not, MissingFieldException still would be thrown. If one wants to preserve the original serial name for deserialization, one should use the JsonNames annotation, as its values are not transformed.

Common pitfalls in conjunction with other Json features

  • Due to the nature of kotlinx.serialization framework, naming strategy transformation is applied to all properties regardless of whether their serial name was taken from the property name or provided by @SerialName annotation. Effectively, it means one cannot avoid transformation by explicitly specifying the serial name.

  • Collision of the transformed name with any other (transformed) properties serial names or any alternative names specified with JsonNames will lead to a deserialization exception.

  • Naming strategies do not transform serial names of the types used for the polymorphism, as they always should be specified explicitly. Values from JsonClassDiscriminator or global JsonBuilder.classDiscriminator also are not altered.

Controversy about using global naming strategies

Global naming strategies have one key trait that makes them a debatable and controversial topic: They are very implicit. It means that by looking only at the definition of the class, it is impossible to say which names it will have in the serialized form. As a consequence, naming strategies are not friendly to refactorings. Programmer renaming myId to userId may forget to rename my_id, and vice versa. Generally, any tools one can imagine work poorly with global naming strategies: Find Usages/Rename in IDE, full-text search by grep, etc. For them, the original name and the transformed are two different things; changing one without the other may introduce bugs in many unexpected ways. The lack of a single place of definition, the inability to use automated tools, and more error-prone code lead to greater maintenance efforts for code with global naming strategies. However, there are cases where usage of naming strategies is inevitable, such as interop with an existing API or migrating a large codebase. Therefore, one should carefully weigh the pros and cons before considering adding global naming strategies to an application.

Types

Link copied to clipboard

Contains basic, ready to use naming strategies.

Functions

Link copied to clipboard
abstract fun serialNameForJson(descriptor: SerialDescriptor, elementIndex: Int, serialName: String): String

Accepts an original serialName (defined by property name in the class or SerialName annotation) and returns a transformed serial name which should be used for serialization and deserialization.