I have written a DAML model that generates a list of tuples, e.g. [(Int, Text)]
. I receive this data via the DA Ledger API - how do I convert it to List<Pair<Long, String>>
in Java?

- 17,373
- 7
- 77
- 125

- 9,090
- 1
- 27
- 85
2 Answers
The Java depends on whether you are working with the raw compiled Protobuf types, or the wrapped types provided by the Java Language Bindings.
Objects returned by the API are represented using three major types:
Record
RecordField
Value
.
Simplifying somewhat, aRecord
is a list of RecordField
, a RecordField
is a label and a Value
and a Value
can be one of many things, including an Int64
, a String
, a Record
, or a List
. Tuples like (Int, Text)
have special notation in DAML, but are represented as normal Record
objects in the API.
Assuming you are using the types compiled from the protobuf definitions, and have got your hands on a com.digitalasset.ledger.api.v1.ValueOuterClass.Value
representing the [(Int, Text)]
, you need to do the following:
- Use
Value::getList
andValueOuterClass.List::getElementsList
to unwrap theValue
into aList<Value>
. - Unwrap each
Value
in the list viaValue::getRecord
to get aList<Record>
- Extract each record’s two fields using
Record::getFields
to getList<Pair<RecordField, RecordField>>
- Extract the values from
RecordFields
withRecordFields::getValue
, givingList<Pair<Value, Value>>
- Extract the
Int64
, which is an alias forlong
, andString
from theValue
objects to get the finalList<Pair<Long, String>>
Steps 2. - 4. can be accomplished neatly using Java’s streaming interface. The code shown is for the raw gRPC types, starting from a com.digitalasset.ledger.api.v1.ValueOuterClass.Value
:
import com.digitalasset.ledger.api.v1.ValueOuterClass;
import static java.util.AbstractMap.SimpleImmutableEntry;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
public class Demo {
static SimpleImmutableEntry<ValueOuterClass.RecordField, ValueOuterClass.RecordField> EntryFromTuple(ValueOuterClass.Record tupleRecord) {
return new SimpleImmutableEntry<>(tupleRecord.getFields(0), tupleRecord.getFields(1));
}
static class SimpleImmutableEntryMap<S, T, U, V> implements Function<SimpleImmutableEntry<S, T>, SimpleImmutableEntry<U, V>> {
Function<S, U> mapFst;
Function<T, V> mapSnd;
public SimpleImmutableEntryMap(Function<S, U> mapFst, Function<T, V> mapSnd) {
this.mapFst = mapFst;
this.mapSnd = mapSnd;
}
@Override
public SimpleImmutableEntry<U, V> apply(SimpleImmutableEntry<S, T> stEntry) {
return new SimpleImmutableEntry<> (mapFst.apply(stEntry.getKey()), mapSnd.apply(stEntry.getValue()));
}
}
static List<SimpleImmutableEntry<Long, String>> mapTuple(ValueOuterClass.Value v) {
return v.getList().getElementsList().stream()
.map(ValueOuterClass.Value::getRecord)
.map(Demo::EntryFromTuple)
.map(new SimpleImmutableEntryMap<>(ValueOuterClass.RecordField::getValue, ValueOuterClass.RecordField::getValue))
.map(new SimpleImmutableEntryMap<>(ValueOuterClass.Value::getInt64, ValueOuterClass.Value::getText))
.collect(Collectors.toList());
}
}

- 121
- 4
Assuming that you have the following daml template:
template ListOfTuples
with
party : Party
listOfTuples : [(Int, Text)]
where
signatory party
that has been transformed to a com.daml.ledger.javaapi.data.Record
with the java api, you can convert it to a List<Pair<Long, String>>
by treating the tuples in the list also as Record
s:
import java.util.List;
import javafx.util.Pair;
import java.util.stream.Collectors;
import com.daml.ledger.javaapi.data.Record;
public void parseListOfTuples(Record record) {
List<Pair<Long, String>> listOfTuples =
record.getFields().get(1).getValue().asList().get().getValues().stream()
.map(t -> {
List<Record.Field> tuple = t.asRecord().get().getFields();
return new Pair<>(
tuple.get(0).getValue().asInt64().get().getValue(),
tuple.get(1).getValue().asText().get().getValue());
})
.collect(Collectors.toList());
}

- 86
- 1