After this important discussion I've ended with a functional solution which I am sharing here with whoever might find useful. This code is in Java. Details of it might be found on TezosJ_plainJava github repository.
The method "solvePair" transforms recursively a "Pair" of parameters into the expected JSON/Pairs format that is needed to be passed to Tezos smart contracts entrypoints, making it easy for developers to interact with Tezos blockchain.
Example:
INPUT:
Pair : (([1000000],[2000000,003]),([001],[005,002]))
Datatypes : [ "int", "int", "String", "String", "String", "String" ]
OUTPUT:
{ "prim": "Pair", "args": [ { "prim": "Pair", "args": [ { "int": "1000000" }, { "prim": "Pair", "args": [ { "int": "2000000" }, { "string": "003" } ] } ] }, { "prim": "Pair", "args": [ { "string": "001" }, { "prim": "Pair", "args": [ { "string": "005" }, { "string": "002" } ] } ] } ] }
Here are the routines:
private Object solvePair(Object pair, List datatypes) throws Exception
{
Object result = null;
// Extract and check contents.
if (hasPairs((Pair) pair) == false)
{
// Here we've got List in both sides. But they might have more than one element.
Object jsonLeft = ((Pair) pair).getLeft() == null ? null : toJsonFormat((List)((Pair) pair).getLeft(), datatypes, 0);
Object jsonRight = ((Pair) pair).getRight() == null ? null : toJsonFormat((List)((Pair) pair).getRight(), datatypes, ((Pair) pair).getLeft() == null ? 0 : ((List)((Pair) pair).getLeft()).size() );
// Test if there is only one parameter.
if (jsonLeft == null)
if (jsonRight == null)
throw new Exception("Pair cannot be (null, null)");
else
return jsonRight;
else if (jsonRight == null)
return jsonLeft;
// Build json outter pair.
JSONObject jsonPair = new JSONObject();
jsonPair.put("prim", "Pair");
// Create pair contents array.
JSONArray pairContents = new JSONArray();
pairContents.put(jsonLeft);
pairContents.put(jsonRight);
jsonPair.put("args", pairContents);
return jsonPair;
}
else
{
Object jsonLeft = solvePair(((Pair<Pair, List>) pair).getLeft(), datatypes);
Object jsonRight = solvePair(((Pair<Pair, List>) pair).getRight(), datatypes.subList( countPairElements((Pair) ((Pair) pair).getLeft()), datatypes.size()) );
// Build json outter pair.
JSONObject jsonPair = new JSONObject();
jsonPair.put("prim", "Pair");
// Create pair contents array.
JSONArray pairContents = new JSONArray();
pairContents.put(jsonLeft);
pairContents.put(jsonRight);
jsonPair.put("args", pairContents);
return jsonPair;
}
}
private Integer countPairElements(Pair pair)
{
Integer leftCount = 0;
Integer rightCount = 0;
Object left = pair.getLeft();
Object right = pair.getRight();
if(left instanceof Pair)
{
leftCount = countPairElements((Pair) left);
}
else
{
leftCount = ((List)left).size();
}
if(right instanceof Pair)
{
rightCount = countPairElements((Pair) right);
}
else
{
rightCount = ((List)right).size();
}
return leftCount+rightCount;
}
private Boolean hasPairs(Pair pair)
{
Object left = pair.getLeft();
Object right = pair.getRight();
if( (left instanceof Pair) || (right instanceof Pair) )
{
return true;
}
else
{
return false;
}
}
private JSONObject toJsonFormat(List list, List datatypes, Integer firstElement)
{
JSONArray result = new JSONArray();
for(int i=0;i<list.size();i++)
{
JSONObject element = new JSONObject();
element.put((String) datatypes.get(firstElement + i), list.get(i));
// Add element to array.
result.put(element);
}
if (result.length() > 1)
{
// Wrap json result in outter pair.
JSONObject jsonPair = new JSONObject();
jsonPair.put("prim", "Pair");
jsonPair.put("args", result);
return jsonPair;
}
else
{
return (JSONObject)result.get(0);
}
}
And if you wish to build a Pair object from a String[] parameter array, you might use the routine below.
INPUT: empty JSONObject, empty Pair, List of your parameters values (like String[] {"param1", "param2", "param3"} ).
OUTPUT: (param1,(param2,param3))
private Pair buildParameterPairs(JSONObject jsonObj, Pair pair, List<String> parameters,
String[] contractEntryPointParameters,
Boolean doSolveLeft) throws Exception
{
// Test parameters validity.
if (parameters.isEmpty())
{
throw new Exception("Missing parameters to pass to contract entrypoint");
}
List<String> left = new ArrayList<String>();
List<String> right = new ArrayList<String>();
Pair newPair = null;
if(parameters.size() == 1)
{
// If number of parameters is only 1.
newPair = new MutablePair<>(null, new ArrayList<String>(Arrays.asList(parameters.get(0))));
}
else
{
if (pair == null)
{
Integer half = ( Math.abs(parameters.size() / 2) );
left = parameters.subList(0, half);
right = parameters.subList(half, parameters.size());
newPair = new MutablePair<>(left, right);
}
else
{
List<String> newList;
if (doSolveLeft == true)
{
newList = ((List<String>) pair.getLeft());
}
else
{
newList = ((List<String>) pair.getRight());
}
Integer half = ( Math.abs( newList.size() / 2) );
left = newList.subList(0, half);
right = newList.subList(half, newList.size());
newPair = new MutablePair<>(left, right);
}
if ( (((List)newPair.getRight()).size() > 2) || (((List)newPair.getLeft()).size() > 2) )
{
newPair = new MutablePair<>(buildParameterPairs(jsonObj, newPair, parameters, contractEntryPointParameters, true),
buildParameterPairs(jsonObj, newPair, parameters, contractEntryPointParameters, false));
}
else
{
return newPair;
}
}
return newPair;
}