use of com.linkedin.data.DataMap in project rest.li by linkedin.
the class TestExceptionsResource2 method testGet.
@Test(dataProvider = com.linkedin.restli.internal.common.TestConstants.RESTLI_PROTOCOL_1_2_PREFIX + "exceptionHandlingModesDataProvider")
public void testGet(boolean explicit, ErrorHandlingBehavior errorHandlingBehavior, RootBuilderWrapper<Long, Greeting> builders) throws RemoteInvocationException {
Response<Greeting> response = null;
RestLiResponseException exception = null;
try {
final Request<Greeting> req = builders.get().id(1L).build();
ResponseFuture<Greeting> future;
if (explicit) {
future = getClient().sendRequest(req, errorHandlingBehavior);
} else {
future = getClient().sendRequest(req);
}
response = future.getResponse();
if (!explicit || errorHandlingBehavior == ErrorHandlingBehavior.FAIL_ON_ERROR) {
Assert.fail("expected exception");
}
} catch (RestLiResponseException e) {
if (!explicit || errorHandlingBehavior == ErrorHandlingBehavior.FAIL_ON_ERROR) {
exception = e;
} else {
Assert.fail("not expected exception");
}
}
if (explicit && errorHandlingBehavior == ErrorHandlingBehavior.TREAT_SERVER_ERROR_AS_SUCCESS) {
Assert.assertNotNull(response);
Assert.assertTrue(response.hasError());
exception = response.getError();
Assert.assertEquals(response.getStatus(), HttpStatus.S_500_INTERNAL_SERVER_ERROR.getCode());
Assert.assertNotNull(response.getEntity());
Assert.assertEquals(response.getEntity(), new Greeting().setMessage("Hello, sorry for the mess"));
}
Assert.assertNotNull(exception);
Assert.assertTrue(exception.hasDecodedResponse());
Assert.assertEquals(exception.getStatus(), HttpStatus.S_500_INTERNAL_SERVER_ERROR.getCode());
final DataMap respEntityMap = DataMapUtils.readMap(exception.getResponse());
Assert.assertEquals(respEntityMap, new Greeting().setMessage("Hello, sorry for the mess").data());
}
use of com.linkedin.data.DataMap in project rest.li by linkedin.
the class URIDetails method testUriGeneration.
/**
* Tests the construction and validity of the provided URI. Requires an URIDetails object with the broken down URI.
*
* @param createdURIString
* @param expectedURIDetails
*/
@SuppressWarnings({ "unchecked" })
public static void testUriGeneration(String createdURIString, URIDetails expectedURIDetails) {
final ProtocolVersion version = expectedURIDetails.getProtocolVersion();
//Compare the path. Note that in both V1 and V2 all the keys (complex, compound and simple) are serialized recursively
//in a sorted order. Hence the path will be the same regardless of the underlying Map implementation (order or unordered)
final String actualPath = createdURIString.split("\\?")[0];
Assert.assertEquals("The path should be correct", expectedURIDetails._path, actualPath);
//Move onto the rest of the URI
final URI createdURI = URI.create(createdURIString);
//We will parse the created URI into memory and compare it to what's inside the URI details
final DataMap actualURIDataMap;
//Note that the actualURIDataMap that is created is composed of query parameters (including ids) and fields
try {
if (version.compareTo(AllProtocolVersions.RESTLI_PROTOCOL_1_0_0.getProtocolVersion()) <= 0) {
//1.0 - decode and then parse into a data map
final Map<String, List<String>> queryParameters = UriComponent.decodeQuery(createdURI.getRawQuery(), true);
actualURIDataMap = QueryParamsDataMap.parseDataMapKeys(queryParameters);
} else {
//2.0 - no need to decode as the parsing decodes for us
final Map<String, List<String>> queryParameters = UriComponent.decodeQuery(createdURI.getRawQuery(), false);
actualURIDataMap = URIParamUtils.parseUriParams(queryParameters);
}
//This will cover everything except fields and ids
if (expectedURIDetails._queryParams != null) {
for (final Map.Entry<String, ?> entry : expectedURIDetails._queryParams.entrySet()) {
Assert.assertNotNull("We should have a valid (non null) key for query param: " + entry.getKey() + " in our created URI", actualURIDataMap.get(entry.getKey()));
Assert.assertEquals("The value portion of for the query param: " + entry.getKey() + " URI should be correct", actualURIDataMap.get(entry.getKey()), entry.getValue());
}
}
//IDs is to be treated a bit differently since client requests put them in a set
if (expectedURIDetails._ids != null) {
final Set<Object> idSet;
final List<Object> idList;
if (actualURIDataMap.get("ids") instanceof List) {
idList = (List<Object>) actualURIDataMap.get("ids");
} else {
//Just a single object, (i.e String, DataMap, etc...)
idList = Arrays.asList(actualURIDataMap.get("ids"));
}
idSet = new HashSet<Object>(idList);
Assert.assertEquals("The set of IDs must match", expectedURIDetails._ids, idSet);
}
//Fields is to be treated a bit differently since they could be in any order, hence we compare sets
if (expectedURIDetails._fields != null) {
final String[] fieldsArray = ((String) actualURIDataMap.get("fields")).split(",");
final Set<String> actualFieldSet = new HashSet<String>(Arrays.asList(fieldsArray));
Assert.assertEquals("The set of projection fields should be correct", expectedURIDetails._fields, actualFieldSet);
}
//Now we want to make sure that we have the desired number of keys in the actualURIDataMap
int desiredKeyCount = 0;
desiredKeyCount += expectedURIDetails._queryParams == null ? 0 : expectedURIDetails._queryParams.size();
//values stored in a single key
desiredKeyCount += expectedURIDetails._fields == null ? 0 : 1;
//values stored in a single key
desiredKeyCount += expectedURIDetails._ids == null ? 0 : 1;
Assert.assertEquals("Incorrect number of keys discovered in URI", desiredKeyCount, actualURIDataMap.size());
} catch (Exception e) {
Assert.fail("Unexpected exception when parsing created URI with exception: " + e);
}
}
use of com.linkedin.data.DataMap in project rest.li by linkedin.
the class RestLiAnnotationReader method addActionResourceMethod.
/**
* Add the given action method to the given resource model, validating the method is a action before adding.
* @param model provides the model to add the method to.
* @param method provides the method to add to the model.
* @throws ResourceConfigException on validation errors.
*/
private static void addActionResourceMethod(final ResourceModel model, final Method method) {
Action actionAnno = method.getAnnotation(Action.class);
if (actionAnno == null) {
return;
}
String actionName = actionAnno.name();
List<Parameter<?>> parameters = getParameters(model, method, ResourceMethod.ACTION);
Class<?> returnClass = getActionReturnClass(model, method, actionAnno, actionName);
TyperefDataSchema returnTyperefSchema = getActionTyperefDataSchema(model, actionAnno, actionName);
validateActionReturnType(model, method, returnClass, returnTyperefSchema);
if (!Modifier.isPublic(method.getModifiers())) {
throw new ResourceConfigException(String.format("Resource '%s' contains non-public action method '%s'.", model.getName(), method.getName()));
}
RecordDataSchema recordDataSchema = DynamicRecordMetadata.buildSchema(method.getName(), parameters);
RecordDataSchema actionReturnRecordDataSchema;
FieldDef<?> returnFieldDef;
if (returnClass != Void.TYPE) {
@SuppressWarnings({ "unchecked", "rawtypes" }) FieldDef<?> nonVoidFieldDef = new FieldDef(ActionResponse.VALUE_NAME, returnClass, getDataSchema(returnClass, returnTyperefSchema));
returnFieldDef = nonVoidFieldDef;
actionReturnRecordDataSchema = DynamicRecordMetadata.buildSchema(ActionResponse.class.getName(), Collections.singleton((returnFieldDef)));
} else {
returnFieldDef = null;
actionReturnRecordDataSchema = DynamicRecordMetadata.buildSchema(ActionResponse.class.getName(), Collections.<FieldDef<?>>emptyList());
}
if (model.getResourceLevel() == ResourceLevel.ENTITY && actionAnno.resourceLevel() == ResourceLevel.COLLECTION) {
throw new ResourceConfigException(String.format("Resource '%s' is a simple resource, it cannot contain actions at resource level \"COLLECTION\".", model.getName()));
}
DataMap annotationsMap = ResourceModelAnnotation.getAnnotationsMap(method.getAnnotations());
addDeprecatedAnnotation(annotationsMap, method);
model.addResourceMethodDescriptor(ResourceMethodDescriptor.createForAction(method, parameters, actionName, getActionResourceLevel(actionAnno, model), returnFieldDef, actionReturnRecordDataSchema, recordDataSchema, getInterfaceType(method), annotationsMap));
}
use of com.linkedin.data.DataMap in project rest.li by linkedin.
the class RestLiAnnotationReader method addTemplateResourceMethod.
/**
* Handle method that overrides resource template method. Only meaningful for classes
* that extend a resource template class and only for methods that are NOT annotated
* with RestMethod. Those are handled in addCrudResourceMethod()
*/
private static void addTemplateResourceMethod(final Class<?> resourceClass, final ResourceModel model, final Method method) {
// Check if the resource class is derived from one of the resource template classes.
if (!isResourceTemplateClass(resourceClass)) {
return;
}
// addCrudResourceMethod
if (isRestMethodAnnotated(method)) {
return;
}
List<Class<?>> parameterTypes = Arrays.asList(method.getParameterTypes());
boolean partial = parameterTypes.contains(PatchRequest.class) || parameterTypes.contains(BatchPatchRequest.class);
ResourceMethod resourceMethod = ResourceMethodLookup.fromResourceMethodName(method.getName(), partial);
if (resourceMethod != null) {
if (!Modifier.isPublic(method.getModifiers())) {
throw new ResourceConfigException(String.format("Resource '%s' contains non-public CRUD method '%s'.", model.getName(), method.getName()));
}
DataMap annotationsMap = ResourceModelAnnotation.getAnnotationsMap(method.getAnnotations());
addDeprecatedAnnotation(annotationsMap, method);
List<Parameter<?>> parameters = getParameters(model, method, resourceMethod);
model.addResourceMethodDescriptor(ResourceMethodDescriptor.createForRestful(resourceMethod, method, parameters, getInterfaceType(method), annotationsMap));
}
}
use of com.linkedin.data.DataMap in project rest.li by linkedin.
the class RestLiAnnotationReader method processResource.
/**
* Processes an annotated resource class, producing a ResourceModel.
*
* @param resourceClass annotated resource class
* @return {@link ResourceModel} for the provided resource class
*/
public static ResourceModel processResource(final Class<?> resourceClass, ResourceModel parentResourceModel) {
final ResourceModel model;
checkAnnotation(resourceClass);
if ((resourceClass.isAnnotationPresent(RestLiCollection.class) || resourceClass.isAnnotationPresent(RestLiAssociation.class))) {
// If any of these annotations, a subclass of KeyValueResource is expected
if (!KeyValueResource.class.isAssignableFrom(resourceClass)) {
throw new RestLiInternalException("Resource class '" + resourceClass.getName() + "' declares RestLi annotation but does not implement " + KeyValueResource.class.getName() + " interface.");
}
@SuppressWarnings("unchecked") Class<? extends KeyValueResource<?, ?>> clazz = (Class<? extends KeyValueResource<?, ?>>) resourceClass;
model = processCollection(clazz, parentResourceModel);
} else if (resourceClass.isAnnotationPresent(RestLiActions.class)) {
model = processActions(resourceClass, parentResourceModel);
} else if (resourceClass.isAnnotationPresent(RestLiSimpleResource.class)) {
@SuppressWarnings("unchecked") Class<? extends SingleObjectResource<?>> clazz = (Class<? extends SingleObjectResource<?>>) resourceClass;
model = processSingleObjectResource(clazz, parentResourceModel);
} else {
throw new ResourceConfigException("Class '" + resourceClass.getName() + "' must be annotated with a valid @RestLi... annotation");
}
if (parentResourceModel != null) {
parentResourceModel.addSubResource(model.getName(), model);
}
if (!model.isActions()) {
checkRestLiDataAnnotations(resourceClass, (RecordDataSchema) getDataSchema(model.getValueClass(), null));
}
addAlternativeKeys(model, resourceClass);
DataMap annotationsMap = ResourceModelAnnotation.getAnnotationsMap(resourceClass.getAnnotations());
addDeprecatedAnnotation(annotationsMap, resourceClass);
model.setCustomAnnotation(annotationsMap);
return model;
}
Aggregations