CircularJsonSerialiser ist ein Serialiser für Java mit dem Ziel, dass ohne manuelle Konfiguration alle Klassen-
und Objektstrukturen korrekt gespeichert und identisch wiederhergestellt werden.
Alle bidirektionalen und zirkulären Verweise zwischen verschiedenen Objekten werden automatisch behandelt und korrekt
gespeichert und aufgelöst.
Außerdem wird die Identität von Objekten erkannt; wenn ein Objekt zum Beispiel in zwei Listen gespeichert wird, werden
beim Deserialisieren nicht zwei verschiedene Instanzen, sondern dasselbe Objekt in beide Listen gespeichert.
Auch die Art primitiver Datentypen wie z. B. Zahlen oder Datenstrukturen wie z. B. Listen wird korrekt gespeichert,
sodass nach dem Deserialisieren keine Cast Exceptions durch falsch wiederhergestellte Objekte zu erwarten sind.
Um den CircularJsonSerialiser in ein Maven-Projekt einzubinden, muss in der pom.xml die folgende Dependency hinzugefügt werden:
<dependency>
<groupId>de.korne127.circularjsonserialiser</groupId>
<artifactId>circular-json-serialiser</artifactId>
<version>1.2</version>
</dependency>
Dasselbe gilt äquivalent für ein Gradle-Projekt:
implementation 'de.korne127.circularjsonserialiser:circular-json-serialiser:1.2'
Falls ein anderes Build-Management-Tool verwendet wird, das ebenfalls auf das zentrale Maven-Repository zugreifen kann, kann man hier den Code nachschauen, um die Dependency entsprechend hinzuzufügen.
Alternativ kann auch die .jar-Datei des neuesten Releases heruntergeladen und manuell dem Projekt in der IDE hinzugefügt werden.
Um ein Objekt zu serialisieren, muss zunächst ein Serialiser
-Objekt erstellt werden:
Serialiser serialiser = new Serialiser();
Ein Objekt kann auf zwei Arten serialisiert werden:
Die Standardserialisierung verwandelt das Objekt in einen JSON-String, der in einer Datei gespeichert wird:
String jsonString = serialiser.serialiseObject(object);
Das Objekt wird wiederhergestellt, indem dieser JSON-String an die Standard-Deserialisierungsmethode gegeben wird:
Object object = serialiser.deserialiseObject(jsonString);
Alternativ gibt es auch eine andere Art, ein Objekt zu serialisieren, nämlich die
serialiseObjectSeparated
-Methode:
Map<String, String> jsonMap = serialiser.serialiseObjectSeparated(object);
Diese kann benutzt werden, wenn die serialisierten Objekte in mehrere Dateien unterteilt werden sollen. Dazu können
Klassen und Attribute mit einer SerialiseFile
-Annotation versehen werden, die den Dateinamen enthält,
zu dem die entsprechenden Objekte zugeordnet werden sollen, siehe
Annotationen und Exceptions.
Die einzelnen Strings werden in einer Map ihrem Dateinamen zugeordnet zurückgegeben.
In den Strings werden Verweise zwischen den einzelnen Objekten gespeichert, die beim Deserialisieren wieder
zusammengesetzt werden. Somit können mit der deserialiseSeparatedObject
-Methode die verschiedenen JSON-Strings
wieder in ein Objekt umgewandelt werden:
Object object = serialiser.deserialiseSeparatedObject(jsonMap);
Bei der Serialisierung eines Objektes kann eine SerialiseException
, bei der Deserialisierung können eine
DeserialiseException
und eine JsonParseException
geworfen werden.
Für mehr Informationen zu möglichen Auslösern, siehe Annotationen und Exceptions.
Das Ziel dieses Serialisers ist es, Objektstrukturen ohne manuelle Konfiguration so akkurat wie möglich zu speichern und wiederherzustellen, sodass das Programm nach dem Deserialisieren identisch funktionieren kann.
Da andere Serialiser wie Gson oder Jackson Performanz und nicht eine möglichst akkurate Speicherung der Objektstrukturen priorisieren, hat dieser Serialiser einige zusätzliche Eigenschaften, die eine bessere Wiederherstellung ermöglichen:
Objekte können sich gegenseitig referenzieren und ohne manuelle Konfiguration korrekt (de-)serialisiert werden. Zusätzlich werden die Identitäten von Objekten gespeichert, sodass sich Strukturen beim Deserialisieren nicht doppelt bilden und Objekte mehrfach gespeichert werden würden.
Es können eigene Klassen als Keys für Maps benutzt werden, ohne dass irgendeine Konfiguration nötig ist, wie mit diesen Maps umgegangen werden soll. Sie werden einfach beim Serialisieren in den JSON-String gespeichert und beim Deserialisieren wiederhergestellt.
Es werden alle Felder eines Objektes gespeichert, auch solche, die in Oberklassen der eigentlichen Klasse gespeichert sind. Dies stellt sicher, dass sich das generierte Objekt nach dem Deserialisieren identisch zu dem ursprünglichen Objekt verhält.
In bestimmten Entwicklungsmustern wie etwa der Schablonenmethode oder dem Zustands-Muster wird nur die Instanz
einer Oberklasse in dem Code gespeichert, welche dann dynamisch durch Instanzen der verschiedenen Unterklassen
ausgetauscht werden kann.
Dieser Serialiser speichert die genaue Klasse des Objektes und stellt sie wieder her, sodass die Ausführung des
Programmes nicht verändert wird.
Auch die Art der primitiven Datentypen wird, anders als bei anderen Serialisern, gespeichert. Dies führt dazu,
dass die Zahlen bzw. Buchstaben immer im korrekten Typ wiederhergestellt werden und es beim Benutzen von
selteneren Typen wie char
, byte
oder short
nicht zu einer ClassCastException
kommt.
Ebenso werden Enums nicht wie in anderen Serialisern als String gespeichert, sondern explizit als Typ des
entsprechenden Enums, sodass sie in jedem Fall wieder korrekt hergestellt werden können.
Die konkrete Information, welche Collection- oder Map-Klasse benutzt wird, wird bei dem Serialisieren ebenfalls
gespeichert. So kann beim Deserialisieren eine identische Collection / Map, die sich weiterhin gleich verhält,
erstellt werden.
(Falls es nicht möglich ist, eine Instanz der speziellen Collection- / Map-Klasse herzustellen, kann eine möglichst
ähnliche alternative Klasse benutzt werden.)
Der Serialiser besitzt einige zusätzliche Funktionen, die dabei helfen, in verschiedenen
Anwendungsgebieten optimale Ergebnisse zu erzielen.
Diese sind hier aufgelistet:
Es kann für jede Klasse und jedes Attribut ein Dateiname annotiert werden, zu dem Objekte aus dieser Klass
bzw. das entsprechende Objekt des Attributes serialisiert gespeichert
werden sollen. Mit Map<String, String> serialised = serialiser.serialiseObjectSeparated(object)
wird eine Map
zurückgegeben, die die einzelnen JSON-Strings den Dateinamen, zu denen sie gespeichert werden sollen, zugeordnet
beinhaltet. Diese Map kann an den Deserialiser übergeben werden, der daraus erfolgreich das Objekt wiederherstellt.
Dies kann hilfreich sein, falls die serialisierten Strings auch für Menschen einfach überschaubar sein sollen: Einzelne Klassen und Objekte können in einer anderen Datei gespeichert werden, um die Übersicht zu verbessern oder den Zugriff auf sensible Informationen zu verhindern.
Es können Methoden mit einer BeforeSerialise-Annotation annotiert werden. Dann werden diese vor dem
Deserialisieren ausgeführt. Diese Methoden können auch ein Argument annehmen, das im Serialiser
spezifiziert wird.
Es können Felder mit einer Setter-Annotation annotiert werden. Dann wird das Feld während dem
Deserialisieren auf ein im Serialiser spezifiziertes Argument überschrieben.
Es können Methoden mit einer AfterDeserialise-Annotation annotiert werden. Dann werden diese nach dem
Deserialisieren ausgeführt. Diese Methoden können auch ein Argument annehmen, das im Serialiser
spezifiziert wird.
Für mehr Informationen zu den entsprechenden Annotationen und die Spezifikation von Argumenten im Serialiser siehe Annotationen und Exceptions und methodParameters.
Es ist möglich, dynamisch zu serialisieren, also, dass für verschiedene Fälle verschiedene Felder serialisiert
werden.
Dies ist möglich, da die SerialiseIgnore- und die Setter-Annotationen IDs als Parameter besitzen können und
vor dem (De-)Serialisieren eingestellt werden kann, dass Annotationen mit bestimmten IDs ignoriert
werden.
Für mehr Informationen zu den entsprechenden Annotationen und den Einstellungen zum dynamischen
Serialisieren siehe Annotationen und Exceptions,
ignoreExceptionIDs und ignoreSetterIDs.
Der Serialiser besitzt verschiedene Konfigurationsmöglichkeiten, die das Verhalten des Serialisers anpassen:
Standardmäßig werden die Variablen aus der obersten Oberklasse eines Objektes zuerst und die Variablen der
eigentlichen Klasse des Objektes zuletzt serialisiert.
Dieses Verhalten kann mit setStartSerialisingInSuperclass(boolean)
angepasst werden.
Die BeforeSerialise-, AfterDeserialise- sowie Setter-Annotationen können einen Parameter besitzen. Diesen
Parametern können Objekte in einer Map zugeordnet werden.
Wenn eine Methode, die eine BeforeSerialise- oder AfterDeserialise-Annotation besitzt, ein Argument entgegennimmt,
wird das zu dem Parameter der entsprechenden Annotation gespeicherte Objekt dafür benutzt.
Ebenso werden Felder, die die Setter-Annotation besitzen, mit dem Objekt überschrieben, das zu dem Parameter
der Annotation gespeichert ist.
Diese Map "methodParameters" ist standardmäßig leer und kann mit setMethodParameters(Map)
überschrieben werden.
Falls der Parameter (die ID) einer SerialiseIgnore-Annotation in ignoreExceptionIDs enthalten ist, wird die
Annotation ignoriert, also der Parameter doch serialisiert.
Dies ermöglicht eine dynamische Serialisierung für verschiedene Fälle, in denen unterschiedliche Felder
serialisiert werden sollen.
Das Set "ignoreExceptionIDs" ist standardmäßig leer (es werden also standardmäßig alle Felder mit einer
SerialiseIgnore-Annotation ignoriert) und kann mit setIgnoreExceptionIDs(Set)
überschrieben werden.
Falls der Parameter (die ID) einer Setter-Annotation in ignoreSetterIDs enthalten ist, wird die Annotation
ignoriert, der Wert des Feldes also nicht überschrieben.
Dies ermöglicht eine dynamische Serialisierung für verschiedene Fälle, in denen unterschiedliche Felder
serialisiert werden sollen.
Das Set "ignoreSetterIDs" ist standardmäßig leer (es werden also standardmäßig alle Felder mit einer
Setter-Annotation überschrieben) und kann mit setIgnoreSetterIDs(Set)
überschrieben werden.
Falls beim Deserialisieren eine Collection oder Map existiert, von der keine Instanz erstellt werden kann,
bestimmt der gesetzte "collectionHandling"-Wert, wie sich der Serialiser verhält:
- NO_WARNING: Falls keine Instanz einer Collection / Map erstellt werden kann, wird eine andere, möglichst ähnliche Collection- / Map-Klasse genommen, in der die Elemente gespeichert werden.
- CONVERT_WITH_WARNING: Falls keine Instanz einer Collection / Map erstellt werden kann, wird eine andere, möglichst
ähnliche Collection- / Map-Klasse genommen, in der die Elemente gespeichert werden.
Zusätzlich wird eine Warnung, welche Klasse in welche Klasse umgewandelt wurde, ausgegeben.
Dies ist die standardmäßige Einstellung. - DEBUG_MODE: Falls keine Instanz einer Collection / Map erstellt werden kann, wird eine andere, möglichst
ähnliche Collection- / Map-Klasse genommen, in der die Elemente gespeichert werden.
Zusätzlich wird die komplette Exception, die gefangen wurde, sowie eine Warnung, welche Klasse in welche Klasse umgewandelt wurde, ausgegeben. - NO_CASTING: Falls keine Instanz einer Collection / Map erstellt werden kann, wird eine DeserialiseException geworfen und der Programmablauf unterbrochen.
Falls das Feld direkt mit der IgnoreCasting-Annotation annotiert ist, wird das Casten für eine Collection / Map aus dem speziellen Feld unabhängig von dem generellen collectionHandling-Wert ohne Warnung vollzogen.
Die Einstellung collectionHandling lässt sich mit setCollectionHandling(CollectionHandling)
überschreiben.
Falls beim Deserialisieren eine Klasse eine "neue Variable", also eine Variable, die (de-)serialisiert
werden soll, aber nicht im angegebenen Json gespeichert wurde, besitzt, bestimmt der gesetzte
"newVariableHandling"-Wert, wie sich der Serialiser verhält:
- NO_WARNING: Falls eine Klasse eine neue Variable enthält, wird diese ignoriert.
- WARNING: Falls eine Klasse eine neue Variable enthält, wird diese nicht gesetzt, aber es wird eine Warnung mit Informationen zu der neuen Variable und in welchem Objekt sie enthalten ist, ausgegeben.
- EXCEPTION: Falls eine Klasse eine neue Variable enthält, wird eine DeserialiseException geworfen
und der Programmablauf unterbrochen.
Dies ist die standardmäßige Einstellung.
Die Einstellung newVariableHandling lässt sich mit setNewVariableHandling(NewVariableHandling)
überschreiben.
Standardmäßig werden die generierten JSON-Strings mit Leerzeichen, Zeilenumbrüchen und Tabulatoren versehen,
um die Objekt- und Array-Strukturen hierarchisch anzuordnen und für den Leser übersichtlich und einfach
lesbar zu machen. Alternativ können aber auch komprimierte JSON-Strings generiert werden, die keine Leerzeichen,
Zeilenumbrüche oder Tabulatoren besitzen. Dies kann z.B. in Situationen mit begrenztem Speicherplatz
vorteilhaft sein.
Dieses Verhalten kann mit setCompressedJson(boolean)
angepasst werden.
Folgende Annotations und Exceptions existieren:
SerialiseIgnore-Annotation:
Diese Annotation kann vor ein Attribut gesetzt werden, um es von der Serialisierung und Deserialisierung
auszuschließen.
Die Annotation nimmt einen Parameter an, der als ID fungiert. Vor dem (De-)Serialisieren kann
eingestellt werden, dass SerialiseIgnore-Annotationen mit bestimmten IDs ignoriert werden,
die entsprechenden Felder also doch serialisiert werden.
Dies erlaubt eine dynamische Serialisierung für verschiedene Fälle, in denen verschiedene Felder serialisiert
werden sollen.
SerialiseFile-Annotation:
Diese Annotation kann vor eine Klasse gesetzt werden, um festzulegen, in welcher Datei die Objekte dieser Klasse
deserialisisert werden, wenn die separate Serialisierung genutzt wird. Die Annotation kann auch direkt vor ein
Attribut gesetzt werden; dies überschreibt, falls die Klasse des Objektes annotiert ist.
Ein Array wird standardmäßig in die Datei geschrieben, in die die Elemente des Arrays gehören; eine Collection
oder Map wird standardmäßig in die Datei geschrieben, in der die Elternklasse steht.
BeforeSerialise-Annotation:
Diese Annotation kann vor eine Methode gesetzt werden. Es werden alle Methoden mit einer
BeforeSerialise-Annotation vor dem Serialisieren ausgeführt.
Die Annotation nimmt einen Parameter an. Vor dem (De-)Serialisieren kann für jeden Parameter ein
Objekt angegeben werden. Falls die Methode ein Argument annimmt, wird dann das Objekt,
dass zu dem Parameter der Annotation angegeben wurde, an die Methode angegeben.
Setter-Annotation: Diese Annotation kann vor ein Feld gesetzt werden. Sie nimmt einen Parameter an; zu diesem muss vor dem (De-)Serialisieren ein Objekt angegeben werden. Dann wird bei der Deserialisierung der Feldwert auf das entsprechende zum Annotations-Parameter angegebene Objekt gesetzt. Alternativ kann vor dem (De-)Serialisieren eingestellt werden, dass Setter-Annotationen mit bestimmten Parametern ignoriert werden, die entsprechenden Felder also nicht auf angegebene Werte gesetzt, sondern normal deserialisiert werden. Dies erlaubt eine dynamische Serialisierung für verschiedene Fälle, in denen verschiedene Felder serialisiert werden sollen.
AfterDeserialise-Annotation:
Diese Annotation kann vor eine Methode gesetzt werden. Es werden alle Methoden mit einer
AfterDeserialise-Annotation nach dem Deserialisieren ausgeführt.
Die Annotation nimmt einen Parameter an. Vor dem (De-)Serialisieren kann für jeden Parameter ein
Objekt angegeben werden. Falls die Methode ein Argument annimmt, wird dann das Objekt,
das zu dem Parameter der Annotation angegeben wurde, an die Methode angegeben.
IgnoreCasting-Annotation::
Diese Annotation kann vor ein Feld gesetzt werden. In diesem Fall wird, falls das Feld eine Collection bzw.
Map, die zu einer anderen gecastet werden muss, ist oder enthält, keine Warnung ausgegeben
(es sei denn, der DEBUG-Modus ist aktiviert).
Dies ist hilfreich, wenn man nicht allgemein alle Warnungen ausschalten, sie aber
für ein bestimmtes Feld unterdrücken will, z. B. falls es beabsichtigt ist, dass ein bestimmtes Feld umgecastet
wird.
SerialiseException: Diese Exception wird geworfen, wenn ein Objekt nicht serialisiert werden konnte, z. B. weil ein Wert nicht abgefragt werden konnte.
DeserialiseException: Diese Exception wird geworfen, wenn ein Fehler während der Deserialisierung auftritt, z. B. wenn eine Klasse oder ein verlinktes Objekt nicht gefunden oder auf einen Wert gesetzt werden konnte.
JsonParseException: Diese Exception wird geworfen, wenn ein Fehler während des Lesens des JSON-Strings auftritt. Sofern die JSON-Strings nicht editiert werden, sollte diese Exception nicht geworfen werden.
Folgende Dinge gibt es bei der Benutzung des CircularJsonSerialisers zu beachten:
Jede Klasse, die serialisiert wird, muss einen Standardkonstruktor, also einen Konstruktor, der im Format
new Class()
ist und keine Argumente annimmt, besitzen.
Es ist mit dem CircularJsonSerialiser nicht möglich, Instanzen von Interfaces, also anonyme Klassen oder
Lambda-Funktionen zu serialisieren. Falls eine anonyme Klasse oder eine Lambda-Funktion angegeben wird oder
in einer Klasse zu serialisieren ist, wird eine entsprechende SerialiseException geworfen.
Falls es nötig ist, eine Instanz eines Interfaces zu serialisieren, muss daher eine Unterklasse gebildet werden.
Diese Unterklasse enthält dann den entsprechenden Code, den die anonyme Klasse / Lambda-Funktion ausführen würde
und kann normal als Klasse serialisiert und deserialisiert werden.
Falls ein spezieller Collection oder Map-Typ benutzt wird, der nicht deserialisiert werden kann, wird der Typ der Collection in eine möglichst geeignete, der Struktur ähnliche, alternative Klasse umgewandelt. In diesem Fall wird standardmäßig eine Warnung ausgedruckt, die beschreibt, welche Klasse benutzt wurde. Beim Erstellen der Serialiser-Instanz lässt sich allerdings einer von vier Modi auswählen, der bestimmt, wie sich der Serialiser in diesem Fall verhalten soll. Zusätzlich lassen sich mit der IgnoreCasting-Annotation auch die Warnungen für ein bestimmtes Feld, z. B. wenn ein Casten in diesem Fall beabsichtigt ist, unterdrücken.
Collections oder Maps, die entweder keinen Konstruktor besitzen (z. B. EnumSets) oder, die zusätzlich zu den
eigentlichen Werten weitere Inhalte speichern (z. B. TreeSets), können automatisch nicht 100%ig korrekt
wiederhergestellt werden.
Wie in Eventuelles Casten von Collections / Maps gezeigt,
werden Collections oder Maps ohne Konstruktor in eine möglichst ähnliche andere Collection / Map deserialisiert;
zusätzliche Inhalte, die in Collections oder Maps gespeichert sind, werden nicht wiederhergestellt.
Das kann dazu führen, dass sich die Collections / Maps im Nachhinein anders verhalten als vor der Serialisierung.
Im Folgenden sind zwei Beispiele abgebildet, die zeigen, wie man manuell jeden dieser Spezialfälle korrekt
speichern und wiederherstellen kann, um dies zu vermeiden:
Einige Collections / Maps besitzen keinen Konstruktor. In diesem Fall wird die Collection / Map
beim Deserialisieren in eine möglichst ähnliche andere Collection / Map umgewandelt.
Im Falle eines EnumSets wird beispielsweise ein LinkedHashSet wiederhergestellt, das deutlich weniger performant
ist als das für Enums optimierte EnumSet.
Häufig ist dies eine ausreichende Alternative, allerdings kann es auch Fälle geben, in denen es notwendig
ist, dass die eigentliche spezielle Collection / Map ohne Konstruktor wiederhergestellt wird.
Daher wird hier am Beispiel eines EnumSets gezeigt, wie man das machen kann:
@SerialiseIgnore
private EnumSet<ExampleEnum> enumSet;
@IgnoreCasting
private Set<ExampleEnum> enumSetForSerialisation;
@BeforeSerialise
private void serialiseEnumSet() {
enumSetForSerialisation = enumSet;
}
@AfterDeserialise
private void deserialiseEnumSet() {
enumSet = EnumSet.copyOf(enumSetForSerialisation);
enumSetForSerialisation = null;
}
Der Serialiser macht bei diesem Code das Folgende:
Vor der Serialisierung wird die Variable enumSetForSerialisation auf das enumSet gelegt.
Bei der Serialisierung wird die eigentliche Variable enumSet wegen der SerialiseIgnore-Annotation nicht
serialisiert, sondern nur enumSetForSerialisation.
Bei der Deserialisierung wird enumSetForSerialisation von einem EnumSet zu einem LinkedHashSet umgecastet.
Das ist der Grund, warum enumSetForSerialisation vom allgemeineren Typen "Set" sein muss.
Wegen der IgnoreCasting-Annotation wird keine Warnung geworfen.
Nach der Deserialisierung wird ein neues EnumSet mit den Inhalten des LinkedHashSets enumSetForSerialisation
generiert und auf die Variable enumSet gelegt. Die Variable enumSetForSerialisation wird zurückgesetzt.
Somit wird das EnumSet mit allen Inhalten serialisiert und korrekt als EnumSet wiederhergestellt.
Der Vorteil der zusätzlichen Variable enumSetForSerialisation ist, dass die eigentliche Variable
enumSet als EnumSet gespeichert werden kann (während enumSetForSerialisation das allgemeinere Set sein muss).
Falls das EnumSet selbst nur als Set gespeichert wird, kann man die zusätzliche Variable aber auch weglassen.
Einige Collections / Maps speichern zusätzlich zu den Elementen noch andere Werte. Beim normalen Serialisieren
werden lediglich die Elemente gespeichert und wiederhergestellt, zusätzliche Werte gehen dabei verloren.
Im Falle eines TreeSets wird beispielsweise der Comparator nicht wiederhergestellt.
Es kann allerdings notwendig sein, dass die Collection / Map auch mit bestimmten zusätzlichen Werten
wiederhergestellt wird, damit sie sich nicht anders verhält als vor der Serialisierung.
Daher wird hier am Beispiel eines TreeSets gezeigt, wie man das machen kann:
private TreeSet<String> treeSet;
@AfterDeserialise
private void deserialiseTreeSet() {
TreeSet<String> help = new TreeSet<>(Comparator.comparingInt(String::length));
help.addAll(so);
so = help;
}
Der Serialiser macht bei diesem Code das Folgende:
Das TreeSet wird normal serialisiert und die einzelnen Elemente werden gespeichert.
Das TreeSet wird normal deserialisiert und die einzelnen Elemente werden als Werte des TreeSets gesetzt.
Nach der Deserialisierung wird ein neues TreeSet erstellt, das einen eigenen Comparator, der festgelegt ist
sowie alle Elemente, die gespeichert wurden, besitzt.
Somit wird das TreeSet mit allen Elementen und dem Comparator korrekt wiederhergestellt.
Falls der Comparator nicht, wie in diesem Beispiel, immer gleich ist, sondern dynamisch wechseln kann, kann er alternativ auch (als Unterklasse) selbst gespeichert und wiederhergestellt werden.
Standardmäßig wird eine DeserialiseException geworfen, falls während der Deserialisierung eine "neue Variable",
also eine Variable in einer Klasse, die nicht im JSON-gespeichert wurde, aber (de-)serialisiert werden soll,
entdeckt wird. Im Normalfall ist dies das gewünschte Verhalten, um sicherzustellen, dass die resultierende
Objektstruktur identisch zur Originalen ist.
Falls der Serialiser aber über verschiedene Versionen eines Programmes hinweg benutzt werden soll, wenn z. B. vor
einer Aktualisierung eine Serialisierung und nach der Aktualisierung die Deserialisierung passieren soll, können
Klassen neue Variablen bekommen. In diesem Fall ist es also gewünscht, dass solche neuen Variablen ignoriert
werden. Dies lässt sich in der Konfiguration einstellen.
JSON wurde ursprünglich für Javascript entwickelt und ist auf die Bedürfnisse dieser Sprache angepasst. Der JSON-Parser dieses Serialisers weicht in einigen Punkten von dem offiziellen JSON-Standard ab, da er für diesen Serialiser und dessen Aufgaben speziell optimiert ist:
- Chars werden als einzelne Zeichen zwischen einem '-Paar kodiert
- '-Zeichen werden daher mit einem Backslash (\) escaped
- Schrägstriche (/) werden nicht mit einem Backslash escaped
- Die Zahlenwerte NaN, Infinity und -Infinity werden gespeichert und wiederhergestellt
- Bytes wird am Ende der Zahl ein B, Shorts ein S, Longs ein L und Floats ein F hinzugefügt
Der CircularJsonSerialiser ist unter der GNU Affero General Public Licence v3 lizenziert.
Wenn der Quellcode verändert oder für ein anderes Projekt in irgendeiner Form benutzt wird und der veränderte
Code bzw. das eigene Projekt geteilt, verkauft, auf einen Server geladen oder anderweitig zur Verfügung gestellt
wird, muss der vollständige Quellcode des Resultats unter dieser Lizenz (GNU AGPNv3) geteilt werden.
Siehe LICENSE für mehr Informationen.