title: Stream API not working for lazy loaded collections in EclipseLink / Glassfish?
body: <p>After detecting a flaw in one of my web services I tracked down the error to the following one-liner:</p>
  
  <pre><code>return this.getTemplate().getDomains().stream().anyMatch(domain -&gt; domain.getName().equals(name));
  </code></pre>
  
  <p>This line was returning false when I positively knew that the list of domains contained a domain which name was equal to the provided <code>name</code>. So after scratching my head for a while, I ended up splitting the whole line to see what was going on. I got the following in my debugging session:</p>
  
  <p><a href="https://i.stack.imgur.com/NoQFr.png" rel="noreferrer"><img src="https://i.stack.imgur.com/NoQFr.png" alt="Screenshot of debugging session"></a></p>
  
  <p>Please notice the following line:</p>
  
  <pre><code>List&lt;Domain&gt; domains2 = domains.stream().collect(Collectors.toList());
  </code></pre>
  
  <p>According to the debugger, <code>domains</code> is a list with two elements. But after applying <code>.stream().collect(Collectors.toList())</code> I get a completely empty list. Correct me if I'm wrong, but from what I understand, that should be the identity operation and return the same list (or a copy of it if we are strict). So what is going on here??? </p>
  
  <p>Before you ask: <strong>No, I haven't manipulated that screenshot at all.</strong></p>
  
  <p>To put this in context, this code is executed in a stateful request scoped EJB using JPA managed entities with field access in a extended persistence context. Here you have some parts of the code relevant to the problem at hand:</p>
  
  <pre><code>@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&lt;Domain&gt; domains = template.getDomains();
          List&lt;Domain&gt; domains2 = domains.stream().collect(Collectors.toList());
          List&lt;String&gt; names = domains.stream().map(Domain::getName).collect(Collectors.toList());
          boolean exists1 = names.contains(name);
          boolean exists2 = this.getTemplate().getDomains().stream().anyMatch(domain -&gt; domain.getName().equals(name));
          return this.getTemplate().getDomains().stream().anyMatch(domain -&gt; 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&lt;Version&gt; versions = new LinkedList&lt;&gt;();
      @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true) @OrderBy(value = "name")
      private List&lt;Domain&gt; domains = new LinkedList&lt;&gt;();
  
      public List&lt;Version&gt; getVersions() {
          return Collections.unmodifiableList(versions);
      }
  
      public List&lt;Domain&gt; getDomains() {
          return Collections.unmodifiableList(domains);
      }
  }
  </code></pre>
  
  <p>I've included both <code>getVersions</code> and <code>getDomains</code> methods because I have similar operations running flawlessly on versions. The only significant difference I'm able to find is that <code>versions</code> are eagerly fetched while <code>domains</code> are lazily fetched. But as far as I know the code is being executed inside a transaction and the list of domains is being loaded. If not I'd get a lazy initialization exception, wouldn't I?</p>
  
  <p><strong>UPDATE</strong>: Following @Ferrybig 's suggestion I've investigated the issue a bit further, and there doesn't seem to have anything to do with improper lazy loading. If I traverse the collection in a classic way I still can't get proper results using streams:</p>
  
  <pre><code>boolean found = false;
  for (Domain domain: this.getTemplate().getDomains()) {
      if (domain.getName().equals(name)) {
          found = true;
      }
  }
  
  List&lt;Domain&gt; domains = this.getTemplate().getDomains();
  long estimatedSize = domains.spliterator().estimateSize(); // This returns 0!
  domains.spliterator().forEachRemaining(domain -&gt; {
      // Execution flow never reaches this point!
  });
  </code></pre>
  
  <p>So it seems that even when the collection has been loaded you still have that odd behavior. This seems to be a missing or empty spliterator implementation in the proxy used to manage lazy collections. What do you think?</p>
  
  <p>BTW, this is deployed on Glassfish / EclipseLink</p>