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:
RecordRecordFieldValue.
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::getListandValueOuterClass.List::getElementsListto unwrap theValueinto aList<Value>. - Unwrap each
Valuein the list viaValue::getRecordto get aList<Record> - Extract each record’s two fields using
Record::getFieldsto getList<Pair<RecordField, RecordField>> - Extract the values from
RecordFieldswithRecordFields::getValue, givingList<Pair<Value, Value>> - Extract the
Int64, which is an alias forlong, andStringfrom theValueobjects 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 Records:
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