use of com.linkedin.data.DataList in project rest.li by linkedin.
the class CollectionResponseBuilder method buildResponse.
@Override
public PartialRestResponse buildResponse(RoutingResult routingResult, RestLiResponseData responseData) {
CollectionResponseEnvelope response = responseData.getCollectionResponseEnvelope();
PartialRestResponse.Builder builder = new PartialRestResponse.Builder();
CollectionResponse<AnyRecord> collectionResponse = new CollectionResponse<AnyRecord>(AnyRecord.class);
collectionResponse.setPaging(response.getCollectionResponsePaging());
DataList elementsMap = (DataList) collectionResponse.data().get(CollectionResponse.ELEMENTS);
for (RecordTemplate entry : response.getCollectionResponse()) {
CheckedUtil.addWithoutChecking(elementsMap, entry.data());
}
if (response.getCollectionResponseCustomMetadata() != null) {
collectionResponse.setMetadataRaw(response.getCollectionResponseCustomMetadata().data());
}
builder.entity(collectionResponse);
return builder.headers(responseData.getHeaders()).cookies(responseData.getCookies()).build();
}
use of com.linkedin.data.DataList in project rest.li by linkedin.
the class ArgumentBuilder method buildDataTemplateArgument.
private static DataTemplate<?> buildDataTemplateArgument(final ResourceContext context, final Parameter<?> param) {
Object paramValue = context.getStructuredParameter(param.getName());
DataTemplate<?> paramRecordTemplate;
if (paramValue == null) {
return null;
} else {
@SuppressWarnings("unchecked") final Class<? extends RecordTemplate> paramType = (Class<? extends RecordTemplate>) param.getType();
/**
* It is possible for the paramValue provided by ResourceContext to be coerced to the wrong type.
* If a query param is a single value param for example www.domain.com/resource?foo=1.
* Then ResourceContext will parse foo as a String with value = 1.
* However if a query param contains many values for example www.domain.com/resource?foo=1&foo=2&foo=3
* Then ResourceContext will parse foo as an DataList with value [1,2,3]
*
* So this means if the 'final' type of a query param is an Array and the paramValue we received from
* ResourceContext is not a DataList we will have to wrap the paramValue inside a DataList
*/
if (AbstractArrayTemplate.class.isAssignableFrom(paramType) && paramValue.getClass() != DataList.class) {
paramRecordTemplate = DataTemplateUtil.wrap(new DataList(Arrays.asList(paramValue)), paramType);
} else {
paramRecordTemplate = DataTemplateUtil.wrap(paramValue, paramType);
}
// Validate against the class schema with FixupMode.STRING_TO_PRIMITIVE to parse the
// strings into the corresponding primitive types.
ValidateDataAgainstSchema.validate(paramRecordTemplate.data(), paramRecordTemplate.schema(), new ValidationOptions(RequiredMode.CAN_BE_ABSENT_IF_HAS_DEFAULT, CoercionMode.STRING_TO_PRIMITIVE));
return paramRecordTemplate;
}
}
use of com.linkedin.data.DataList in project rest.li by linkedin.
the class AbstractDefaultDataTranslator method translate.
protected Object translate(List<Object> path, Object value, DataSchema dataSchema) {
dataSchema = dataSchema.getDereferencedDataSchema();
DataSchema.Type type = dataSchema.getType();
Object result;
switch(type) {
case NULL:
if (value != Data.NULL) {
throw new IllegalArgumentException(message(path, "value must be null for null schema"));
}
result = value;
break;
case BOOLEAN:
result = ((Boolean) value).booleanValue();
break;
case INT:
result = ((Number) value).intValue();
break;
case LONG:
result = ((Number) value).longValue();
break;
case FLOAT:
result = ((Number) value).floatValue();
break;
case DOUBLE:
result = ((Number) value).doubleValue();
break;
case STRING:
result = (String) value;
break;
case BYTES:
Class<?> clazz = value.getClass();
if (clazz != String.class && clazz != ByteString.class) {
throw new IllegalArgumentException(message(path, "bytes value %1$s is not a String or ByteString", value));
}
result = value;
break;
case ENUM:
String enumValue = (String) value;
EnumDataSchema enumDataSchema = (EnumDataSchema) dataSchema;
if (!enumDataSchema.getSymbols().contains(enumValue)) {
throw new IllegalArgumentException(message(path, "enum value %1$s not one of %2$s", value, enumDataSchema.getSymbols()));
}
result = value;
break;
case FIXED:
clazz = value.getClass();
ByteString byteString;
if (clazz == String.class) {
byteString = ByteString.copyAvroString((String) value, true);
} else if (clazz == ByteString.class) {
byteString = (ByteString) value;
} else {
throw new IllegalArgumentException(message(path, "fixed value %1$s is not a String or ByteString", value));
}
FixedDataSchema fixedDataSchema = (FixedDataSchema) dataSchema;
if (fixedDataSchema.getSize() != byteString.length()) {
throw new IllegalArgumentException(message(path, "ByteString size %1$d != FixedDataSchema size %2$d", byteString.length(), fixedDataSchema.getSize()));
}
result = byteString;
break;
case MAP:
DataMap map = (DataMap) value;
DataSchema valueDataSchema = ((MapDataSchema) dataSchema).getValues();
Map<String, Object> resultMap = new DataMap(map.size() * 2);
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
path.add(key);
Object entryAvroValue = translate(path, entry.getValue(), valueDataSchema);
path.remove(path.size() - 1);
resultMap.put(key, entryAvroValue);
}
result = resultMap;
break;
case ARRAY:
DataList list = (DataList) value;
DataList resultList = new DataList(list.size());
DataSchema elementDataSchema = ((ArrayDataSchema) dataSchema).getItems();
for (int i = 0; i < list.size(); i++) {
path.add(i);
Object entryAvroValue = translate(path, list.get(i), elementDataSchema);
path.remove(path.size() - 1);
resultList.add(entryAvroValue);
}
result = resultList;
break;
case RECORD:
DataMap recordMap = (DataMap) value;
RecordDataSchema recordDataSchema = (RecordDataSchema) dataSchema;
DataMap resultRecordMap = new DataMap(recordDataSchema.getFields().size() * 2);
for (RecordDataSchema.Field field : recordDataSchema.getFields()) {
String fieldName = field.getName();
Object fieldValue = recordMap.get(fieldName);
path.add(fieldName);
Object resultFieldValue = translateField(path, fieldValue, field);
path.remove(path.size() - 1);
if (resultFieldValue != null) {
resultRecordMap.put(fieldName, resultFieldValue);
}
}
result = resultRecordMap;
break;
case UNION:
result = translateUnion(path, value, (UnionDataSchema) dataSchema);
break;
default:
throw new IllegalStateException(message(path, "schema type unknown %1$s", type));
}
return result;
}
use of com.linkedin.data.DataList in project rest.li by linkedin.
the class Patch method executeReorderCommand.
private void executeReorderCommand(Object reorderCommand, DataList dataList, Map<String, String> usedFields, InterpreterContext instrCtx) {
if (reorderCommand != null) {
assert reorderCommand.getClass() == DataList.class : reorderCommand.getClass();
DataList reorders = (DataList) reorderCommand;
if (reorders.size() > 1) {
instrCtx.addErrorMessage("Reordering more than one array item is not supported.");
return;
}
if (reorders.size() == 1) {
assert reorders.get(0).getClass() == DataMap.class;
DataMap reorder = (DataMap) reorders.get(0);
int fromIndex = reorder.getInteger(FROM_INDEX);
int toIndex = reorder.getInteger(TO_INDEX);
int size = dataList.size();
if (fromIndex < 0 || toIndex < 0 || fromIndex >= size || toIndex >= size) {
instrCtx.addErrorMessage("$fromIndex %1$d and $toIndex %2$d must be between 0 and %3$d.", fromIndex, toIndex, size);
return;
}
if (fromIndex != toIndex) {
int direction = Integer.signum(toIndex - fromIndex);
Object fromObject = dataList.get(fromIndex);
int i = fromIndex;
while (i != toIndex) {
// Shift the items between fromIndex and toIndex by one place.
CheckedUtil.setWithoutChecking(dataList, i, dataList.get(i + direction));
i += direction;
}
CheckedUtil.setWithoutChecking(dataList, toIndex, fromObject);
}
}
}
}
use of com.linkedin.data.DataList in project rest.li by linkedin.
the class Patch method interpret.
/**
* Interpret and execute the current instruction based on the
* interpreter context.
*
* @param instrCtx the current interpreter context
*/
public void interpret(final InterpreterContext instrCtx) {
Instruction instruction = instrCtx.getCurrentInstruction();
// operation's node is always DataMap
assert instruction.getOperation().getClass() == DataMap.class;
// _usedFields variable is used to keep track of fields, which were already used
// at this nodes. The reason for it is that if field should not be used in more than
// one operation e.g. $set and $delete, because such patch becomes ambiguous.
// Each operation, upon being executed updates this variable.
final Map<String, String> usedFields = new HashMap<>();
DataMap opNode = (DataMap) instruction.getOperation();
DataComplex dataComplex = instruction.getData();
if (dataComplex.getClass() == DataMap.class) {
DataMap dataNode = (DataMap) dataComplex;
/**
* Apply all supported operations here. _usedFields is used to keep track of fields
* that operations were applied to.
*/
executeSetCommand(opNode.get(SET_COMMAND), dataNode, usedFields, instrCtx);
executeDeleteCommand(opNode.get(DELETE_COMMAND), dataNode, usedFields, instrCtx);
// iterate over children
for (Entry<String, Object> entry : opNode.entrySet()) {
processChild(dataNode, entry.getKey(), entry.getValue(), usedFields, instrCtx);
}
} else if (dataComplex.getClass() == DataList.class) {
DataList dataNode = (DataList) dataComplex;
executeReorderCommand(opNode.get(REORDER_COMMAND), dataNode, usedFields, instrCtx);
} else {
instrCtx.addErrorMessage("Unexpected data type %1$s at %2$s.", dataComplex.getClass(), instrCtx.getPath());
}
}
Aggregations