use of com.linkedin.restli.internal.common.PathSegment.ListMap in project rest.li by linkedin.
the class QueryParamsDataMap method parseDataMapKeys.
/**
* Parse a multi-map representing query parameters into a DataMap, as follows.
*
* Multi-indexed parameter names, such as ids[0][2] or ids[0,2] are not
* currently supported.
*
* For example, the following query string:
*
* /groupMemberships?ids[0].params.versionTag=tag1&ids[0].params.authToken=tok1&ids[0].memberID=1&ids[0].groupID=2& \
* ids[1].params.versionTag=tag2&ids[1].params.authToken=tok2&ids[1].memberID=2&ids[1].groupID=2& \
* q=someFinder
*
* is parsed into the following data map:
*
* {"ids" : [
* {
* "memberID" : "1",
* "groupID" : "2",
* "params" : {
* "authToken" : "tok1",
* "versionTag" : "tag1"
* }
* },
* { "memberID" : "2",
* "groupID" : "2",
* "params" : {
* "authToken" : "tok2",
* "versionTag" : "tag2"
* }
* }
* ],
* "q" : "someFinder"
* }
*
*
* Note: at this point the data map is not typed - all names and values are
* parsed as strings.
*
* Note: when parsing indexed parameter names, those will be converted to a list,
* preserving the order of the values according to the index, but ignoring any
* possible "holes" in the index sequence. The index values therefore only
* serve to define order of the parameter values, rather than their actual
* position in any collection.
*
* @param queryParameters the query parameters
* @return - the DataMap represented by potentially hierarchical keys encoded
* by the multi-part parameter names.
*
* @throws PathSegmentSyntaxException
*/
public static DataMap parseDataMapKeys(Map<String, List<String>> queryParameters) throws PathSegmentSyntaxException {
// The parameters are parsed into an intermediary structure comprised of
// HashMap<String,Object> and HashMap<Integer,Object>, defined respectively
// as MapMap and ListMap for convenience. This is done for two reasons:
// - first, indexed keys representing lists are parsed into ListMaps keyed on
// index values, since the indices may come in any order in the query parameter,
// while we want to preserve the order.
// - second, DataMap only accepts Data objects as values, so ListMaps cannot
// be stored there, so using an intermediary structure even for maps.
MapMap dataMap = new MapMap();
for (Map.Entry<String, List<String>> entry : queryParameters.entrySet()) {
// As per the notation above, we no longer support multiple occurrences of
// a parameter (considering its full multi-part and indexed name), i.e
// there should be only a single entry in each list. For backward compatibility
// as well as ease of use, repeated parameters are still allowed if they
// are "simple", i.e. they are not multi-part or indexed.
List<String> valueList = entry.getValue();
if (valueList.size() == 1) {
String[] key = SEGMENT_DELIMITER_PATTERN.split(entry.getKey());
parseParameter(key, valueList.get(0), dataMap);
} else {
String parameterName = entry.getKey();
// indexed and then simulate the index for each one.
if (parameterName.indexOf('.') != -1)
throw new PathSegmentSyntaxException("Multiple values of complex query parameter are not supported");
if (parameterName.charAt(parameterName.length() - 1) == ']')
throw new PathSegmentSyntaxException("Multiple values of indexed query parameter are not supported");
if (dataMap.containsKey(parameterName))
throw new PathSegmentSyntaxException("Conflicting references to key " + parameterName + "[0]");
else {
dataMap.put(parameterName, new DataList(valueList));
}
}
}
return (DataMap) convertToDataCollection(dataMap);
}
use of com.linkedin.restli.internal.common.PathSegment.ListMap in project rest.li by linkedin.
the class QueryParamsDataMap method convertToDataCollection.
/**
* The method recursively traverses the input Map and transforms it as follows:
* - wherever encounters instances of ListMap (Map<Integer,Object>), converts
* those to DataList, preserving key order but ignoring any "holes" in key sequences.
* - wherever encounters instances of MapMap (Map<String,Object>) converts them
* into DataMap.
*
* This is done since while parsing out indexed query parameters it's convenient to
* parse them into a map due to arbitrary order in which they may appear, while if they
* are defined in the schema as a list, a DataList is expected during validation.
*
* @param map the Map to transform
* @return DataMap or DataList, depending on the type of the input Map
*/
private static DataComplex convertToDataCollection(Map<?, ?> map) {
// recursively on every value that is itself a map
if (map instanceof MapMap) {
DataMap result = new DataMap();
MapMap mapMap = (MapMap) map;
for (Entry<String, Object> entry : mapMap.entrySet()) {
Object value = entry.getValue();
if (value instanceof Map<?, ?>)
value = convertToDataCollection((Map<?, ?>) value);
result.put(entry.getKey(), value);
}
return result;
}
// convert this map into a list preserving key order.
if (map instanceof ListMap) {
DataList result = new DataList();
ListMap listMap = (ListMap) map;
List<Integer> sortedKeys = new ArrayList<Integer>(listMap.keySet());
Collections.sort(sortedKeys);
for (Integer key : sortedKeys) {
Object object = map.get(key);
if (object instanceof Map<?, ?>)
object = convertToDataCollection((Map<?, ?>) object);
result.add(object);
}
return result;
}
throw new IllegalArgumentException("Only MapMap or ListMap input argument types are allowed");
}
Aggregations