{"id":21399315,"url":"https://github.com/streamr-dev/streamr-client-java","last_synced_at":"2026-03-16T16:39:23.891Z","repository":{"id":36098470,"uuid":"136232339","full_name":"streamr-dev/streamr-client-java","owner":"streamr-dev","description":"Java library for interacting with Streamr APIs: publishing and subscribing to data, creating streams, etc.","archived":false,"fork":false,"pushed_at":"2023-04-06T05:57:30.000Z","size":1688,"stargazers_count":5,"open_issues_count":11,"forks_count":4,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-07-10T16:51:12.106Z","etag":null,"topics":[],"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/streamr-dev.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":"2018-06-05T20:40:11.000Z","updated_at":"2022-10-24T07:58:42.000Z","dependencies_parsed_at":"2023-02-19T04:45:38.825Z","dependency_job_id":null,"html_url":"https://github.com/streamr-dev/streamr-client-java","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/streamr-dev/streamr-client-java","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamr-dev%2Fstreamr-client-java","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamr-dev%2Fstreamr-client-java/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamr-dev%2Fstreamr-client-java/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamr-dev%2Fstreamr-client-java/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/streamr-dev","download_url":"https://codeload.github.com/streamr-dev/streamr-client-java/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/streamr-dev%2Fstreamr-client-java/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265200062,"owners_count":23726765,"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":[],"created_at":"2024-11-22T15:14:05.151Z","updated_at":"2026-03-16T16:39:23.836Z","avatar_url":"https://github.com/streamr-dev.png","language":"Java","readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://streamr.network\"\u003e\n    \u003cimg alt=\"Streamr\" src=\"https://raw.githubusercontent.com/streamr-dev/network-monorepo/main/packages/client/readme-header-img.png\" width=\"1320\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n# Streamr Java Client\n\n**NOTE: This library is deprecated! It works with the Corea milestone network, but won't work with Brubeck which launches in Q1/2022. The [Broker node](https://streamr.network/docs/streamr-network/installing-broker-node) pattern works trivially with any programming language including Java. Or if you happen to run JS, you could check out the [light node](https://streamr.network/docs/streamr-network/using-a-light-node) pattern as well.**\n\nUsing this library, you can easily interact with Streamr over HTTP and websocket APIs from Java-based applications.\n\nThis library covers the following functionality:\n\n- [Authentication](#authentication)\n- [Data signing](#signing)\n- [Handling Errors](#handling-errors)\n- [Creating Streams](#creating-streams)\n- [Looking up Streams](#looking-up-streams)\n- [Publishing events to Streams](#publishing)\n- [Subscribing and unsubscribing to Streams](#subscribing-unsubscribing)\n- [Data Unions](#data-unions)\n\n[![CI](https://github.com/streamr-dev/streamr-client-java/actions/workflows/ci-cd.yaml/badge.svg)](https://github.com/streamr-dev/streamr-client-java/actions/workflows/ci-cd.yaml)\n\n## Installation\n\nThis library is published to the Maven Central repository.\n\n#### Using Maven\n\nIn your `pom.xml`, add the repository:\n```\n\u003crepositories\u003e\n  \u003crepository\u003e\n    \u003curl\u003ehttps://dl.bintray.com/ethereum/maven\u003c/url\u003e\n  \u003c/repository\u003e\n  ...\n\u003c/repositories\u003e\n```\nAnd the artifact itself (replace x.y.z with the [latest version](https://mvnrepository.com/artifact/com.streamr/client)):\n```\n\u003cdependencies\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003ecom.streamr\u003c/groupId\u003e\n    \u003cartifactId\u003eclient\u003c/artifactId\u003e\n    \u003cversion\u003ex.y.z\u003c/version\u003e\n  \u003c/dependency\u003e\n  ...\n\u003c/dependencies\u003e\n```\n\n#### Using Gradle\n\nIn your `build.gradle`, add the repository:\n```\nrepositories {\n    maven {\n        url \"https://dl.bintray.com/ethereum/maven/\"\n    }\n}\n```\nAnd the artifact itself (replace x.y.z with the [latest version](https://mvnrepository.com/artifact/com.streamr/client)):\n```\ndependencies {\n    implementation 'com.streamr:client:x.y.z'\n}\n```\n\n## Usage\n\nEvery interaction with Streamr is done through a `StreamrClient` instance. In the following sections, we will see how to:\n- [Create a `StreamrClient` instance with different options](#options)\n- [Create streams](#creating-streams)\n- [Look up streams](#looking-up-streams)\n- [Publish events to streams](#publishing)\n- [Subscribe and unsubscribe to streams](#subscribing-unsubscribing)\n\n\u003ca name=\"options\"\u003e\u003c/a\u003e\n#### Instantiation and options\n\nQuickstart (unauthenticated):\n\n```java\nStreamrClient client = new StreamrClient();\n```\n\nQuickstart (authenticated):\n\n```java\n// An Ethereum private key to use for signing and identity\nString myPrivateKey = \"0x...\"; \nStreamrClient client = new StreamrClient(new EthereumAuthenticationMethod(myPrivateKey));\n```\n\nFor full configuration of the client's behavior, you can construct the client with `StreamrClientOptions`:\n\n```java\nStreamrClientOptions options = new StreamrClientOptions(...);\nStreamrClient client = new StreamrClient(options);\n```\n\nThe complete constructor of the `StreamrClientOptions` has the following signature:\n\n```java\nStreamrClientOptions(\n  AuthenticationMethod authenticationMethod,\n  SigningOptions signingOptions,\n  EncryptionOptions encryptionOptions,\n  String websocketApiUrl,\n  String restApiUrl,\n  int propagationTimeout,\n  int resendTimeout,\n  boolean skipGapsOnFullQueue\n)\n```\n\nThe next subsections will cover every parameter of the `StreamrClientOptions` constructor:\n- [Authentication options](#authentication)\n- [Signing options](#signing)\n- [Encryption options](#encryption)\n- [Other options](#other-options)\n\n\u003ca name=\"authentication\"\u003e\u003c/a\u003e\n## Authentication\nTo authenticate as a Streamr user, provide an `AuthenticationMethod` instance. We have one concrete class that extend `AuthenticationMethod`:\n\n- `EthereumAuthenticationMethod(String ethereumPrivateKey)`\n\nTo authenticate with an Ethereum account, create an `EthereumAuthenticationMethod` instance and pass it to the `StreamrClient` constructor:\n\n```java\nStreamrClient client = new StreamrClient(new EthereumAuthenticationMethod(myEthereumPrivateKey)); \n```\n\nThe library will automatically initiate a challenge-response protocol to allow you to prove that you own the Ethereum private key without revealing it. You will be identified with the associated Ethereum public address. At the end of the protocol, the library will fetch a session token to allow authenticated requests to be made.\n\nYou can access public resources without authenticating. In this case you can create the instance without any arguments:\n\n```java\nStreamrClient client = new StreamrClient();\n```\n\n\u003ca name=\"signing\"\u003e\u003c/a\u003e\n## Signing\n\nThe events published to streams can be signed using an Ethereum private key and verified using the corresponding Ethereum public key. The signing options define two policies: one deciding when to sign, the other when to verify.\n\nThe `SigningOptions` instance can be constructed as follows: \n\n```java\nSigningOptions.SignatureComputationPolicy signPol = SigningOptions.SignatureComputationPolicy.AUTO; // or ALWAYS or NEVER\nSigningOptions.SignatureVerificationPolicy verPol = SigningOptions.SignatureVerificationPolicy.AUTO; // or ALWAYS or NEVER\nSigningOptions signingOptions = new SigningOptions(signPol, verPol);\n```\n\nThe following table describes the meaning of the different values for the `SignatureComputationPolicy` enum.\n\nOption value | Description\n:------------ | :-----------\nAUTO | Default value. Published events will be signed if and only if the client is authenticated using the `EthereumAuthenticationMethod`.\nALWAYS | The constructor will throw if the authentication method is not `EthereumAuthenticationMethod`. Will sign events otherwise.\nNEVER | Won't sign published events.\n\nThe following table describes the meaning of the different values for the `SignatureVerificationPolicy` enum. Note that every stream has a list of valid Ethereum addresses that are allowed to publish. Every stream also has a metadata boolean flag set by the creator of the stream that determines whether events on the stream are supposed to be signed or not.\n\nIn the following table, by \"verify\" we mean:\n1) Extract the Ethereum address from the signature and check it's equal to the publisher's address (verify the signature itself)\n2) Check that the set of valid publishers Ethereum addresses contains the publisher's address.\n\nOption value | Description\n:------------ | :-----------\nAUTO | Default value. All signed events are verified. Unsigned events are accepted if and only if the stream does not require signed data according to the metadata boolean flag.\nALWAYS | Only signed and verified events are accepted.\nNEVER | All signed events are verified. Unsigned events are always accepted.\n\n\u003ca name=\"encryption\"\u003e\u003c/a\u003e\n## Encryption\n\nWe first introduce the `GroupKey` class: it defines a symmetric AES-256 group key used by the publisher to encrypt data and by the subscriber to decrypt data. A new, random `GroupKey` can be generated as follows:\n\n```java\nGroupKey groupKey = GroupKey.generate();\n```\n\nThe `GroupKey` can then be passed to the `publish` method to publish end-to-end encrypted messages:\n\n```java\nclient.publish(stream, payload, groupKey);\n```\n\nTo rotate the key, simply generate a new one. This will announce the new key to everyone who has the current key. Rotating the key every now and then establishes forward secrecy: compromised future `GroupKey`s will not reveal previous messages. \n\n```java\ngroupKey = GroupKey.generate(); // Generate new key\nclient.publish(stream, payload, groupKey); // Publish as usual\n```\n\nSubscribers normally obtain the `GroupKey` via an automatic key exchange mechanism, which is triggered if the subscriber receives messages for which they don't have the key. As an alternative, keys can also be pre-shared manually and configured on the client like this:\n\n```\nclient.getKeyStore().add(streamId, new GroupKey(keyId, groupKeyHex));\n```\n\nWe also need a way to revoke subscribers whose subscription has expired. This is accomplished with a rekey, which means that a new group key is chosen by the publisher and sent to the remaining valid subscribers but not to the revoked ones. The rekey is a fairly intensive operation which should be used only when necessary.\n\nThere are two ways to rekey (examples below):\n- By using the automatic built-in revocation mechanism: it periodically checks how many subscribers should be revoked and rekey if the number reaches a threshold (5 subscribers).\n- By explicitly calling the `client.rekey(stream)` method at any time.\n\n```java\n// autoRevoke determines whether the automatic revocation mechanism is to be used or not. \n// In this case, it is deactivated.\nboolean autoRevoke = false; // default is true \nEncryptionOptions encryptionOptions = new EncryptionOptions(autoRevoke);\n\nStreamrClient client = new StreamrClient(new StreamrClientOptions(...)); // passing the encryptionOptions here\n\nGroupKey key = GroupKey.generate()\nclient.publish(Stream, payload, key); // publishing some message with an initial key\n\n// You can trigger a rekey of the stream at any moment to revoke any expired subscribers from the next message.\nkey = client.rekey(Stream);\n\n// Publish with the new key generated during the rekey.\nclient.publish(Stream, payload, key); \n```\n\n\u003ca name=\"other-options\"\u003e\u003c/a\u003e\n## Other options\n\nThe following table describes the other options of the `StreamrClientOptions` constructor and their default values.\n\nOption | Default value | Description\n:------ | :------------- | :-----------\nwebsocketApiUrl | wss://streamr.network/api/v1/ws | Address of the websocket endpoint to connect to.\nrestApiUrl | https://streamr.network/api/v1 | Base URL of the Streamr REST API.\npropagationTimeout | 5 seconds | When a gap between two received events is detected, a resend request is sent periodically until the gap is resolved. This option determines that period. \nresendTimeout | 5 seconds | When subscribing with a resend option (See [this](#subscribing-unsubscribing) section), the messages requested by a first resend request might not be available yet. This option determines after how much time, the resend must be requested a second time.\nskipGapsOnFullQueue | true | Determine behaviour in the case of gap filling failure. Default behaviour (`true`) is to clear the internal queue of messages and start immediately processing new incoming messages. This means that any queued messages are effectively ignored and skipped. If it is more important that messages be processed at the expense of latency, this should be set to `false`. This will mean that in the case of gap filling failure, the next messages (and potential gaps) in the queue will be processed in order. This comes at the expense of the real-time.\n\n\u003ca name=\"handling-errors\"\u003e\u003c/a\u003e\n## Handling Errors\n\nYou can customize error handling by registering an error handler.\n```java\nclient.setErrorMessageHandler({ ErrorResponse error -\u003e\n    // handle error\n})\n```\nIf no error message handler is register then the error is logged.\n\n\u003ca name=\"creating-streams\"\u003e\u003c/a\u003e\n## Creating streams\n\nYou create streams via the `create(Stream)` method, passing in a prototype `Stream` object with fields set as you wish. The method returns the `Stream` object that was actually created.\n\n```java\nStream created = client.createStream(new Stream(\"Stream name\", \"Stream description\"));\n```\n\n\u003ca name=\"looking-up-streams\"\u003e\u003c/a\u003e\n## Looking up streams\n\nYou can look up streams by `id`:\n\n```java\nStream stream = client.getStream(\"id-of-the-stream\");\n```\n\nOr by the name of the stream (expects an unique result):\n\n```java\nStream stream = client.getStreamByName(\"My Fancy Stream\");\n```\n\n\u003ca name=\"publishing\"\u003e\u003c/a\u003e\n## Publishing events to Streams\n\nEvents in Streams are key-value pairs, represented in Java as `Map` objects. Below is an example of creating an event payload and publishing it into a Stream:\n\n```java\n// Create the message payload, which is represented as a Map\n// Each 'Object' in the Map must be serializable to JSON.\nMap\u003cString, Object\u003e msg = new LinkedHashMap\u003c\u003e();\nmsg.put(\"foo\", \"bar\");\nmsg.put(\"random\", Math.random());\n\n// Then publish it!\nclient.publish(stream, msg);\n```\n\nAll events are timestamped. The above example assigns the current timestamp to the new event, but you can also provide a timestamp explicitly:\n\n```java\nclient.publish(stream, msg, new Date());\n```\n\nBy default streams have one partition. For streams with multiple partitions, you can map messages to partitions using a partition key. The same partition key always maps to the same partition:\n```java\nclient.publish(stream, msg, new Date(), \"myPartitionKey\");\n```\n\nThe events can be end-to-end encrypted by passing a `GroupKey` to the `publish` method:\n\n```java\nGroupKey key = GroupKey.generate();\nclient.publish(stream, msg, key);\n\n// You can rotate the key at any time\nGroupKey newKey = GroupKey.generate();\nclient.publish(stream, msg2, newKey); // message is encrypted with newKey instead of key\n```\n\n\u003ca name=\"subscribing-unsubscribing\"\u003e\u003c/a\u003e\n## Subscribing and unsubscribing to streams\n\nBy subscribing to streams, your application gets immediately notified about new events in the stream. You provide a `MessageHandler` which gets called with new events.\n\n```java\nSubscription sub = client.subscribe(stream, new MessageHandler() {\n    @Override\n    public void onMessage(Subscription s, StreamMessage message) {\n        // Here you can react to the latest message\n        System.out.println(message.getParsedContent().toString());\n    }\n});\n```\n\nYou can also choose other options such as a specific partition to subscribe to (for load balancing high-volume, partitioned streams), or specify a resend option:\n\n```java\nint partition = 0;\nMessageHandler handler = ...\nResendOption resendOption = ...\nSubscription sub = client.subscribe(stream, partition, handler, resendOption);\n```\n\nBelow are examples of ways to construct the `ResendOption`.\n\n```java\n// Resends the last 10 events\nResendOption opt = new ResendLastOption(10);\n```\n\n```java\n// Resends the events from a specific timestamp (and sequence number) for a particular message chain of a publisher\nDate from = new Date(341298709);\nint sequenceNumber = 0;\nResendOption opt = new ResendFromOption(from, sequenceNumber, \"publisherId\", \"msgChainId\");\n```\n\n```java\n// Resends the events between two timestamps for a particular message chain of a publisher\nDate from = new Date(341298709);\nDate to = new Date(341299000);\n// the 0s are sequence numbers\nResendOption opt = new ResendRangeOption(from, 0, to, 0, \"publisherId\", \"msgChainId\");\n```\n\nTo stop receiving events from a stream, pass the `Subscription` object you got when subscribing to the `unsubscribe` method:\n\n```java\nclient.unsubscribe(sub);\n```\n\n\u003ca name=\"data-unions\"\u003e\u003c/a\u003e\n## Data Unions\nThis library provides functions for working with [Data Unions](https://github.com/streamr-dev/data-union-solidity). The Data Union is a system of efficient revenue splitting contracts that have components on the mainnet and a sidechain. Please see the Data Unions [README](https://github.com/streamr-dev/data-union-solidity) for more details. The mainnet contract is basically a conduit to the sidechain contract, which handles member addition and removal, does accounting, and stores tokens.\n\nTo get a Data Union client instance, call:\n\n`client.dataUnionClient(mainnetPrivateKey, sideChainPrivateKey)`\n\nThe client can be used to deploy and connect to existing DataUnions. `mainnetPrivateKey` and `sideChainPrivateKey` are the keys that will be used to sign transactions in this sessions.\n\nTo deploy a new Data Union, call:\n\n`dataUnionClient.deployDataUnion(name, adminAddress, adminFeeFraction, agents)`\n\nNote that the **deployed address is a function of name + mainnetKey**.\n\nTo get an existing instance of Data Union, call:\n\n`dataUnionFromMainnetAddress(mainnetAddress)` or `dataUnionClient.dataUnionFromName(name)`\n\n### Functions that trigger mainnet transactions (possibly expensive)\n| Name          | Returns  | Description |\n| :------------ | :------ | :----------- |\n| DataUnionClient.deployDataUnion() | DataUnion | deploy new DU |\n| DataUnionClient.portTxsToMainnet(txHash, prvKey) | `List\u003cTransactionReceipt\u003e` | takes a sidechain TX as input, and ports all triggered bridge TXs to mainnet |\n| DataUnion.sendTokensToBridge() | TransactionReceipt | sends tokens stored in mainnet DU to sidechain DU |\n| DataUnion.setAdminFeeFraction(fraction) | TransactionReceipt | sets the fraction that will be kept by admin (admin-only function) |\n\n\n### Functions that trigger sidechain transactions (cheap)\n| Name          | Returns  | Description |\n| :------------ | :------ | :----------- |\n| addMembers(String ...members) | TransactionReceipt | Add members |\n| partMembers(String ...members) | TransactionReceipt | Remove members from Data Union |\n| withdrawTokensForSelfOrAsAdmin(String memberAddress, BigInteger amount, boolean sendWithdrawToMainnet) | TransactionReceipt | Withdraw members tokens to given address |\n| withdrawTokensForMember(BigInteger privateKey, String to, BigInteger amount, boolean sendWithdrawToMainnet) | TransactionReceipt | Withdraw members tokens |\n\nAdding members using admin functions is not at feature parity with the member function `join`. The newly added member will not be granted publish permissions to the streams inside the Data Union. This will need to be done manually using, `streamr.grantPermission(stream_publish, user)`. Similarly, after removing a member using the admin function `removeMembers`, the publish permissions will need to be removed in a secondary step using `revokePermission(permissionId)`.\n\nWhen withdrawing, you can choose to send tokens to sidechain or mainnet with the `sendWithdrawToMainnet` boolean. If you withdraw to mainnet, you must **port** the resulting TransactionReceipt across the bridge with `DataUnionClient.portTxsToMainnet(sidechainTxReceipt, prvKey)`, which costs ETH. If you keep tokens on sidechain, you can use the [xDai bridge](https://omni.xdaichain.com/) to transfer them to mainnet at a later time.\n\n\n### Read-only functions (free)\n| Name          | Returns  | Description |\n| :------------ | :------ | :----------- |\n| isDeployed() | boolean | Check if Data Union deployment has completed |\n| getWithdrawableEarnings(member) | BigInteger | get member's earnings |\n| isMemberActive(String memberAddress)         | boolean  | true if member is active |\n| isMemberInactive(String memberAddress)       | boolean  | true if member was removed |\n| totalEarnings() | BigInteger |  |\n| totalEarningsWithdrawn() | BigInteger |  |\n| activeMemberCount() | BigInteger |  |\n| inactiveMemberCount() | BigInteger |  |\n| lifetimeMemberEarnings() | BigInteger |  |\n| joinPartAgentCount() | BigInteger |  |\n| getAdminFeeFraction() | BigInteger | fee fraction expressed in wei (ie 10^18 means 1) |\n| getEarnings(String member) | BigInteger |  |\n| getWithdrawn(String member) | BigInteger |  |\n| getWithdrawableEarnings(String member) | BigInteger |  |\n\n\n### Code Examples\n\nDeploy a data union contract and set the admin fee:\n\n```java\nDataUnionClient dataUnionClient = new StreamrClient(new StreamrClientOptions()).dataUnionClient(\"mainnetAdminPrvKey\", \"sidechainAdminPrvKey\");\n// 2% of mainnet revenue will go to admin fee\ndouble adminFeeFraction = 0.02;\nList\u003cString\u003e agents = Arrays.asList(\"0x\u003caddress of agent\u003e\");\nDataUnion dataUnion = dataUnionClient.deployDataUnion(\"Cool Data Union\", adminAddress, adminFeeFraction, agents);\n```\n\nWithdraw for another (ie withdrawer key signs TX, DataUnionClient key pays for it) :\n\n```java\nBigInteger withdrawerPrivateKey = new BigInteger(\"0x...\");\nString to = \"0x....\";\nEthereumTransactionReceipt receipt = dataUnion.withdrawAllTokensForMember(withdrawerPrivateKey, to)\n```\nsee also `DataUnion.createWithdrawRequest`, which creates the withdrawl request that the above code signs. The above method creates and signs the request, but the signature can be created by withdrawer separately.\n\nHere's an example on how to get a member's withdrawable token balance (in \"wei\", where 1 DATA = 10^18 wei)\n\n```java\nBigInteger withdrawable = dataUnion.getEarnings(member);\n```\n\n## Contributions\n\nThis library is officially developed and maintained by the Streamr core dev team, but community contributions are very welcome!\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstreamr-dev%2Fstreamr-client-java","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstreamr-dev%2Fstreamr-client-java","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstreamr-dev%2Fstreamr-client-java/lists"}