PersistentResource implements com.yahoo.elide.security.PersistentResource<T> { public static Set<PersistentResource> loadRecords( Class<?> loadClass, List<String> ids, Optional<FilterExpression> filter, Optional<Sorting> sorting, Optional<Pagination> pagination, RequestScope requestScope) { EntityDictionary dictionary = requestScope.getDictionary(); FilterExpression filterExpression; DataStoreTransaction tx = requestScope.getTransaction(); if (shouldSkipCollection(loadClass, ReadPermission.class, requestScope)) { if (ids.isEmpty()) { return Collections.emptySet(); } throw new InvalidObjectIdentifierException(ids.toString(), dictionary.getJsonAliasFor(loadClass)); } if (pagination.isPresent() && !pagination.get().isDefaultInstance() && !CanPaginateVisitor.canPaginate(loadClass, dictionary, requestScope)) { throw new BadRequestException(String.format("Cannot paginate %s", dictionary.getJsonAliasFor(loadClass))); } Set<PersistentResource> newResources = new LinkedHashSet<>(); if (!ids.isEmpty()) { String typeAlias = dictionary.getJsonAliasFor(loadClass); newResources = requestScope.getNewPersistentResources().stream() .filter(resource -> typeAlias.equals(resource.getType()) && ids.contains(resource.getUUID().orElse(""))) .collect(Collectors.toSet()); FilterExpression idExpression = buildIdFilterExpression(ids, loadClass, dictionary, requestScope); filterExpression = filter .map(fe -> (FilterExpression) new AndFilterExpression(idExpression, fe)) .orElse(idExpression); } else { filterExpression = filter.orElse(null); } Optional<FilterExpression> permissionFilter = getPermissionFilterExpression(loadClass, requestScope); if (permissionFilter.isPresent()) { if (filterExpression != null) { filterExpression = new AndFilterExpression(filterExpression, permissionFilter.get()); } else { filterExpression = permissionFilter.get(); } } Set<PersistentResource> existingResources = filter(ReadPermission.class, filter, new PersistentResourceSet(tx.loadObjects(loadClass, Optional.ofNullable(filterExpression), sorting, pagination.map(p -> p.evaluate(loadClass)), requestScope), requestScope)); Set<PersistentResource> allResources = Sets.union(newResources, existingResources); Set<String> allExpectedIds = allResources.stream() .map(resource -> (String) resource.getUUID().orElseGet(resource::getId)) .collect(Collectors.toSet()); Set<String> missedIds = Sets.difference(new HashSet<>(ids), allExpectedIds); if (!missedIds.isEmpty()) { throw new InvalidObjectIdentifierException(missedIds.toString(), dictionary.getJsonAliasFor(loadClass)); } return allResources; } PersistentResource(@NonNull T obj, PersistentResource parent, String id, @NonNull RequestScope scope); @Override String toString(); static PersistentResource<T> createObject(
            PersistentResource<?> parent,
            Class<T> entityClass,
            RequestScope requestScope,
            Optional<String> uuid); @Override boolean matchesId(String checkId); @SuppressWarnings("resource") @NonNull static PersistentResource<T> loadRecord(
            Class<T> loadClass, String id, RequestScope requestScope); static Set<PersistentResource> loadRecords(
            Class<?> loadClass,
            List<String> ids,
            Optional<FilterExpression> filter,
            Optional<Sorting> sorting,
            Optional<Pagination> pagination,
            RequestScope requestScope); boolean updateAttribute(String fieldName, Object newVal); boolean updateRelation(String fieldName, Set<PersistentResource> resourceIdentifiers); boolean clearRelation(String relationName); void removeRelation(String fieldName, PersistentResource removeResource); boolean relationshipAlreadyExists(String fieldName, PersistentResource toAdd); void addRelation(String fieldName, PersistentResource newRelation); void deleteResource(); @Override String getId(); void setId(String id); boolean isIdGenerated(); @Override Optional<String> getUUID(); PersistentResource getRelation(String relation, String id); Set<PersistentResource> getRelation(String relation,
            List<String> ids,
            Optional<FilterExpression> filter,
            Optional<Sorting> sorting,
            Optional<Pagination> pagination); Set<PersistentResource> getRelationCheckedFiltered(String relationName,
            Optional<FilterExpression> filterExpression,
            Optional<Sorting> sorting,
            Optional<Pagination> pagination); RelationshipType getRelationshipType(String relation); Object getAttribute(String attr); @Override T getObject(); void setObject(T obj); @Override @JsonIgnore Class<T> getResourceClass(); @Override String getType(); @Override int hashCode(); @Override boolean equals(Object obj); ResourceLineage getLineage(); EntityDictionary getDictionary(); @Override RequestScope getRequestScope(); Resource toResource(); Resource toResourceWithSortingAndPagination(); Resource toResource(final Supplier<Map<String, Relationship>> relationshipSupplier,
                               final Supplier<Map<String, Object>> attributeSupplier); static Object getValue(Object target, String fieldName, RequestScope requestScope);  }
@Test() public void testLoadRecords() { Child child1 = newChild(1); Child child2 = newChild(-2); Child child3 = newChild(-3); Child child4 = newChild(4); Child child5 = newChild(5); DataStoreTransaction tx = mock(DataStoreTransaction.class); User goodUser = new User(1); when(tx.loadObjects(eq(Child.class), any(), any(), any(), any(RequestScope.class))) .thenReturn(Lists.newArrayList(child1, child2, child3, child4, child5)); RequestScope goodScope = buildRequestScope(tx, goodUser); Set<PersistentResource> loaded = PersistentResource.loadRecords(Child.class, new ArrayList<>(), Optional.empty(), Optional.empty(), Optional.empty(), goodScope); Set<Child> expected = Sets.newHashSet(child1, child4, child5); Set<Object> actual = loaded.stream().map(PersistentResource::getObject).collect(Collectors.toSet()); assertEquals(3, actual.size(), "The returned list should be filtered to only include elements that have read permission" ); assertEquals(expected, actual, "The returned list should only include elements with a positive ID" ); }