{"id":21665065,"url":"https://github.com/galan/verjson","last_synced_at":"2025-10-15T13:34:15.117Z","repository":{"id":12956533,"uuid":"15634816","full_name":"galan/verjson","owner":"galan","description":"A Java serializer for evolving data-structures","archived":false,"fork":false,"pushed_at":"2017-11-21T08:05:58.000Z","size":349,"stargazers_count":10,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-25T20:12:56.518Z","etag":null,"topics":["jackson","java","json-schema","schema-evolution","transformations"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/galan.png","metadata":{"files":{"readme":"README.md","changelog":"changes.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-01-04T15:53:12.000Z","updated_at":"2019-07-12T15:07:18.000Z","dependencies_parsed_at":"2022-09-26T22:01:25.484Z","dependency_job_id":null,"html_url":"https://github.com/galan/verjson","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/galan%2Fverjson","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/galan%2Fverjson/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/galan%2Fverjson/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/galan%2Fverjson/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/galan","download_url":"https://codeload.github.com/galan/verjson/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248501189,"owners_count":21114626,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["jackson","java","json-schema","schema-evolution","transformations"],"created_at":"2024-11-25T10:48:49.751Z","updated_at":"2025-10-15T13:34:15.037Z","avatar_url":"https://github.com/galan.png","language":"Java","readme":"Verjson is a specialized Java/JSON serialization-library that allows evolvable data-structures on already serialized object-graphs by using transformation and validation steps between versions.\n\n![Verjson](https://github.com/galan/verjson/raw/master/resources/Verjson.png)\n\n# Problem description\nWhen you have to send an object-graph from one process to another, you have to serialize the data into an exchange-format that can be read by the receiver. There are plenty of possiblities in the Java space to perform such a task, eg. native Java serialization, XML (XStream, ..) , JSON (Gson, Jackson, ..), SOAP, and more (Avro, Protobuf, ..). These solutions work great until the object-graph changes too much. Some of the libraries also offer version-support ([1](http://martin.kleppmann.com/2012/12/05/schema-evolution-in-avro-protocol-buffers-thrift.html), ..), most have limitations.\n\nBut what if complex real-world changes happen, and you want to keep your object-model code clean? If you want to remove or rename fields, create a Collection from a previously comma-seperated String, change a field to a another type, or other changes?\n\nOf course you can simply deploy the next version of your software/models. But what about the in-flight messages that still have to be processed and are are serialized in some older version? How about long-term storage of such object-graphs if they are written to files, and are a couple of versions behind?\n\n# Solution\nWith Verjson each serialized object-graph includes its version-number along other meta-data. Verjson utilizes Jackson to generate JSON as intermediate-format. When the structure of the object-graph changes, a simple `Transformation` class has to be implemented that performs the steps to transform from one version to another. The transformation is applied directly on the serialized JSON, which has some benefits such as performance, memory-footprint, avoid code-redundancy, etc.. To ensure correctness the transformed output can be optional validated against an JSON-Schema.\n\nLet's take a quick look on a short example to illustrate the process ([source code](https://github.com/galan/verjson/blob/master/src/test/java/de/galan/verjson/examples/simple/ExampleBeanTest.java)).\n\nWe have a simple bean that should be serialized:\n```java\npublic class ExampleBean {\n\tString text;\n\tLong number;\n}\n```\n\nFirst we create a Verjson instance that contains the configuration and manages the serialization. In this case there is no configuration, since this is the first version which requires no transformations (validation is optional, see [other examples](https://github.com/galan/verjson/tree/master/src/test/java/de/galan/verjson/examples)):\n```java\nVerjson\u003cExampleBean\u003e verjson = Verjson.create(ExampleBean.class, null);\n```\n\nNow we can serialize/deserialize ExampleBean objects:\n```java\nExampleBean bean = new ExampleBean();\nbean.text = \"Hello\";\nbean.number = 42L;\n\nString serializedBean = verjson.write(bean);\nExampleBean deserializedBean = verjson.read(serializedBean);\n```\n\nThe requirements change and we want to have a list instead of a single String field. We don't want to loose data and have the content of the \"text\" field as first element. Furthermore the name of the \"number\" field should be changed to \"counter\". We change the ExampleBean (there is no requirement to keep the old version copied to somewhere), now it looks like this:\n```java\npublic class ExampleBean {\n\tList\u003cString\u003e texts;\n\tLong counter;\n}\n```\n\nIn order to transform old data we have to write a `Transformation` class (`Transformations` contains static methods that should be static imported):\n```java\npublic class Transformation1 extends Transformation {\n\t@Override\n\tprotected void transform(JsonNode node) {\n\t\tobj(node).put(\"texts\", createArray(remove(obj(node), \"text\")));\n\t\trename(obj(node), \"number\", \"counter\");\n\t}\n}\n```\n\nThen we create the configuration for Verjson by subclassing `Versions`. This configuration class will grow over time, new versions/transformations, validation will be added. Custom serializer/deserializer and polymorph types will be registered here too.\n```java\npublic class ExampleBeanVersions extends Versions {\n\t@Override\n\tpublic void configure() {\n\t\tadd(1L, new Transformation1());\n\t}\n}\n```\n\nHere is the modified example that serializes ExampleBean objects in version 2, and also could read serialized objects from version 1 and 2:\n```java\nVerjson\u003cExampleBean\u003e verjson = Verjson.create(ExampleBean.class, new ExampleBeanVersions());\n\nExampleBean bean = new ExampleBean();\nbean.texts = Lists.newArrayList(\"Hello\");\nbean.counter = 42L;\n\nString serializedBean = verjson.write(bean);\nExampleBean deserializedBean = verjson.read(serializedBean);\n```\n\n## Recap\n1. Use Verjson to serialize/deserialize your models\n2. Use an extended `Versions` object to configure Verjson\n3. Extend a `Transformation` for each version of your model, do not change that later (create a new version instead)\n4. Create a `Validator` for each version  of your model that you whish to validate against a json-schema\n\n## Tips\n* Move your model, Versions, Transformations and json-schemas into an own maven-artifact. So you can manage the versions much easier\n* Unit-test your transformations and json-schemas\n* Take a look into the [examples](https://github.com/galan/verjson/tree/master/src/test/java/de/galan/verjson/examples)\n\n# Possible use-cases:\n* messaging (eg. in-flight messages)\n* long-term storage\n* producer/consumer scenarios\n* data-processing in general\n* ... (tell me how you use it)\n\n# Features\n* Serializes/Deserializes into JSON (Jackson based)\n* Custom transformation between versions\n* Support for polymorph types\n* Support for custom-type Serializer/Deserializer\n* Each version can be validated using JSON-Schema\n* Versions can be omitted\n* One line per serialized object (appendable)\n* Thread-safe\n\n# Integration with Maven\nJust add the following dependency:\n\n    \u003cdependency\u003e\n    \t\u003cgroupId\u003ede.galan\u003c/groupId\u003e\n    \t\u003cartifactId\u003everjson\u003c/artifactId\u003e\n    \t\u003cversion\u003e0.7.0\u003c/version\u003e\n    \u003c/dependency\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgalan%2Fverjson","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgalan%2Fverjson","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgalan%2Fverjson/lists"}