Skip to content

Commit 995c8a8

Browse files
authored
Update README.md
1 parent 65fe167 commit 995c8a8

1 file changed

Lines changed: 112 additions & 0 deletions

File tree

README.md

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,113 @@
11
# OpenCode
2+
## Serialization Project
3+
4+
This project is just an attempt to implement a feature to serialize objects (persistent or just registered) with **two main goals in mind** :
5+
6+
1. Avoid the need of changing the class definition if there are changes in naming of serialized properties or even in the criteria to serialize the object
7+
2. Being able to serialize/deserialize to/from multiple formats (JSON, CSV, XML, custom,…), also _without touching the class definition itself_.
8+
9+
### How to get universal serialization feature in your classes
10+
11+
To get the full features, you just have to import in your system 4 classes (1) : _OPNLib.Serialize.Adaptor, OPNLib.Serialize.Util and OPNLib.Serialize.TemplateOPNLib.Serialize.TemplateCSV_.
12+
13+
(1) Actually you would just need _OPNLib.Serialize.Adaptor_ if you just need JSON serialization
14+
15+
### Start Serializing
16+
17+
To enable this feature for a class, that class has to extend from _OPNLib.Serialize.Adaptor_. That'll be the only time that you'll have to touch your class for this feature. After that moment your class will be able to export/import JSON objects and it will accept future serialization mechanisms that you decide to implement without having to make more changes to class definition.
18+
19+
```
20+
```
21+
_**Example:**_
22+
_(Example assumes that your classname is `SampleApps.Serialize.MapTesting`, that is a persistent class and that you already extended it to inherit from `OPNLib.Serialize.Adaptor`)_
23+
24+
From the terminal,in the name space where your class exists :
25+
26+
```javascript
27+
Set obj = ##class(SampleApps.Serialize.MapTesting).%OpenId(1)
28+
Set JSON = obj.Export()
29+
Do JSON.%ToJSON()
30+
31+
Set newObj = ##class(SampleApps.Serialize.MapTesting).%New()
32+
Do newObj.Import(,,JSON)
33+
```
34+
We will have a new instance of _`SampleApps.Serialize.MapTesting`_ object, a clone of the one with ID=1. This was the example, we can modify it before saving or just discarding.
35+
```
36+
```
37+
38+
### What _`OPNLib.Serialize.Adaptor`_ provides?
39+
40+
Basically 2 generic instance methods: `Export` and `Import`; and a generic mapping between each of the properties in the Caché object and its equivalent serialized.
41+
42+
Once the class that extends the Adaptor is compiled, we'll have those methods available and a class mapping storaged in 2 internal globals : ^MAPS and ^MAPSREV (**).
43+
(**) Globals structure explained later on
44+
45+
How is the mapping built at first place?
46+
47+
We can have several maps for a particular class (for example to exchange data from an object with different systems or organizations, we might need to export some properties but not others, or apply different conversions to some values, or name the properties differently , etc…).
48+
49+
By default, Adaptor will generate MAP0, and will make a direct mapping regarding property names (same name for target an source property).
50+
51+
Each property will be categorized in group types. Currently these are the group types supported :
52+
1) Basic type
53+
○ It'll include %String, %Integer, %Date, %Datetime,%Timestamp,%Decimal,%Float,… and most of the basic types defined in the %Library package
54+
2) List collection
55+
○ It'll include collections of datatypes of type %Collection.ListOfDT
56+
3) Array collection
57+
○ It'll include collections of datatypes of type %Collection.ArrayOfDT
58+
4) Object Reference
59+
○ A property that reference a custom object not in %* libraries
60+
5) Array of objects and Relationship objects
61+
○ A property of type %Collection.ArrayOfObject or a property of type %RelationshipObject with cardinality many or children
62+
6) List of Objects
63+
○ A property of type %Collection.ListOfObject
64+
7) Stream
65+
○ Properties of type %Stream.*, %CSP.*stream*,…
66+
67+
How could we configure our mapping for serialization?
68+
69+
We can have as much mapping definitions for a class as we need. An easy way to start to define our customized maps is exporting the default MAP0 and importing it again with a different name, then we can make changes in the map regarding the properties that should be exported /imported, names, conversor methods to apply (***)
70+
(***) See OPNLIB.SERIALIZE.ADAPTOR.Serialize.Util library for tools to export/import maps, get / set property mappings,etc…)
71+
72+
We also have the possibility of changing a bit the way in which default map MAP0 is generated :
73+
• Change the name of default map.
74+
○ Use parameter EXPTDEFAULTMAP to indicate a name for default map before compiling the class
75+
• Excluding properties
76+
○ if we don't want to export some properties, we should include them in the parameter : EXPTEXCLUDEPROP before compiling the class (the properties will be in a comma separated list)
77+
• include object references
78+
○ Even when we decide not to drill down through referenced objects, we still have the chance to export the object reference itself if we set the parameter EXPTINCLUDEOREF to 1.
79+
• Drill down levels
80+
○ To indicate up to what number of levels we want the export mechanism to drill down through object references. 0 means no drill down. A positive number(n) means to drill down n times through the chain of references.
81+
82+
Example:
83+
84+
<<<create MAP1 from MAP0 >>>
85+
86+
<<<USING MAP0 and MAP1 from the same object instance >>>
87+
88+
How did it work the default mechanism?
89+
90+
Both methods, export and Import will call the generated methods: exportStd and imoortStd respectively. These two methods will go through the global ^MAPS and ^MAPSREV respectively, looking for the properties to export /import and applying the required conversions.
91+
Both methods work over an already instantiated method. This is particularly important for import, as we can have an object in memory with some data already and import the rest of the data from a serialized object. The import mechanism will replace with the new content the properties contained in the serialization but will preserve other properties already set in the instance that are not included in the serialization that we import.
92+
93+
Example:
94+
95+
<< import a JSON with just some properties in an object where we already have some others set >>>
96+
97+
This way of working give us the flexibility of using different mappings using the same autogenerated code but it can have a penalty in performance if we use it massively in loops or in very high concurrency use cases. Anyway,better test in such scenarios.
98+
99+
Some considerations about performance
100+
101+
As we already mentioned, the default mechanism resolve the mapping sets at real time, trasversing a global to set the properties to export/import targets. That means that this mechanism will always be slower than if we already had that settings resolved at compile time. In order to provide that functionality, we can use the Template classes.
102+
103+
What are the template classes for?
104+
105+
The templates classes allow us to generate the logic to export /import at compile time.
106+
This have benefits over performance but comes at the price of having to use a different class for each type of serialization format and mapping.
107+
108+
Anyway, the primary class is not affected and doesn't have to be changed no matter how many templates define to handle the serialization of its objects.
109+
110+
Example :
111+
112+
<<< define and use different template classes, for different maps in JSON and also for different serialization (CSV)
113+
>>>

0 commit comments

Comments
 (0)