{"id":16567823,"url":"https://github.com/sylvainhalle/azrael","last_synced_at":"2026-02-27T14:02:32.839Z","repository":{"id":52139802,"uuid":"50801385","full_name":"sylvainhalle/Azrael","owner":"sylvainhalle","description":"A universal Java serialization library","archived":false,"fork":false,"pushed_at":"2025-09-17T16:26:43.000Z","size":464,"stargazers_count":5,"open_issues_count":4,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-17T18:51:24.697Z","etag":null,"topics":["json","json-serialization","memento-pattern","serialization","serialization-library","universal-serialization-library","xml","xml-serialization","xml-serializer"],"latest_commit_sha":null,"homepage":"https://sylvainhalle.github.io/Azrael/javadoc","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sylvainhalle.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-01-31T23:32:36.000Z","updated_at":"2025-09-17T16:25:30.000Z","dependencies_parsed_at":"2025-02-13T23:43:17.808Z","dependency_job_id":null,"html_url":"https://github.com/sylvainhalle/Azrael","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/sylvainhalle/Azrael","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sylvainhalle%2FAzrael","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sylvainhalle%2FAzrael/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sylvainhalle%2FAzrael/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sylvainhalle%2FAzrael/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sylvainhalle","download_url":"https://codeload.github.com/sylvainhalle/Azrael/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sylvainhalle%2FAzrael/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29898849,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-27T12:09:13.686Z","status":"ssl_error","status_checked_at":"2026-02-27T12:09:13.282Z","response_time":57,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["json","json-serialization","memento-pattern","serialization","serialization-library","universal-serialization-library","xml","xml-serialization","xml-serializer"],"created_at":"2024-10-11T21:07:35.642Z","updated_at":"2026-02-27T14:02:32.823Z","avatar_url":"https://github.com/sylvainhalle.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"Azrael: a universal serialization library for Java\n==================================================\n\n![Azrael the cat](azrael.jpg?raw=true)\n\n\u003cimg src=\"http://leduotang.ca/Azrael.svg\" height=\"16\" alt=\"Downloads\"/\u003e\n\nAzrael is a [serialization](https://en.wikipedia.org/wiki/Serialization)\nlibrary for Java. It allows Java objects to be saved (\"serialized\") to\nsome data format, and to be reconstructed (\"deserialized\") from that saved\ndata at a later time.\n\nThe form to which objects are serialized is parameterizable. \nBy default, Azrael comes with a serializer for\n[JSON](https://en.wikipedia.org/wiki/JSON) and XML, but its\nAPI allows you to easily implement serialization to your own custom data\nformat.\n\n[Read the API documentation](https://sylvainhalle.github.io/Azrael/javadoc)\n\nHow it works\n------------\n\nSuppose you have the following class:\n\n```java\nclass MyClass {\n  int x = 0;\n  String s = \"\";\n  List\u003cFloat\u003e f = new LinkedList\u003cFloat\u003e();\n  \n  public add(Float x) {\n\tf.add(x);\n  }\n}\n```\n\nYou would like to serialize the state of objects of class `MyClass` to\nJSON. With Azrael, you can do the following:\n\n```java\n// Create an object and fill with values\nMyClass my_obj = new MyClass();\nmy_obj.x = 1; my_obj.s = \"abc\"; my_obj.add(1.5);\n\n// Create a serializer for JSON\nJsonPrinter p = new JsonPrinter();\nJsonElement e = p.print(my_obj);\n```\n\nThe contents of `my_obj` are saved in a JSON element, which you can save\nsomewhere as a string using its `toString()` method.\n\nNow suppose you want to reconstruct an object of `MyClass` with the exact\ndata that was contained in the saved JSON. You first reconstruct the JSON\nelement `e` (from a String, etc.), and then call the `read()` method:\n\n```java\nJsonReader d = new JsonReader();\nMyClass my_new_obj = (MyClass) d.read(e);\n```\n\nYou could check for yourself that the member fields of `my_obj` and\n`my_new_obj` are identical. Note that you don't need to use the same\ninstance serializer for both operations, or be in the same program when\nsaving and loading.\n\nThis, in a nutshell, is how Azrael works (and how other serialization\nlibraries work too, although with some peculiarities).\n\nFeatures\n--------\n\nAzrael was developed out of insatisfaction with existing (JSON)\nserialization libraries, mostly\n[Java Google Gson](https://code.google.com/p/google-gson/) (Gson) and\n[Genson](http://owlike.github.io/genson/). Here are a couple of features\nof Azrael for which other libraries didn't fit the author's needs.\n\n### Truly generic\n\nExisting serialization libraries are tied to a single specific output\nformat. Hence, if you want to serialize objects to another format than JSON\n(XML, strings, whatever custom format you wish), a JSON library can't help\nyou. You need to use yet another library (such as\n[XStream](http://x-stream.github.io/) for XML).\n\n**Not so with Azrael.** Its default `ObjectPrinter` and `ObjectReader`\nclasses take care of much of the work of decomposing an object and\ndetermining type information. JSON is just one possible way of implementing\nthe abstract methods of these two classes. To serialize to another format,\nsimply override them in a different way to produce the output you wish. (As\na matter of fact, the code specific to JSON serialization is a mere 600\nlines long.) The serialized object is not even aware of the format it is\nbeing serialized into.\n\nThis means that, in the example above, if you want to serialize `my_obj`\ninto XML, you simply pass `my_obj` to another type of object printer:\n\n```java\nXmlPrinter p = new XmlSerializer();\nXmlElement e = p.print(my_obj);\n```\n\nAnother nice consequence of Azrael's structure is that you can write\nserializers that do not even perform serialization. For example:\n\n- The `Core` folder provides an implementation of a serializer that prints\n  an object as itself. The deserializer deserializes primitive values as\n  themselves, and deserializes other objects as new instances of themselves.\n  The end result is a process that performs a\n  [deep copy](https://en.wikipedia.org/wiki/Object_copying) of an object.\n- The `Size` folder contains an implementation of a serializer that turns\n  any object into a number. This can be used to compute the size of an\n  arbitrary object using just 350 lines of code.\n  \n### Not forced to use reflection\n\nMost libraries use reflection to serialize an object. Some may argue that\nthis is a \"brutal\" process: the object is not aware it is being serialized,\nits internal contents are revealed bare (totally disregarding visibility\nmodifiers), and has no control over what and how things are serialized. The\nreverse operation creates an empty object skeleton, and forcefully populates\nits member fields --effectively treating the object as an inert\n\"[bag of data](https://www.yegor256.com/2016/07/06/data-transfer-object.html)\".\n\nIn contrast, an object can choose to cooperate with Azrael by implementing\nthe `Printable` interface to serialize itself of its own will, and the\n`Readable` interface to create a new instance from a serialized version.\nWhat is more, the object does not need to be aware of the format to which it\nis serialized: Azrael takes care of that.\n\nAs an example, consider again the class `MyClass`:\n\n```java\nclass MyClass implements Printable, Readable {\n  int x = 0;\n  String s = \"\";\n  List\u003cFloat\u003e f = new LinkedList\u003cFloat\u003e();\n  \n  public add(Float x) {\n\tf.add(x);\n  }\n  \n  public Object print(ObjectPrinter\u003c?\u003e printer) {\n\tList\u003cObject\u003e list = new ArrayList\u003cObject\u003e();\n\tlist.add(System.currentTimeMillis() / 1000);\n\tlist.add(x);\n\tlist.add(s);\n\tlist.add(f);\n\treturn printer.print(list);\n  }\n  \n  public Object read(ObjectReader\u003c?\u003e reader, Object o) throws ReadException {\n\tList\u003cObject\u003e list = (List\u003cObject\u003e) reader.read(o);\n\tlong now = System.currentTimeMillis() / 1000;\n\tif (now - (Long) list.get(0) \u003e 600) {\n\t  throw new ReadException(\"Copy is too old\");\n\t}\n\tMyClass mc = new MyClass((Integer) list.get(1), (String) list.get(2));\n\tfor (float f : (List\u003cFloat\u003e) list.get(3)) {\n\t  mc.add(f);\n\t}\n\treturn mc;\n  }\n}\n```\n\nThis time, the class implements `Printable`, and decides what and how to\nprint its contents. In this case, the choice is to use a list; notice how\nthe first element of that list is *not* even part of the object's state\n(in this case, a timestamp indicating when the serialization was made).\nThe object simply asks an anonymous `ObjectPrinter` to print the contents of\nthis list --whether this is done with JSON, XML or something else is\ncompletely irrelevant to the class.\n\nSimilarly, the `read` method implements the `Readable` interface. Notice\nhow the object asks an `ObjectReader` to deserialize an arbitrary object\n`o`, which recovers the list that was saved by `print`. Again, exactly what\nis `o` (XML? JSON? something else?) is irrelevant. The contents of the\nlist are used to recreate a new instance of `MyClass`, but through means\nthat the object itself controls. Remark how the timestamp that was\nserialized by the object is used to throw an exception when the copy is\ntoo old.\n\n### No reliance on declared type\n\nWhen serializing member fields of an object, Azrael inserts information\nabout the actual type of an object, and not the type that is declared in\na class. Consider the following example:\n\n```java\nabstract class A { \n}\n\nclass B extends A {\n  int x = 0;\n}\n\nclass C {\n  A my_b = new B();\n}\n```\n\nWhen deserializing an object of class `C`, other libraries run into a\nproblem, as they try to instantiate an object of class `A`, since this is\nthe *declared* type of field `my_b`. But `A` is an abstract class, and\ncannot be instantiated. To handle this case with Gson, you need to write\nyet more custom code to take care of this (not quite) exceptional\nsituation.\n\n**Not so with Azrael**, which takes care of adding to the serialization that\nthe actual class of `my_b` is `B`, enabling it to properly deserialize the\nobject. Works out of the box, period.\n\nThis means that you can serialize generic collections such as lists, sets\nand maps easily. In many other serialization libraries, \"collections require special\ntreatment since the Collections are of generic type and the type information\nis lost while converting to JSON due to Java type erasure\" (says the [Gson\ndocumentation](http://www.studytrails.com/java/json/java-google-json-introduction.jsp)).\n\n**Not so with Azrael**, which *does* takes care of serializing the exact\nclass of each element in a collection (list, map, set). Hence you can write,\nas you would for any other object:\n\n```java\nList\u003cInteger\u003e list1 = new LinkedList\u003cInteger\u003e();\n(...Fill the list with stuff...)\nObject o = serializer.print(list1);\nList\u003cInteger\u003e list2 = (List\u003cInteger\u003e) serializer.read(o);\n```\n\nThe contents of `list2` recreate precisely the original objects with their\n*actual* (not declared) type. No custom code is needed (contrary to what\nGson requires).\n\nFridges\n-------\n\nAzrael also defines an interface called a `Fridge`, which is an \nimplementation of the [memento pattern](https://en.wikipedia.org/wiki/Memento_pattern).\nA fridge can be used to store an object (using a method called `store`),\nand retrieve this object at a later time (using a method called `fetch`).\nExactly how and where this object is stored is transparent to the user.\n\nFor example, a `FileFridge` serializes the object (using an arbitrary\nformat) and saves it as a local text file. The fetch operation loads that\nfile and deserializes its content to recreate the original object. Consider\nthe following code:\n\n```java\nMyClass mc = ...\nXmlFileFridge fridge = new XmlFileFridge(\"/path/to/file.xml\");\nfridge.store(mc);\n(... Some time later ...)\nMyClass mc_new = (MyClass) fridge.fetch();\n```\n\nThe generic `Fridge` interface can be implemented for other purposes. For\nexample, one could imagine a fridge that sends the object's contents to\na remote server using an HTTP request, or that stores it into a database.\n\nSpecifying class loaders\n------------------------\n\nIf you use Azrael as a library within your own project, it cannot\ninstantiate objects outside of the basic Java classes out of the box.\nYou need to give one or more *class loaders* that will enable it to\ncreate instances of your objects.\n\nSuppose for example that you have a package called `my.package`; to\nhelp Azrael create objects from this package, do the following:\n\n```java\nmy_serializer.addClassLoader(my.package.MyClass.class.getClassLoader());\n```\n\nwhere `MyClass` is any of the classes of `my.package`. This should normally\nbe enough for all classes of that package. You can add more than one\nclass loader to Azrael; when it attempts to instantiate an object, it tries\nthem all until one of them works.\n\nCustom handlers\n---------------\n\nIf you would like to serialize objects that do not implement `Printable` and\n`Readable` in a special way, you can do so by creating a custom\n`PrintHandler` and `ReadHandler`. The print handler must implement a method\ncalled `canHandle`, which must return `true` when given an object it can\nserialize (and `false` otherwise). The method `handle` should contain custom\ncode that takes care of printing the content of that object. Conversely, the\nread handler also has a method called `canHandle`, and another called\n`read` which should should contain custom code that takes care of reading\nthe content of that object.\n\nDisabling access checks\n-----------------------\n\nIn version 9 of Java onwards, serialization using reflection can sometimes\ncause an exception that looks like this:\n\n```\njava.lang.reflect.InaccessibleObjectException: Unable to make field private\nstatic final jdk.internal.misc.Unsafe jdk.internal.misc.InnocuousThread.UNSAFE accessible:\nmodule java.base does not \"opens jdk.internal.misc\" to unnamed module @5cba847b\n...\n```\n\nAs per this [StackOverflow answer](https://stackoverflow.com/a/56339895),\nthis is caused by the fact that \"one of the dependencies of your project is\ntrying to access a JVM API which was moved to an internal Java module, and\nis no longer exposed\". The workaround is to run the application with the\nfollowing flag:\n\n```\n--add-opens jdk.management/xxx.xxx.xxx=ALL-UNNAMED\n```\n\nWhere `xxx.xxx.xxx` is the name of the offending package in the exception's\nmessage (here \"jdk.internal.misc\").\n\nAnother possibility is to make Azrael silently ignore these warnings. In\norder to do so, call `ignoreAccessChecks(true)` on an `ObjectPrinter` or\nan `ObjectReader`.\n\nDependencies\n------------\n\nThis project is separated in two parts:\n\n- The `Core` folder generates a small JAR file that only defines the\n  *interfaces* to support serialization. If you develop a library and\n  want your objects to be serialized, simply include this JAR in your\n  project.\n- The other folders implement serialization in a variety of formats. For\n  example, the `Json` folder provides a JSON serializer; the `Xml`\n  folder provides an XML serializer.\n\nThese JARs may themselves have dependencies.\n\n- JSON serialization requires that the library\n  [json-lif](https://github.com/liflab/json-lif) be in your\n  classpath.\n- XML serialization requires that the library\n  [xml-lif](https://github.com/liflab/xml-lif) be in your\n  classpath.\n\nProjects that use Azrael\n------------------------\n\n- [Cornipickle](https://github.com/liflab/cornipickle), a web testing tool\n- [LabPal](https://liflab.github.io/labpal), a library for running\n  experiments on a computer\n- The [Serialization palette](https://github.com/liflab/beepbeep-3-palettes)\n  and [Hibernate palette](https://github.com/liflab/beepbeep-3-palettes)\n  of the [BeepBeep 3](https://liflab.github.io/beepbeep-3) event stream\n  processing engine.\n\nAbout the name\n--------------\n\nAll the letters of \"Azrael\" are contained in the word \"serialization\".\nAnything to add?\n\nAbout the author                                                   {#about}\n----------------\n\nAzrael was written by Sylvain Hallé, professor at Université\ndu Québec à Chicoutimi, Canada.\n\n\u003c!-- :maxLineLen=76: --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsylvainhalle%2Fazrael","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsylvainhalle%2Fazrael","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsylvainhalle%2Fazrael/lists"}