/** * All Paths are 'tagged' in swagger with the final entity type name in the path. * This allows swaggerUI to group the paths by entities. * @return the entity type name */ private String getTag() { return dictionary.getJsonAliasFor(type); }
/** * Constructs a PathMetaData for a 'root' entity. * @param type the 'root' entity type of the first segment of the URL. */ public PathMetaData(Class<?> type) { this.type = type; lineage = new Stack<>(); name = dictionary.getJsonAliasFor(type); }
/** * @return Something like '/book/{bookId}' */ public String getInstanceUrl() { String typeName = dictionary.getJsonAliasFor(type); return getCollectionUrl() + "/{" + typeName + "Id}"; }
private Path buildPath(Class rootEntityType, String selector) { String[] associationNames = selector.split("\\."); List<Path.PathElement> path = new ArrayList<>(); Class entityType = rootEntityType; for (String associationName : associationNames) { String typeName = dictionary.getJsonAliasFor(entityType); Class fieldType = dictionary.getParameterizedType(entityType, associationName); if (fieldType == null) { throw new RSQLParseException( String.format("No such association %s for type %s", associationName, typeName)); } path.add(new Path.PathElement(entityType, fieldType, associationName)); entityType = fieldType; } return new Path(path); }
private Path buildPath(Class rootEntityType, String selector) { String[] associationNames = selector.split("\\."); List<Path.PathElement> path = new ArrayList<>(); Class entityType = rootEntityType; for (String associationName : associationNames) { String typeName = dictionary.getJsonAliasFor(entityType); Class fieldType = dictionary.getParameterizedType(entityType, associationName); if (fieldType == null) { throw new RSQLParseException( String.format("No such association %s for type %s", associationName, typeName)); } path.add(new Path.PathElement(entityType, fieldType, associationName)); entityType = fieldType; } return new Path(path); }
/** * Invoke the get[fieldName] method on the target object OR get the field with the corresponding name. * @param target the object to get * @param fieldName the field name to get or invoke equivalent get method * @param requestScope the request scope * @return the value */ public static Object getValue(Object target, String fieldName, RequestScope requestScope) { EntityDictionary dictionary = requestScope.getDictionary(); AccessibleObject accessor = dictionary.getAccessibleObject(target, fieldName); try { if (accessor instanceof Method) { // Pass RequestScope into @Computed fields if requested if (dictionary.isMethodRequestScopeable(target, (Method) accessor)) { return ((Method) accessor).invoke(target, requestScope); } return ((Method) accessor).invoke(target); } if (accessor instanceof Field) { return ((Field) accessor).get(target); } } catch (IllegalAccessException e) { throw new InvalidAttributeException(fieldName, dictionary.getJsonAliasFor(target.getClass()), e); } catch (InvocationTargetException e) { throw handleInvocationTargetException(e); } throw new InvalidAttributeException(fieldName, dictionary.getJsonAliasFor(target.getClass())); }
/** * Construct a new resource from the ID provided. * * @param obj the obj * @param parent the parent * @param id the id * @param scope the request scope */ public PersistentResource(@NonNull T obj, PersistentResource parent, String id, @NonNull RequestScope scope) { this.obj = obj; this.uuid = Optional.ofNullable(id); this.lineage = parent != null ? new ResourceLineage(parent.lineage, parent) : new ResourceLineage(); this.dictionary = scope.getDictionary(); this.type = dictionary.getJsonAliasFor(obj.getClass()); this.transaction = scope.getTransaction(); this.requestScope = scope; dictionary.initializeEntity(obj); }
/** * Construct a new resource from the ID provided. * * @param obj the obj * @param parent the parent * @param id the id * @param scope the request scope */ public PersistentResource(@NonNull T obj, PersistentResource parent, String id, @NonNull RequestScope scope) { this.obj = obj; this.uuid = Optional.ofNullable(id); this.lineage = parent != null ? new ResourceLineage(parent.lineage, parent) : new ResourceLineage(); this.dictionary = scope.getDictionary(); this.type = dictionary.getJsonAliasFor(obj.getClass()); this.transaction = scope.getTransaction(); this.requestScope = scope; dictionary.initializeEntity(obj); }
private Set<PersistentResource> getRelation(String relationName, Optional<FilterExpression> filterExpression, Optional<Sorting> sorting, Optional<Pagination> pagination, boolean checked) { if (checked && !checkRelation(relationName)) { return Collections.emptySet(); } final Class<?> relationClass = dictionary.getParameterizedType(obj, relationName); if (pagination.isPresent() && !pagination.get().isDefaultInstance() && !CanPaginateVisitor.canPaginate(relationClass, dictionary, requestScope)) { throw new InvalidPredicateException(String.format("Cannot paginate %s", dictionary.getJsonAliasFor(relationClass))); } return getRelationUnchecked(relationName, filterExpression, sorting, pagination); }
private Set<PersistentResource> getRelation(String relationName, Optional<FilterExpression> filterExpression, Optional<Sorting> sorting, Optional<Pagination> pagination, boolean checked) { if (checked && !checkRelation(relationName)) { return Collections.emptySet(); } final Class<?> relationClass = dictionary.getParameterizedType(obj, relationName); if (pagination.isPresent() && !pagination.get().isDefaultInstance() && !CanPaginateVisitor.canPaginate(relationClass, dictionary, requestScope)) { throw new InvalidPredicateException(String.format("Cannot paginate %s", dictionary.getJsonAliasFor(relationClass))); } return getRelationUnchecked(relationName, filterExpression, sorting, pagination); }
@Override public Map<String, FilterExpression> parseTypedExpression(String path, MultivaluedMap<String, String> filterParams) throws ParseException { Map<String, FilterExpression> expressionMap = new HashMap<>(); List<FilterPredicate> filterPredicates = extractPredicates(filterParams); for (FilterPredicate filterPredicate : filterPredicates) { if (FilterPredicate.toManyInPath(dictionary, filterPredicate.getPath())) { throw new ParseException("Invalid toMany join: " + filterPredicate); } String entityType = dictionary.getJsonAliasFor(filterPredicate.getEntityType()); FilterExpression filterExpression = expressionMap.get(entityType); if (filterExpression != null) { expressionMap.put(entityType, new AndFilterExpression(filterExpression, filterPredicate)); } else { expressionMap.put(entityType, filterPredicate); } } return expressionMap; }
public Path(Class<?> entityClass, EntityDictionary dictionary, String dotSeparatedPath) { List<PathElement> elements = new ArrayList<>(); String[] fieldNames = dotSeparatedPath.split("\\."); Class<?> currentClass = entityClass; for (String fieldName : fieldNames) { if (dictionary.isRelation(currentClass, fieldName)) { Class<?> relationClass = dictionary.getParameterizedType(currentClass, fieldName); elements.add(new PathElement(currentClass, relationClass, fieldName)); currentClass = relationClass; } else if (dictionary.isAttribute(currentClass, fieldName) || fieldName.equals(dictionary.getIdFieldName(entityClass))) { Class<?> attributeClass = dictionary.getType(currentClass, fieldName); elements.add(new PathElement(currentClass, attributeClass, fieldName)); } else if ("this".equals(fieldName)) { elements.add(new PathElement(currentClass, null, fieldName)); } else { String alias = dictionary.getJsonAliasFor(currentClass); throw new InvalidValueException(alias + " doesn't contain the field " + fieldName); } } pathElements = ImmutableList.copyOf(elements); }
@Override public Map<String, FilterExpression> parseTypedExpression(String path, MultivaluedMap<String, String> filterParams) throws ParseException { Map<String, FilterExpression> expressionMap = new HashMap<>(); List<FilterPredicate> filterPredicates = extractPredicates(filterParams); for (FilterPredicate filterPredicate : filterPredicates) { if (FilterPredicate.toManyInPath(dictionary, filterPredicate.getPath())) { throw new ParseException("Invalid toMany join: " + filterPredicate); } String entityType = dictionary.getJsonAliasFor(filterPredicate.getEntityType()); FilterExpression filterExpression = expressionMap.get(entityType); if (filterExpression != null) { expressionMap.put(entityType, new AndFilterExpression(filterExpression, filterPredicate)); } else { expressionMap.put(entityType, filterPredicate); } } return expressionMap; }
public Path(Class<?> entityClass, EntityDictionary dictionary, String dotSeparatedPath) { List<PathElement> elements = new ArrayList<>(); String[] fieldNames = dotSeparatedPath.split("\\."); Class<?> currentClass = entityClass; for (String fieldName : fieldNames) { if (dictionary.isRelation(currentClass, fieldName)) { Class<?> relationClass = dictionary.getParameterizedType(currentClass, fieldName); elements.add(new PathElement(currentClass, relationClass, fieldName)); currentClass = relationClass; } else if (dictionary.isAttribute(currentClass, fieldName) || fieldName.equals(dictionary.getIdFieldName(entityClass))) { Class<?> attributeClass = dictionary.getType(currentClass, fieldName); elements.add(new PathElement(currentClass, attributeClass, fieldName)); } else if ("this".equals(fieldName)) { elements.add(new PathElement(currentClass, null, fieldName)); } else { String alias = dictionary.getJsonAliasFor(currentClass); throw new InvalidValueException(alias + " doesn't contain the field " + fieldName); } } pathElements = ImmutableList.copyOf(elements); }
/** * Build an id filter expression for a particular entity type. * * @param ids Ids to include in the filter expression * @param entityType Type of entity * @return Filter expression for given ids and type. */ private static FilterExpression buildIdFilterExpression(List<String> ids, Class entityType, EntityDictionary dictionary, RequestScope scope) { Class<?> idType = dictionary.getIdType(entityType); String idField = dictionary.getIdFieldName(entityType); String typeAlias = dictionary.getJsonAliasFor(entityType); List<Object> coercedIds = ids.stream() .filter(id -> scope.getObjectById(typeAlias, id) == null) // these don't exist yet .map(id -> CoerceUtil.coerce(id, idType)) .collect(Collectors.toList()); /* construct a new SQL like filter expression, eg: book.id IN [1,2] */ FilterExpression idFilter = new InPredicate( new Path.PathElement( entityType, idType, idField), coercedIds); return idFilter; }
/** * @return the swagger PathParameter for this particular path segment. */ private Parameter getPathParameter() { String typeName = dictionary.getJsonAliasFor(type); Parameter param = new PathParameter() .name(typeName + "Id") .description(typeName + " Identifier") .property(new StringProperty()); return param; }
/** * Builds a GraphQL connection object from an entity class. * * @param entityClass The class to use to construct the output object * @return The GraphQL object. */ private GraphQLObjectType buildConnectionObject(Class<?> entityClass) { if (connectionObjectRegistry.containsKey(entityClass)) { return connectionObjectRegistry.get(entityClass); } String entityName = dictionary.getJsonAliasFor(entityClass); GraphQLObjectType connectionObject = newObject() .name(entityName) .field(newFieldDefinition() .name("edges") .dataFetcher(dataFetcher) .type(buildEdgesObject(entityName, buildQueryObject(entityClass)))) .field(newFieldDefinition() .name("pageInfo") .dataFetcher(dataFetcher) .type(pageInfoObject)) .build(); connectionObjectRegistry.put(entityClass, connectionObject); return connectionObject; }
/** * @return the JSON-API 'field' query parameter for some GET operations. */ private Parameter getSparseFieldsParameter() { String typeName = dictionary.getJsonAliasFor(type); List<String> fieldNames = dictionary.getAllFields(type); return new QueryParameter() .type("array") .name("fields[" + typeName + "]") .description("Selects the set of " + typeName + " fields that should be returned in the result.") .items(new StringProperty()._enum(fieldNames)) .collectionFormat("csv"); }
/** * Get the filter expression for a particular relationship * @param parent The object which has the relationship * @param relationName The relationship name * @return A type specific filter expression for the given relationship */ public Optional<FilterExpression> getExpressionForRelation(PersistentResource parent, String relationName) { final Class<?> entityClass = dictionary.getParameterizedType(parent.getObject(), relationName); if (entityClass == null) { throw new InvalidAttributeException(relationName, parent.getType()); } if (dictionary.isMappedInterface(entityClass) && interfaceHasFilterExpression(entityClass)) { throw new InvalidOperationException( "Cannot apply filters to polymorphic relations mapped with MappedInterface"); } final String valType = dictionary.getJsonAliasFor(entityClass); return getFilterExpressionByType(valType); }
/** * Get the filter expression for a particular relationship * @param parent The object which has the relationship * @param relationName The relationship name * @return A type specific filter expression for the given relationship */ public Optional<FilterExpression> getExpressionForRelation(PersistentResource parent, String relationName) { final Class<?> entityClass = dictionary.getParameterizedType(parent.getObject(), relationName); if (entityClass == null) { throw new InvalidAttributeException(relationName, parent.getType()); } if (dictionary.isMappedInterface(entityClass) && interfaceHasFilterExpression(entityClass)) { throw new InvalidOperationException( "Cannot apply filters to polymorphic relations mapped with MappedInterface"); } final String valType = dictionary.getJsonAliasFor(entityClass); return getFilterExpressionByType(valType); }