This week's build of Elements introduces a new aspect-based feature to Elements RTL: support for simple and easy no-code serialization.
With Elements .2981, you can now easily add the ability for a class to be read from and stored as Json or XML, simply by applying the new [Codable]
aspect to it:
type
[Codable]
User = public class
public
property ID: Guid;
property Name: String;
property Email: String;
property Telephone: String;
property ZipCode: String;
end;
Once a class is marked as such, you can use the new Enoder
and Decoder
descendant classes in Elements RTL to convert instances of that class into encoded data or create new instances from encoded data. Coder implementations are provided for Json and XML, but you can, of course, also create your own – for custom data formats, or if you want more flexibility or different output than you are getting from the provided implementations.
var lCoder := new JsonCoder;
lCoder.Encode(lUserA);
writeLn(lCoder.ToJson);
var lCoder := new JsonCoder withJson(lJson)
var lUser := lCoder.Decode<User>;
Controlling the Coding Format
There are a few ways you can influence how your types get encoded (and decoded). This is helpful to match your personal taste, but also if you need to conform to predefined Json or XML schemes that don't exactly match your code style.
By default, the names of the properties are used "as is" to determine the encoded values' name, so ZipCode
will come through as e.g. "ZipCode": "44229"
in Json.
The [Codable]
attribute can take an option parameter of type NamingStyle
that lets you override the naming rules. Supported values include camelCase
, PascalCase
, lowercase
and UPPERCASE
(sorry for yelling). The default is AsIs
.
PascalCase and camelCase use smart logic to convert the identifiers in your code into the proper convention, ez ZipCode
would become zipCode
in camelCase.
type
[Codable(NamingStyle.camelCase)]
User = public class
You can also override the coded name of individual properties by adding the [Encode]
attribute with a string value, eg:
[Encode("plz")]
property ZipCode: String;
Encode can also take a boolean parameter instead, and by specifying Encode(false)
you can skip the property from being coded. ([Encode(true)]
is implied, so specifying that would be redundant ;).
Supported Types
You can encode or decode classes (or records, i guess) that contain any of the following types
- Integers and UInts (8, 16, 32, 64 bits, plus IntPtr)
- Float and Double
- String
- DateTime (encoded and expected as ISO8601)
- Guids
- Json objects and arrays
List<T>
of supported types- arrays of supported types (.NET only)
- Types that implement
IEncodable
/IDecodable
or theICodable
combined interface.
The Json coder will encode properties of JsonNode types natively; e.g. if your class has a JsonObject
or JsonArray
field, it will be encoded as a nested object or array in the result, and read back as such. Other encoders will encode them as string values.
As you may have guessed," Types that ICodable
" includes any type you mark as [Codable]
, since what this aspect does is precisely that: it implements the interface for you, providing strongly-typed code that encodes and decodes all its members (without the need for Reflection).
You can also implement this interface yourself if you want to provide a custom way of how a specific type is encoded or decoded, instead of how [Codable]
does it. Maybe you have a type that represents a data blob, and instead of coding its properties, you want to encode its data as a Base64 string.
Convenience
Some additional convenience can be gained in addition to applying [Codable]
(or implementing ICodable
), you also make your type decent from the Codable
helper class. This is entirely optional but gives you additional niceties, such as a constructor withJson(aJson: JsonDocument);
constructor, a ToJson
, and a default implementation of ToString
that returns the type as Json string.
How to use it?
Using RemObjects.Elements.Serialization is easy:
- Make sure your project uses (or at least references) Elements RTL (i.e. has a
Elements
reference). - Add a reference to the new
RemObjects.Elements.Serialization.dll
from the "Cirrus" tab in the Reference Manager to it. - Add
RemObjects.Elements.Serialization
to your uses/import clause.
And that's it.
PS: Check out JsonDocument
As part of implementing RemObjects.Elements.Serialization (and working with a lot of Json in general), we have made a ton of improvements and tweaks to the JsonDocument
implementation in Elements RTL over the past few years. If you have any need to work with Json data, I recommend you give it a try. (JsonDocument
is also fully cross-platform across all Elements platforms).
Feedback
RemObjects.Elements.Serialization is solid and time-proven; I have been using it for internal and Infrastructure projects for going on two years now, and I expect you will find it immediately useful.
Let me know what you think and/or if you have any ideas for improvement!