- Overview
- Tutorials
- Getting started
- Get started with Canton and the JSON Ledger API
- Get Started with Canton, the JSON Ledger API, TypeScript and WebSockets
- Get Started with Canton, the JSON Ledger API, and TypeScript
- Get started with Canton Network App Dev Quickstart
- Using the JSON Ledger API
- Get started with smart contract development
- Basic contracts
- Test templates using Daml scripts
- Build the Daml Archive (.dar) file
- Data types
- Transform contracts using choices
- Add constraints to a contract
- Parties and authority
- Compose choices
- Handle exceptions
- Work with dependencies
- Functional programming 101
- The Daml standard library
- Test Daml contracts
- Next steps
- Application development
- Getting started
- Development how-tos
- Component how-tos
- Explanations
- References
- Application development
- Smart contract development
- Daml language cheat sheet
- Daml language reference
- Overview: Template Structure
- Reference: Templates
- Reference: Choices
- Reference: Updates
- Reference: Data Types
- Reference: Built-in Functions
- Reference: Expressions
- Reference: Functions
- Reference: Daml File Structure
- Reference: Daml Packages
- Reference: Contract Keys
- Reference: Interfaces
- Reference: Exceptions (Deprecated)
- Fixity, Associativity and Precedence
- Daml standard library
- DA.Action.State.Class
- DA.Action.State
- DA.Action
- DA.Assert
- DA.Bifunctor
- DA.Crypto.Text
- DA.Date
- DA.Either
- DA.Exception
- DA.Fail
- DA.Foldable
- DA.Functor
- DA.Internal.Interface.AnyView.Types
- DA.Internal.Interface.AnyView
- DA.List.BuiltinOrder
- DA.List.Total
- DA.List
- DA.Logic
- DA.Map
- DA.Math
- DA.Monoid
- DA.NonEmpty.Types
- DA.NonEmpty
- DA.Numeric
- DA.Optional
- DA.Record
- DA.Semigroup
- DA.Set
- DA.Stack
- DA.Text
- DA.TextMap
- DA.Time
- DA.Traversable
- DA.Tuple
- DA.Validation
- GHC.Show.Text
- GHC.Tuple.Check
- Prelude
- Daml Script
- Smart contract upgrading reference
- Glossary of concepts
How to work with contracts and transactions in Java¶
When writing Canton Network applications in Java, it is convenient to work with a representation of Daml templates and data types in Java that closely resemble the original Daml code while still being as close to the native types of Java as possible. To achieve this, use the Daml Codegen for Java to generate Java types based on a Daml model. You can then use these types in your Java code when reading information from and sending data to the ledger.
Setup the codegen¶
Run and configure the code generator for Java according to Daml Codegen for Java to use and generate the Java classes for your project.
See also in Generated code how the generated code looks for the Daml built-in and user-defined types.
Use the generated classes in your project¶
In order to compile the resulting Java classes, you need to add the Java bindings library as dependency to your build tools.
Add the following Maven dependency to your project:
<dependency>
<groupId>com.daml</groupId>
<artifactId>bindings-java</artifactId>
<version>YOUR_SDK_VERSION</version>
</dependency>
Note
Replace YOUR_SDK_VERSION with the version of your SDK.
Find the available versions in the Maven Central Repository.
Access the gRPC Ledger API using Java bindings¶
The bindings-java library comes pre-packaged with the generated gRPC stubs allowing you to access the Ledger API.
For each Ledger API service, there is a dedicated Java class with a matching name. For instance, the gRPC
counterpart of CommandSubmissionService is CommandSubmissionServiceGrpc.
Connect to the ledger¶
To establish a connection to the ledger and access the Ledger API services create an instance of a ManagedChannel
using the static NettyChannelBuilder.forAddress(..) method. Then, call the factory method on the respective service
to create a stub e.g. CommandSubmissionServiceGrpc.newFutureStub. Use one of the helper classes provided by the
bindings-java to create an object representing the request service request arguments, convert them to a proto message.
Finally, call the desired method offered by the service.
// Create a managed channel object pointing to the Ledger API address.
ManagedChannel channel = NettyChannelBuilder.forAddress(host, port).usePlaintext().build();
// Create a stub connecting to the desired service on the ledger.
CommandSubmissionServiceFutureStub submissionService = CommandSubmissionServiceGrpc.newFutureStub(channel);
// Create an object representing the service call arguments
CommandsSubmission commandsSubmission = CommandsSubmission.create(...);
// Convert the command submission to a proto data structure
final var request = SubmitRequest.toProto(commandsSubmission);
// Issue the service call
final var response = submissionService.submit(request)
Connect securely¶
The builders created by NettyChannelBuilder.forAddress default to a tls connection, where the keys are taken from
the configured Java Keystore. You can override this behavior by providing your own cryptographic settings. To do so,
invoke sslContext and pass an SslContext.
NettyChannelBuilder.forAddress(host, port)
.useTransportSecurity()
.sslContext(sslContext)
.build();
Warning
You can also configure a plaintext connection invoking usePlaintext(). Use it only when connecting to a locally
running ledger for development purposes.
Secure connections to a ledger must be configured to use client authentication certificates, which can be provided by a ledger operator.
For information on how to set up an SslContext with the provided certificates for client authentication, please consult the gRPC documentation on
TLS with OpenSSL as well as the
HelloWorldClientTls example of the grpc-java project.
Use asynchronous stubs¶
The classes generated for the Ledger API gRPC services come in several flavors: blocking, future-based and asynchronous.
The latter is the recommended way of interacting with the gRPC layer. In the example of the CommandService utilized
above they are called CommandServiceBlockingStub, CommandServiceFutureStub and CommandServiceStub respectively.
For each gRPC endpoint that you want to call from your Java application, create a gRPC StreamObserver providing
implementations of the onNext, onError and onComplete observer methods.
To decode and encode the gRPC messages, use the fromProto and toProto methods of the generated classes of the Java
bindings library.
Use OpenAPI definitions¶
The OpenAPI definitions provide a definition for each Ledger API service and allows you to access it via the JSON Ledger API. Use those definitions to encode/decode the gRPC messages as/from JSON payloads required by the JSON Ledger API. For more details see Get started with Canton and the JSON Ledger API.