Skip to content

Stellar Basics guides to use RPC - Java examples #1533

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
anataliocs opened this issue May 6, 2025 · 1 comment
Open

Stellar Basics guides to use RPC - Java examples #1533

anataliocs opened this issue May 6, 2025 · 1 comment
Assignees
Labels
dev-rel documentation Improvements or additions to documentation

Comments

@anataliocs
Copy link
Contributor

anataliocs commented May 6, 2025

What problem does your feature solve?

We'd like to encourage use of RPC over Horizon, but all of our intro content is centered around Horizon's API

What would you like to see?

The guides in https://developers.stellar.org/docs/build/guides/basics can all do the same series of steps, but against RPC's API instead of Horizon's

What alternatives are there?

@anataliocs anataliocs self-assigned this May 6, 2025
@anataliocs anataliocs moved this to In Progress in Dev Docs May 7, 2025
@anataliocs
Copy link
Contributor Author

anataliocs commented May 7, 2025

@mollykarcher So I was a backend Java dev before pivoting to Web3 so I'm tackling the updates to the Java examples in the docs you are looking for.

Here's an example of the current code samples for reference:

import org.stellar.sdk.Server;
import org.stellar.sdk.responses.AccountResponse;

Server server = new Server("https://horizon-testnet.stellar.org");
AccountResponse account = server.accounts().account(pair.getAccountId());
System.out.println("Balances for account " + pair.getAccountId());
for (AccountResponse.Balance balance : account.getBalances()) {
  System.out.printf(
    "Type: %s, Code: %s, Balance: %s%n",
    balance.getAssetType(),
    balance.getAssetCode(),
    balance.getBalance()
  );

I'm seeing several issues here in addition to migrating away from the Horizon Server:

  • A lot of the Java examples use non-async, blocking code
  • The syntax being used is pretty "old-fashioned" I think a more functional, streams based style will resonate more with our dev audience
  • The lack of concurrency and things like completable futures and composition leads to a lot of boilerplate such as polling for transaction status

With that in mind I created this reference repo using the Stellar Java SDK https://github.com/anataliocs/stellar-java-rpc to test and verify my code samples before committing them.

I wanted to ask you what you think of providing more modern coding style, using CompletableFutures and using handlers and composition for async functionality.

Here's an example:

	/**
	 * Creates generic handlers for wrapping `SorobanServer` rpc calls in an async wrapper.
	 *
	 * @param rpcCallFunction A lambda or method reference that defines the rpc call to execute.
	 * @param <ResponseType>  Generic representing the return type
	 * @return ResponseType
	 */
	@Async("rpcTaskExecutor")
	default <ResponseType> CompletableFuture<ResponseType> asyncRpcCall(
			RpcLambda<Supplier<SorobanServer>, ResponseType> rpcCallFunction) {

		return supplyAsync(() -> rpcCallFunction.makeRpcCall(getSorobanServer()))
				.completeOnTimeout(null, 30, SECONDS)
				.exceptionallyCompose(StellarRpcService::exceptionHandler);
	}

	@FunctionalInterface
	interface RpcLambda<Server extends Supplier<SorobanServer>, ResponseType> {
		ResponseType makeRpcCall(Server server);
	}

So I just wanted to get a gut check if this style is the right level for our audience looking at Java samples. I can also reduce the level of abstraction and simplify.

You can find the full source code(Spring Boot/Java LTS 21/Stellar SDK) in the repo above.

Overview:

  • asyncRpcCall() is a utility function that takes in a lambda such as rpcServer -> rpcServer.get().sendTransaction(transaction) and wraps a RPC call in a CompletableFuture and adds some error handling

  • The RpcLambda Functional Interface defines the lambda(or static method ref) that is passed into the asyncRpcCall wrapper function

  • Then you can see here how the asyncRpcCall wrapper function is used in this next code block. A SendTransaction rpc call is wrapped in a CompletableFuture then a handler is attached(That can do filtering, transformation etc) then that future is composed with a GetTransaction rpc call with a delayedExecutor to allow for transaction processing

	@Override
	public CompletableFuture<GetTransactionResponse> getTransaction(SendTransactionResponse transactionResponse) {
		return asyncRpcCall(rpcServer ->
				rpcServer.get().getTransaction(transactionResponse.getHash()));
	}

	asyncRpcCall(rpcServer -> rpcServer.get().sendTransaction(transaction))
			.thenApplyAsync(StellarRpcServiceImpl::accountCreationHandler)
			.thenComposeAsync(this::getTransaction, delayedExecutor(10, TimeUnit.SECONDS))
			.join();

To me this is a lot cleaner then an infinite while loop polling a endpoint but I also don't want readers to get lost b/c I used to many abstractions.

Just wanted to get your opinion on what you want Java code samples to look like @mollykarcher ! Let me know if we should loop in anyone else like from the Anchor or Lightsail team. Thanks!!!

@anataliocs anataliocs added documentation Improvements or additions to documentation dev-rel labels May 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dev-rel documentation Improvements or additions to documentation
Projects
Status: In Progress
Development

No branches or pull requests

1 participant