|
@@ -1,4 +1,4 @@
|
|
|
-### Serialising with JConv
|
|
|
+## Serialising with JConv
|
|
|
|
|
|
In the context of #BRL.JConv, serialisation is the mapping of BlitzMax objects to their JSON representation.
|
|
|
|
|
@@ -75,7 +75,7 @@ Type TUser
|
|
|
End Type
|
|
|
```
|
|
|
|
|
|
-### Deserialising with JConv
|
|
|
+## Deserialising with JConv
|
|
|
|
|
|
We'll start by creating a #String containing the JSON to convert :
|
|
|
```blitzmax
|
|
@@ -124,7 +124,7 @@ Type TUser
|
|
|
End Type
|
|
|
```
|
|
|
|
|
|
-### Serialising Nested Objects
|
|
|
+## Serialising Nested Objects
|
|
|
|
|
|
#BRL.JConv can also handle the conversion of more complex objects that include the nesting of other non-primitive objects.
|
|
|
To demostrate this we will extend the `TUser` type to include an address, which will be represented by the `TAddress` #Type :
|
|
@@ -161,7 +161,7 @@ We'll initially create the required BlitzMax objects :
|
|
|
Local address:TAddress = New TAddress("66 Some Street", "Someville", "Someland")
|
|
|
Local user:TUser = New TUser("bob", "[email protected]", 30, address)
|
|
|
```
|
|
|
-And then serialise the user with an instance of #TJCon :
|
|
|
+And then serialise the user with an instance of #TJConv :
|
|
|
```blitzmax
|
|
|
Local jconv:TJConv = New TJConvBuilder.Build()
|
|
|
Local json:String = jconv.ToJson(user)
|
|
@@ -172,7 +172,7 @@ The resulting conversion to JSON is :
|
|
|
```
|
|
|
As you can see, #BRL.JConv has correctly nested the address inside the user as a JSON object.
|
|
|
|
|
|
-### Deserialising Nested Objects
|
|
|
+## Deserialising Nested Objects
|
|
|
|
|
|
In the real world, the developer is often presented with a JSON API from which they need to construct the relevant BlitzMax
|
|
|
Types in order to import the data.
|
|
@@ -314,7 +314,7 @@ Type TLocation
|
|
|
End Type
|
|
|
```
|
|
|
|
|
|
-### Customising Field Names
|
|
|
+## Customising Field Names
|
|
|
|
|
|
Occasionally, a JSON object will use a key that has the same name as a reserved keyword in BlitzMax. In that case, you are unable create a field
|
|
|
using the desired name. Fortunately, #BRL.JConv allows you use metadata to specify the serialised name of a given field using the `serializedName`
|
|
@@ -407,7 +407,7 @@ deserialising the JSON would result in the `name` #Field containing the value `u
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-### Ignoring Fields
|
|
|
+## Ignoring Fields
|
|
|
|
|
|
If you don't want a field to be mapped to or from JSON there are some metadata properties that you can apply to your types in order to do so.
|
|
|
The first, `transient`, completely disables field from mapping in either direction.
|
|
@@ -469,3 +469,160 @@ Type TUser
|
|
|
End Type
|
|
|
```
|
|
|
|
|
|
+## Configuring TJConv with the Builder
|
|
|
+
|
|
|
+You may have noticed, that by default #BRL.JConv serialises the JSON into a single line.
|
|
|
+You can change this behaviour with one ofthe builder's configurable options.
|
|
|
+
|
|
|
+The builder uses what is known as a fluent interface, or method chaining design, where a sequence of method calls can be used to construct the #TJConv instance.
|
|
|
+
|
|
|
+For example, the following builder creates an instance of #TJConv which will serialise objects to JSON with a decimal a precision of 2 places and compact objects :
|
|
|
+```blitzmax
|
|
|
+Local jconv:TJConv = New TJConvBuilder.WithPrecision(2).WithCompact().Build()
|
|
|
+```
|
|
|
+
|
|
|
+### WithIndent
|
|
|
+
|
|
|
+The #WithIndent method of #TJConvBuilder specifies the number of spaces to use for indenting of nested objects. The default of 0 (zero)
|
|
|
+means not to use pretty-printing.
|
|
|
+
|
|
|
+This is an example of `TUser` using the default options :
|
|
|
+```json
|
|
|
+{"name": "Bob", "email": "[email protected]", "age": 30}
|
|
|
+```
|
|
|
+And this is an example of building with #WithIndent :
|
|
|
+```json
|
|
|
+{
|
|
|
+ "name": "Bob",
|
|
|
+ "email": "[email protected]",
|
|
|
+ "age": 30
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### WithCompact
|
|
|
+
|
|
|
+On the other hand, JSON can be compacted further using the #WithCompact method, which works to remove extra spaces :
|
|
|
+```json
|
|
|
+{"name":"Bob","email":"[email protected]","age":30}
|
|
|
+```
|
|
|
+### WithPrecision
|
|
|
+The representation of decimal numbers can be controlled by the #WithPrecision method, which specifies the maximum number of decimal places to used.
|
|
|
+
|
|
|
+For example, the default representation of a #Type `TPoint` :
|
|
|
+```blitzmax
|
|
|
+Type TPoint
|
|
|
+ Field x:Double
|
|
|
+ Field y:Double
|
|
|
+End Type
|
|
|
+```
|
|
|
+would normally result in the following JSON with fields of the values (10.565, 15.912) :
|
|
|
+```json
|
|
|
+{"x": 10.565, "y": 15.912000000000001}
|
|
|
+```
|
|
|
+Using a maximum precision of 3 (`WithPrecision(3)`), the resulting JSON would become :
|
|
|
+```json
|
|
|
+{"x": 10.565, "y": 15.912}
|
|
|
+```
|
|
|
+
|
|
|
+### WithEmptyArrays
|
|
|
+
|
|
|
+By default, #Null/empty arrays are not serialised at all. That is, the field is not included in the JSON object.
|
|
|
+The #WithEmptyArrays option can be enabled to generate an empty array (`[]`] instead.
|
|
|
+
|
|
|
+### WithBoxing
|
|
|
+
|
|
|
+Primitive numbers, by their very nature in BlitzMax, have no concept of nullability. JSON, conversely, can represent any field as a null value,
|
|
|
+either by simply not including it in the object, or by having the value `null`.
|
|
|
+
|
|
|
+To support this, #BRL.JConv provides an option to use "boxed" primitives in your types. A Boxed primitive is just an instance of a #Type that has
|
|
|
+a value field of the appropriate numeric #Type. Using a boxed primitive then allows a field to contain a value, or be #Null.
|
|
|
+
|
|
|
+This feature is enabled by using the #WithBoxing option of the builder.
|
|
|
+
|
|
|
+As an example, suppose there is a JSON object which has a numeric field `failures`. The schema specifies that this value can either be `null` or have a value
|
|
|
+greater than zero :
|
|
|
+```json
|
|
|
+[
|
|
|
+ {
|
|
|
+ "jobId": "ABC123",
|
|
|
+ "failures": 3,
|
|
|
+ "lastError": "overflow"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "jobId": "DEF456"
|
|
|
+ }
|
|
|
+]
|
|
|
+```
|
|
|
+Deserialising this wouldn't be a problem, as our `TJob` #Type could represent no `failures` by the number zero :
|
|
|
+```blitzmax
|
|
|
+Type TJob
|
|
|
+ Field jobId:String
|
|
|
+ Field failures:Int
|
|
|
+ Field lastError:String
|
|
|
+End Type
|
|
|
+```
|
|
|
+However, were we required to serialise our #Type to JSON for use by the API, we'd potentially fail schema validation by passing zero as a value for
|
|
|
+the `failures` #Field.
|
|
|
+
|
|
|
+Utilising the boxing feature, we could instead define the `failures` #Field as `TInt` :
|
|
|
+```blitzmax
|
|
|
+Type TJob
|
|
|
+ Field jobId:String
|
|
|
+ Field failures:TInt
|
|
|
+ Field lastError:String
|
|
|
+End Type
|
|
|
+```
|
|
|
+Which would, for #Null values, result in the `features` #Field not being serialized to JSON.
|
|
|
+
|
|
|
+Here's a full example highlighting the use of boxing :
|
|
|
+```blitzmax
|
|
|
+SuperStrict
|
|
|
+
|
|
|
+Framework BRL.StandardIO
|
|
|
+Import BRL.JConv
|
|
|
+
|
|
|
+Local job1:TJob = New TJob("ABC123", 3, "overflow")
|
|
|
+Local job2:TBoxedJob = New TBoxedJob("DEF456", 0, Null)
|
|
|
+
|
|
|
+Local jconv:TJConv = New TJConvBuilder.WithBoxing().WithIndent(2).Build()
|
|
|
+
|
|
|
+Print jconv.ToJson(job1)
|
|
|
+Print jconv.ToJson(job2)
|
|
|
+
|
|
|
+Type TJob
|
|
|
+ Field jobId:String
|
|
|
+ Field failures:Int
|
|
|
+ Field lastError:String
|
|
|
+
|
|
|
+ Method New(jobId:String, failures:Int, lastError:String)
|
|
|
+ Self.jobId = jobId
|
|
|
+ Self.failures = failures
|
|
|
+ Self.lastError = lastError
|
|
|
+ End Method
|
|
|
+End Type
|
|
|
+
|
|
|
+Type TBoxedJob
|
|
|
+ Field jobId:String
|
|
|
+ Field failures:TInt
|
|
|
+ Field lastError:String
|
|
|
+
|
|
|
+ Method New(jobId:String, failures:Int, lastError:String)
|
|
|
+ Self.jobId = jobId
|
|
|
+ If failures > 0 Then
|
|
|
+ Self.failures = New TInt(failures)
|
|
|
+ End If
|
|
|
+ Self.lastError = lastError
|
|
|
+ End Method
|
|
|
+End Type
|
|
|
+```
|
|
|
+Running the above example would result in the following output :
|
|
|
+```
|
|
|
+{
|
|
|
+ "jobId": "ABC123",
|
|
|
+ "failures": 3,
|
|
|
+ "lastError": "overflow"
|
|
|
+}
|
|
|
+{
|
|
|
+ "jobId": "DEF456"
|
|
|
+}
|
|
|
+```
|