use of com.linkedin.data.template.TemplateRuntimeException in project rest.li by linkedin.
the class ArgumentBuilder method buildRegularArgument.
/**
* Build a method argument from a request parameter that is NOT backed by a schema, i.e.
* a primitive or an array
*
* @param context {@link ResourceContext}
* @param param {@link Parameter}
* @return argument value in the correct type
*/
private static Object buildRegularArgument(final ResourceContext context, final Parameter<?> param) {
String value = ArgumentUtils.argumentAsString(context.getParameter(param.getName()), param.getName());
final Object convertedValue;
if (value == null) {
return null;
} else {
if (param.isArray()) {
convertedValue = buildArrayArgument(context, param);
} else {
try {
convertedValue = ArgumentUtils.convertSimpleValue(value, param.getDataSchema(), param.getType());
} catch (NumberFormatException e) {
Class<?> targetClass = DataSchemaUtil.dataSchemaTypeToPrimitiveDataSchemaClass(param.getDataSchema().getDereferencedType());
// thrown from Integer.valueOf or Long.valueOf
throw new RoutingException(String.format("Argument parameter '%s' value '%s' must be of type '%s'", param.getName(), value, targetClass.getName()), HttpStatus.S_400_BAD_REQUEST.getCode());
} catch (IllegalArgumentException e) {
// thrown from Enum.valueOf
throw new RoutingException(String.format("Argument parameter '%s' value '%s' is invalid", param.getName(), value), HttpStatus.S_400_BAD_REQUEST.getCode());
} catch (TemplateRuntimeException e) {
// thrown from DataTemplateUtil.coerceOutput
throw new RoutingException(String.format("Argument parameter '%s' value '%s' is invalid. Reason: %s", param.getName(), value, e.getMessage()), HttpStatus.S_400_BAD_REQUEST.getCode());
}
}
}
return convertedValue;
}
use of com.linkedin.data.template.TemplateRuntimeException in project rest.li by linkedin.
the class RestLiDataValidator method validateOutputEntity.
private ValidationResult validateOutputEntity(RecordTemplate entity, MaskTree projectionMask) {
try {
// Value class from resource model is the only source of truth for record schema.
// Schema from the record template itself should not be used.
DataSchema originalSchema = DataTemplateUtil.getSchema(_valueClass);
// When a projection is defined, we only need to validate the projected fields.
DataSchema validatingSchema = (projectionMask != null) ? buildSchemaByProjection(originalSchema, projectionMask.getDataMap()) : originalSchema;
DataSchemaAnnotationValidator validator = new DataSchemaAnnotationValidator(validatingSchema);
return ValidateDataAgainstSchema.validate(entity.data(), validatingSchema, new ValidationOptions(), validator);
} catch (TemplateRuntimeException e) {
return validationResultWithErrorMessage(TEMPLATE_RUNTIME_ERROR);
}
}
use of com.linkedin.data.template.TemplateRuntimeException in project rest.li by linkedin.
the class RestLiAnnotationReader method buildQueryParam.
private static Parameter<?> buildQueryParam(final Method method, final AnnotationSet annotations, final Class<?> paramType) {
QueryParam queryParam = annotations.get(QueryParam.class);
Optional optional = annotations.get(Optional.class);
String paramName = queryParam.value();
if (INVALID_CHAR_PATTERN.matcher(paramName).find()) {
throw new ResourceConfigException("Unsupported character in the parameter name :" + paramName);
}
Class<? extends TyperefInfo> typerefInfoClass = queryParam.typeref();
try {
@SuppressWarnings({ "unchecked", "rawtypes" }) Parameter<?> param = new Parameter(queryParam.value(), paramType, getDataSchema(paramType, getSchemaFromTyperefInfo(typerefInfoClass)), optional != null, getDefaultValueData(optional), Parameter.ParamType.QUERY, true, annotations);
return param;
} catch (TemplateRuntimeException e) {
throw new ResourceConfigException("DataSchema for parameter '" + paramName + "' of type " + paramType.getSimpleName() + " on " + buildMethodMessage(method) + "cannot be found; type is invalid or requires typeref", e);
} catch (Exception e) {
throw new ResourceConfigException("Typeref for parameter '" + paramName + "' on " + buildMethodMessage(method) + " cannot be instantiated, " + e.getMessage(), e);
}
}
use of com.linkedin.data.template.TemplateRuntimeException in project rest.li by linkedin.
the class RestLiAnnotationReader method buildAlternativeKey.
/**
* Create an {@link com.linkedin.restli.server.AlternativeKey} object from an {@link com.linkedin.restli.server.annotations.AlternativeKey} annotation.
*
* @param resourceName Name of the resource.
* @param altKeyAnnotation The {@link com.linkedin.restli.server.annotations.AlternativeKey} annotation.
* @return {@link com.linkedin.restli.server.AlternativeKey} object.
*/
private static com.linkedin.restli.server.AlternativeKey<?, ?> buildAlternativeKey(String resourceName, AlternativeKey altKeyAnnotation) {
String keyName = altKeyAnnotation.name();
Class<?> keyType = altKeyAnnotation.keyType();
Class<? extends TyperefInfo> altKeyTyperef = altKeyAnnotation.keyTyperefClass();
KeyCoercer<?, ?> keyCoercer;
try {
keyCoercer = altKeyAnnotation.keyCoercer().newInstance();
} catch (InstantiationException e) {
throw new ResourceConfigException(String.format("KeyCoercer for alternative key '%s' on resource %s cannot be instantiated, %s", keyName, resourceName, e.getMessage()), e);
} catch (IllegalAccessException e) {
throw new ResourceConfigException(String.format("KeyCoercer for alternative key '%s' on resource %s cannot be instantiated, %s", keyName, resourceName, e.getMessage()), e);
}
try {
@SuppressWarnings("unchecked") com.linkedin.restli.server.AlternativeKey<?, ?> altKey = new com.linkedin.restli.server.AlternativeKey(keyCoercer, keyType, getDataSchema(keyType, getSchemaFromTyperefInfo(altKeyTyperef)));
return altKey;
} catch (TemplateRuntimeException e) {
throw new ResourceConfigException(String.format("DataSchema for alternative key '%s' of type %s on resource %s cannot be found; type is invalid or requires typeref.", keyName, keyType, resourceName), e);
} catch (Exception e) {
throw new ResourceConfigException(String.format("Typeref for alternative key '%s' on resource %s cannot be instantiated, %s", keyName, resourceName, e.getMessage()), e);
}
}
use of com.linkedin.data.template.TemplateRuntimeException in project rest.li by linkedin.
the class ArgumentBuilder method buildArgs.
/**
* Build arguments for resource method invocation. Combines various types of arguments
* into a single array.
*
* @param positionalArguments pass-through arguments coming from
* {@link RestLiArgumentBuilder}
* @param resourceMethod the resource method
* @param context {@link ResourceContext}
* @param template {@link DynamicRecordTemplate}
* @return array of method argument for method invocation.
*/
@SuppressWarnings("deprecation")
public static Object[] buildArgs(final Object[] positionalArguments, final ResourceMethodDescriptor resourceMethod, final ResourceContext context, final DynamicRecordTemplate template) {
List<Parameter<?>> parameters = resourceMethod.getParameters();
Object[] arguments = Arrays.copyOf(positionalArguments, parameters.size());
fixUpComplexKeySingletonArraysInArguments(arguments);
boolean attachmentsDesired = false;
for (int i = positionalArguments.length; i < parameters.size(); ++i) {
Parameter<?> param = parameters.get(i);
try {
if (param.getParamType() == Parameter.ParamType.KEY || param.getParamType() == Parameter.ParamType.ASSOC_KEY_PARAM) {
Object value = context.getPathKeys().get(param.getName());
if (value != null) {
arguments[i] = value;
continue;
}
} else if (param.getParamType() == Parameter.ParamType.CALLBACK) {
continue;
} else if (param.getParamType() == Parameter.ParamType.PARSEQ_CONTEXT_PARAM || param.getParamType() == Parameter.ParamType.PARSEQ_CONTEXT) {
// don't know what to fill in yet
continue;
} else if (param.getParamType() == Parameter.ParamType.HEADER) {
HeaderParam headerParam = param.getAnnotations().get(HeaderParam.class);
String value = context.getRequestHeaders().get(headerParam.value());
arguments[i] = value;
continue;
} else //we must evaluate based on the param type (annotation used)
if (param.getParamType() == Parameter.ParamType.PROJECTION || param.getParamType() == Parameter.ParamType.PROJECTION_PARAM) {
arguments[i] = context.getProjectionMask();
continue;
} else if (param.getParamType() == Parameter.ParamType.METADATA_PROJECTION_PARAM) {
arguments[i] = context.getMetadataProjectionMask();
continue;
} else if (param.getParamType() == Parameter.ParamType.PAGING_PROJECTION_PARAM) {
arguments[i] = context.getPagingProjectionMask();
continue;
} else if (param.getParamType() == Parameter.ParamType.CONTEXT || param.getParamType() == Parameter.ParamType.PAGING_CONTEXT_PARAM) {
PagingContext ctx = RestUtils.getPagingContext(context, (PagingContext) param.getDefaultValue());
arguments[i] = ctx;
continue;
} else if (param.getParamType() == Parameter.ParamType.PATH_KEYS || param.getParamType() == Parameter.ParamType.PATH_KEYS_PARAM) {
arguments[i] = context.getPathKeys();
continue;
} else if (param.getParamType() == Parameter.ParamType.PATH_KEY_PARAM) {
Object value = context.getPathKeys().get(param.getName());
if (value != null) {
arguments[i] = value;
continue;
}
} else if (param.getParamType() == Parameter.ParamType.RESOURCE_CONTEXT || param.getParamType() == Parameter.ParamType.RESOURCE_CONTEXT_PARAM) {
arguments[i] = context;
continue;
} else if (param.getParamType() == Parameter.ParamType.VALIDATOR_PARAM) {
RestLiDataValidator validator = new RestLiDataValidator(resourceMethod.getResourceModel().getResourceClass().getAnnotations(), resourceMethod.getResourceModel().getValueClass(), resourceMethod.getMethodType());
arguments[i] = validator;
continue;
} else if (param.getParamType() == Parameter.ParamType.RESTLI_ATTACHMENTS_PARAM) {
arguments[i] = ((ServerResourceContext) context).getRequestAttachmentReader();
attachmentsDesired = true;
continue;
} else if (param.getParamType() == Parameter.ParamType.POST) {
// handle action parameters
if (template != null) {
DataMap data = template.data();
if (data.containsKey(param.getName())) {
arguments[i] = template.getValue(param);
continue;
}
}
} else if (param.getParamType() == Parameter.ParamType.QUERY) {
Object value;
if (DataTemplate.class.isAssignableFrom(param.getType())) {
value = buildDataTemplateArgument(context, param);
} else {
value = buildRegularArgument(context, param);
}
if (value != null) {
arguments[i] = value;
continue;
}
} else if (param.getParamType() == Parameter.ParamType.BATCH || param.getParamType() == Parameter.ParamType.RESOURCE_KEY) {
// should not come to this routine since it should be handled by passing in positionalArguments
throw new RoutingException("Parameter '" + param.getName() + "' should be passed in as a positional argument", HttpStatus.S_400_BAD_REQUEST.getCode());
} else {
// unknown param type
throw new RoutingException("Parameter '" + param.getName() + "' has an unknown parameter type '" + param.getParamType().name() + "'", HttpStatus.S_400_BAD_REQUEST.getCode());
}
} catch (TemplateRuntimeException e) {
throw new RoutingException("Parameter '" + param.getName() + "' is invalid", HttpStatus.S_400_BAD_REQUEST.getCode());
}
try {
// check if it is optional parameter
if (param.isOptional() && param.hasDefaultValue()) {
arguments[i] = param.getDefaultValue();
} else if (param.isOptional() && !param.getType().isPrimitive()) {
// optional primitive parameter must have default value or provided
arguments[i] = null;
} else {
throw new RoutingException("Parameter '" + param.getName() + "' is required", HttpStatus.S_400_BAD_REQUEST.getCode());
}
} catch (ResourceConfigException e) {
// Parameter default value format exception should result in server error code 500.
throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Parameter '" + param.getName() + "' default value is invalid", e);
}
}
//that were not needed is safe, but not for request attachments.
if (!attachmentsDesired && ((ServerResourceContext) context).getRequestAttachmentReader() != null) {
throw new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, "Resource method endpoint invoked does not accept any request attachments.");
}
return arguments;
}
Aggregations