Source:
<code>public Set<PersistentResource> getRelation(String relation, List<String> ids, Optional<FilterExpression> filter, Optional<Sorting> sorting, Optional<Pagination> pagination) { FilterExpression filterExpression; Class<?> entityType = dictionary.getParameterizedType(getResourceClass(), relation); Set<PersistentResource> newResources = new LinkedHashSet<>(); if (entityType == null) { throw new InvalidAttributeException(relation, type); } else { if (!ids.isEmpty()) { String typeAlias = dictionary.getJsonAliasFor(entityType); newResources = requestScope.getNewPersistentResources().stream() .filter(resource -> typeAlias.equals(resource.getType()) && ids.contains(resource.getUUID().orElse(""))) .collect(Collectors.toSet()); FilterExpression idExpression = buildIdFilterExpression(ids, entityType); filterExpression = filter .map(fe -> (FilterExpression) new AndFilterExpression(idExpression, fe)) .orElse(idExpression); } else { filterExpression = filter.orElse(null); } } Set<PersistentResource> existingResources = filter(ReadPermission.class, (Set) getRelationChecked(relation, Optional.ofNullable(filterExpression), sorting, pagination)); 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()) { <START> throw new EntityForbiddenException(); <END> } return allResources; }</code><technical_language>If return missing IDs, remove calculation of allExpectedIds missedIds above</technical_language>

Target:
public Set<PersistentResource> getRelation(String relation, List<String> ids, Optional<FilterExpression> filter, Optional<Sorting> sorting, Optional<Pagination> pagination) { FilterExpression filterExpression; Class<?> entityType = dictionary.getParameterizedType(getResourceClass(), relation); Set<PersistentResource> newResources = new LinkedHashSet<>(); if (entityType == null) { throw new InvalidAttributeException(relation, type); } else { if (!ids.isEmpty()) { String typeAlias = dictionary.getJsonAliasFor(entityType); newResources = requestScope.getNewPersistentResources().stream() .filter(resource -> typeAlias.equals(resource.getType()) && ids.contains(resource.getUUID().orElse(""))) .collect(Collectors.toSet()); FilterExpression idExpression = buildIdFilterExpression(ids, entityType); filterExpression = filter .map(fe -> (FilterExpression) new AndFilterExpression(idExpression, fe)) .orElse(idExpression); } else { filterExpression = filter.orElse(null); } } Set<PersistentResource> existingResources = filter(ReadPermission.class, (Set) getRelationChecked(relation, Optional.ofNullable(filterExpression), sorting, pagination)); 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 ForbiddenEntityException(); } return allResources; }