Stream API not working for lazy loaded collections in EclipseLink / Glassfish?

After detecting an error in one of my web services, I found an error in the following single-line file:

return this.getTemplate().getDomains().stream().anyMatch(domain -> domain.getName().equals(name));

This line returned false when I positively knew that the domain list contains a domain whose name is equal to that provided name. Therefore, scratching my head a bit, I ended up dividing the entire line to see what was happening. In a debugging session, I received the following message:

Debug Session Screenshot

Pay attention to the following line:

List<Domain> domains2 = domains.stream().collect(Collectors.toList());

domains - . .stream().collect(Collectors.toList()) . , , , , ( , ). , ???

: , .

, EJB JPA . , :

@Stateful
@RequestScoped
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class DomainResources {
    @PersistenceContext(type = PersistenceContextType.EXTENDED) @RequestScoped
    private EntityManager entityManager;

    public boolean templateContainsDomainWithName(String name) { // Extra code included to diagnose the problem
        MetadataTemplate template = this.getTemplate();
        List<Domain> domains = template.getDomains();
        List<Domain> domains2 = domains.stream().collect(Collectors.toList());
        List<String> names = domains.stream().map(Domain::getName).collect(Collectors.toList());
        boolean exists1 = names.contains(name);
        boolean exists2 = this.getTemplate().getDomains().stream().anyMatch(domain -> domain.getName().equals(name));
        return this.getTemplate().getDomains().stream().anyMatch(domain -> domain.getName().equals(name));
    }

    @POST
    @RolesAllowed({"root"})
    public Response createDomain(@Valid @EmptyID DomainDTO domainDTO, @Context UriInfo uriInfo) {
        if (this.getTemplate().getLastVersionState() != State.DRAFT) {
            throw new UnmodifiableTemplateException();
        } else if (templateContainsDomainWithName(domainDTO.name)) {
            throw new DuplicatedKeyException("name", domainDTO.name);
        } else {
            Domain domain = this.getTemplate().createNewDomain(domainDTO.name);
            this.entityManager.flush();
            return Response.created(uriInfo.getAbsolutePathBuilder().path(domain.getId()).build()).entity(new DomainDTO(domain)).type(MediaType.APPLICATION_JSON).build();
        }
    }
}

@Entity
public class MetadataTemplate extends IdentifiedObject {
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "metadataTemplate", orphanRemoval = true) @OrderBy(value = "creationDate")
    private List<Version> versions = new LinkedList<>();
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) @OrderBy(value = "name")
    private List<Domain> domains = new LinkedList<>();

    public List<Version> getVersions() {
        return Collections.unmodifiableList(versions);
    }

    public List<Domain> getDomains() {
        return Collections.unmodifiableList(domains);
    }
}

getVersions getDomains, , . , , - , versions , domains . , . , ?

. @Ferrybig, , , . , :

boolean found = false;
for (Domain domain: this.getTemplate().getDomains()) {
    if (domain.getName().equals(name)) {
        found = true;
    }
}

List<Domain> domains = this.getTemplate().getDomains();
long estimatedSize = domains.spliterator().estimateSize(); // This returns 0!
domains.spliterator().forEachRemaining(domain -> {
    // Execution flow never reaches this point!
});

, , , . , spliterator -, . ?

BTW, Glassfish/EclipseLink

+4
2

- . .

: . EclipseLink, , org.eclipse.persistence.indirection.IndirectList. java.util.Vector, , removeRange. , , Eclipse, , , (Iterable<E>, Collection<E> List<E>)?

: , , $# | T . , IndirectList . , , ! ? ( ) elementCount? , , ... , -, , , . , ... , ?

: . Vector. Java 1.8 spliterator . (VectorSpliterator), API. , , , , , elementCount API- size(). , elementCount? , ?

, , IndirectList, , Vector (, , , ) .

, , EclipseLink ( JPA Glassfish). , . !

WORKAROUND. , stream(), , . , getDomains. ( ):

public List<Domain> getDomains() {
    return Collections.unmodifiableList(new ArrayList<>(domains));
}

: , .

@Ferrybig

. . , https://bugs.eclipse.org/bugs/show_bug.cgi?id=487799

+8

unit test:

Optional<ChildTable> ct = st.getChildren().stream().filter(i -> i.getId().equals(20001000l)).findFirst();

ct.get() NoSuchElementException.

EclipseLink 2.5.2 2.6.2 . EclipseLink.

, https://bugs.eclipse.org/bugs/show_bug.cgi?id=433075.

. API EclipseLink Java 8 https://bugs.eclipse.org/bugs/show_bug.cgi?id=467470.

+1

Source: https://habr.com/ru/post/1628499/


All Articles