3

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?

Ramón J Romero y Vigil
  • 17,373
  • 7
  • 77
  • 125
Neil Mitchell
  • 9,090
  • 1
  • 27
  • 85

2 Answers2

7

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:

  1. Use Value::getList and ValueOuterClass.List::getElementsList to unwrap the Value into a List<Value>.
  2. Unwrap each Value in the list via Value::getRecord to get a List<Record>
  3. Extract each record’s two fields using Record::getFields to get List<Pair<RecordField, RecordField>>
  4. Extract the values from RecordFields with RecordFields::getValue, giving List<Pair<Value, Value>>
  5. Extract the Int64, which is an alias for long, and String from the Value objects to get the final List<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());
    }
}
Gerolf Seitz
  • 121
  • 4
5

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());
}
Dimitri L.
  • 86
  • 1