title: Disabling Hibernate's recursive fetch
body: <p>Current stack:</p>
  
  <ul>
  <li>Spring Boot 1.5.1</li>
  <li>Spring Data JPA 1.11.0</li>
  <li>Hibernate Core 5.2.6</li>
  </ul>
  
  <p>Let's say we have the following <code>@Entity</code> structure</p>
  
  <pre><code>@Entity
  class Root {
  
      @Id
      private Long id;
  
      @OneToMany
      @JoinColumn(name = "root_id")
      private Set&lt;Child&gt; children
  }
  
  @Entity
  class Child {
  
      @Id
      private Long id;
  
      @OneToMany
      @JoinColumn(name = "child_id")
      private Set&lt;Grandchild&gt; grandchildren;
  }
  
  @Entity
  class Grandchild {
  
      @Id
      private Long id;
  }
  </code></pre>
  
  <p>When I query for all/specific <code>Root</code> objects Hibernate selects only from the corresponding table and the resulting objects' <code>children</code> Set is <del><code>null</code></del> a Hibernate proxy - as it should be.</p>
  
  <p>When I call <code>getChildren()</code> Hibernate correctly initializes the collection but also (unwarrantedly) fetches each <code>Child</code> object's <code>grandchildren</code> Set.</p>
  
  <p>Can someone please explain exactly why this recursive fetching is happening and is there a way to disable it?</p>
  
  <hr/>
  
  <p>I did some more digging and this is what I came up with: it seems to be related to the way Hibernate maps <code>@OneToMany</code> depending on whether the target collection is a <code>List</code> or <code>Set</code>.</p>
  
  <pre><code>private final RootRepo repo;
  </code></pre>
  
  <p>If the collections are <code>Set</code>s</p>
  
  <pre><code>public void test() {
      List&lt;Root&gt; all = repo.findAll(); // SELECT root0_.* FROM root root0_
  
      all.forEach(root -&gt; {
          System.out.println(root.getChildren() == null); // false
          System.out.println(Hibernate.isInitialized(root.getChildren())); // false
  
          root.getChildren().forEach(child -&gt; {
              // SELECT child0_.* FROM children child0_
              // SELECT grandchild0_.* FROM grandchildren grandchild0_
              System.out.println(child.getGrandchildren() == null); // false
              System.out.println(Hibernate.isInitialized(child.getGrandchildren())); // true
  
              child.getGrandChildren().forEach(grandchild -&gt; {});
          });
      });
  }
  </code></pre>
  
  <p><strong>However</strong>, with <code>List</code>s</p>
  
  <pre><code>public void test() {
      List&lt;Root&gt; all = repo.findAll(); // SELECT root0_.* FROM root root0_
  
      all.forEach(root -&gt; {
          System.out.println(root.getChildren() == null); // false
          System.out.println(Hibernate.isInitialized(root.getChildren())); // false
  
          root.getChildren().forEach(child -&gt; {
              // SELECT child0_.* FROM children child0_
              System.out.println(child.getGrandchildren() == null); // false
              System.out.println(Hibernate.isInitialized(child.getGrandchildren())); // false
  
              child.getGrandChildren().forEach(grandchild -&gt; {
                  // SELECT grandchild0_.* FROM grandchildren grandchild0_
              });
          });
      });
  }
  </code></pre>
  
  <hr/>
  
  <p>I am a certifiable idiot.  </p>
  
  <p>I'm using Lombok to generate getters/setters and the like for my <em>POJO</em>s and its default implementation of <code>@EqualsAndHashCode</code> annotation generates both methods taking into account every field.. including the subcollections.</p>