{"id":20770791,"url":"https://github.com/ably/delta-codec-java","last_synced_at":"2026-03-27T02:15:41.452Z","repository":{"id":52957801,"uuid":"208078946","full_name":"ably/delta-codec-java","owner":"ably","description":null,"archived":false,"fork":false,"pushed_at":"2021-04-12T12:59:15.000Z","size":127,"stargazers_count":2,"open_issues_count":1,"forks_count":3,"subscribers_count":26,"default_branch":"main","last_synced_at":"2025-12-26T18:47:53.985Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ably.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}},"created_at":"2019-09-12T15:06:18.000Z","updated_at":"2025-03-03T08:27:28.000Z","dependencies_parsed_at":"2022-08-26T13:24:19.652Z","dependency_job_id":null,"html_url":"https://github.com/ably/delta-codec-java","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ably/delta-codec-java","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ably%2Fdelta-codec-java","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ably%2Fdelta-codec-java/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ably%2Fdelta-codec-java/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ably%2Fdelta-codec-java/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ably","download_url":"https://codeload.github.com/ably/delta-codec-java/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ably%2Fdelta-codec-java/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31009852,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-27T01:56:05.093Z","status":"online","status_checked_at":"2026-03-27T02:00:08.055Z","response_time":164,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2024-11-17T12:11:58.171Z","updated_at":"2026-03-27T02:15:41.422Z","avatar_url":"https://github.com/ably.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# VCDIFF Delta Codec for Java\n\n[![Build Status](https://travis-ci.org/ably/delta-codec-java.svg?branch=main)](https://travis-ci.org/ably/delta-codec-java)\n\n## Overview\n\nThis codec wraps [vcdiff-java](https://github.com/ehrmann/vcdiff-java), an implementation of\n[RFC 3284](https://tools.ietf.org/html/rfc3284) \"The VCDIFF Generic Differencing and Compression Data Format\",\nmaking it easier to use VCDIFF for delta applications including with Ably's services.\n\nSupported platforms:\n\n- **Java**: Java 7 or newer\n- **Android**: `android-19` or newer as the target SDK, `android-16` or newer as a target platform\n\n## General Use\n\nThe `VcdiffDecoder` class is an entry point to the public API. It provides a stateful way of applying a stream of `vcdiff` deltas.\n\n`VcdiffDecoder` can do the necessary bookkeeping in the scenario where a number of successive deltas/patches have to be applied where each of them represents the difference to the previous one (e.g. a sequence of messages each of which represents a set of mutations to a given JavaScript object; i.e. sending only the mutations of an object instead the full object each time).\n\nIn order to benefit from the bookkeeping provided by the `VcdiffDecoder` class one has to first provide the base object that the first delta would be generated against. That could be done using the `setBase` method. The most simple flavor of `setBase` is:\n\n```\nVcdiffDecoder decoder = new VcdiffDecoder();\ndecoder.setBase(baseObject /*the base object/message*/);\n```\n\nOnce the decoder is initialized like this it could be used to apply a stream of deltas/patches each one resulting in a new full payload. E.g. for binary objects/messages:\n\n```\nbyte[] result = decoder.applyDelta(vcdiffDelta).asByteArray();\n```\n\nor for string objects/messages:\n\n```\nstring result = decoder.applyDelta(vcdiffDelta).asUtf8String();\n```\n\n`applyDelta` could be called as many times as needed. The `VcdiffDecoder` will automatically retain the last delta application result and use it as a base for the next delta application. Thus it allows applying an infinite sequence of deltas.\n\n`applyDelta` return type is `DeltaApplicationResult`. That is a convenience class that allows interpreting the result in various data formats - string, array, etc.\n\n`CheckedVcdiffDecoder` is a flavor of `VcdiffDecoder` that could be used if deltas and objects against which deltas are generated have unique IDs. `CheckedVcdiffDecoder`'s `setBase` and `applyDelta` methods require these IDs and make sure the deltas are applied to the objects they were generated against. E.g.\n\n```\nDeltaApplicationResult result = checkedDecoder.applyDelta(vcdiffDelta, \n                deltaID,/*any unique identifier of the delta there might be*/ \n                baseID/*any unique identifier of the object this delta was generated against there might be */);\n```\n\nThere are `base64` flavors of `setBase` and `applyDelta` that would accept `base64` encoded input - `setBase64Base` and `applyBase64Delta`. These are convenience methods and they follow the same logic as `setBase` and `applyDelta`.\n\n## Ably Use\n\n### MQTT with Binary Payload\n\nThis is a simple example that uses this codec to handle delta messages received from Ably over an MQTT connection.\n\n    public class Main {\n        public static void main(String[] args) {\n            final String channelName = \"sample-app-mqtt\";\n            final Mqtt3AsyncClient client = createClient();\n            final VcdiffDecoder channelDecoder = new VcdiffDecoder();\n\n            connect(client, () -\u003e {\n                subscribe(client, \"[?delta=vcdiff]\" + channelName, (payload) -\u003e {\n                    byte[] data;\n                    try {\n                        if (VcdiffDecoder.isDelta(payload)) {\n                            data = channelDecoder.applyDelta(payload).asByteArray();\n                        } else {\n                            data = payload;\n                            channelDecoder.setBase(data);\n                        }\n                    } catch (Throwable error) {\n                        /* Delta decoder error */\n                        System.out.println(error.getMessage());\n                        return;\n                    }\n\n                    /* Process decoded data */\n                    System.out.println(Arrays.toString(data));\n                });\n            });\n        }\n\n        private static Mqtt3AsyncClient createClient() {\n            return Mqtt3Client.builder()\n                .serverHost(\"mqtt.ably.io\")\n                .serverPort(8883)\n                .sslWithDefaultConfig()\n                .simpleAuth(\n                    Mqtt3SimpleAuth.builder()\n                        .username(\"FIRST_HALF_OF_API_KEY\")\n                        .password(\"SECOND_HALF_OF_API_KEY\".getBytes(StandardCharsets.UTF_8))\n                        .build()\n                )\n                .buildAsync();\n        }\n\n        private static void connect(Mqtt3AsyncClient client, Runnable callback) {\n            client.connect().whenComplete((mqtt3ConnAck, throwable) -\u003e {\n                if (throwable != null) {\n                    System.out.println(\"Connect failed - \" + throwable.getMessage());\n                    return;\n                }\n\n                callback.run();\n            });\n        }\n\n        private static void subscribe(Mqtt3AsyncClient client, String channelName, Consumer\u003cbyte[]\u003e callback) {\n            client.subscribeWith()\n                .topicFilter(channelName)\n                .qos(MqttQos.AT_MOST_ONCE)\n                .callback(mqtt3Publish -\u003e callback.accept(mqtt3Publish.getPayloadAsBytes()))\n                .send();\n        }\n    }\n\n## Building\n\nA Gradle wrapper is included. The Linux / macOS form of the commands, given below, is:\n\n    ./gradlew \u003ctask name\u003e\n\nOn Windows there is a batch file:\n\n    gradlew.bat \u003ctask name\u003e\n\nThis library supports the standard gradle targets; for example, to build the library, use:\n\n    ./gradlew assemble\n\n## Tests\n\nRun tests with:\n\n    ./gradlew test\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fably%2Fdelta-codec-java","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fably%2Fdelta-codec-java","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fably%2Fdelta-codec-java/lists"}