title: Spring Data JPA: Creating Specification Query Fetch Joins
body: <p><strong>TL;DR</strong>: How do you replicate JPQL Join-Fetch operations using specifications in Spring Data JPA?</p>
  
  <p>I am trying to build a class that will handle dynamic query building for JPA entities using Spring Data JPA.  To do this, I am defining a number of methods that create <code>Predicate</code> objects (such as is suggested in the <a href="http://docs.spring.io/spring-data/jpa/docs/1.8.0.RELEASE/reference/html/#specifications" rel="noreferrer">Spring Data JPA docs</a> and elsewhere), and then chaining them when the appropriate query parameter is submitted.  Some of my entities have one-to-many relationships with other entities that help describe them, which are eagerly fetched when queried and coalesced into collections or maps for DTO creation. A simplified example:</p>
  
  <pre><code>@Entity
  public class Gene {
  
      @Id 
      @Column(name="entrez_gene_id")
      privateLong id;
  
      @Column(name="gene_symbol")
      private String symbol;
  
      @Column(name="species")
      private String species;
  
      @OneToMany(mappedBy="gene", fetch=FetchType.EAGER) 
      private Set&lt;GeneSymbolAlias&gt; aliases;
  
      @OneToMany(mappedBy="gene", fetch=FetchType.EAGER) 
      private Set&lt;GeneAttributes&gt; attributes;
  
      // etc...
  
  }
  
  @Entity
  public class GeneSymbolAlias {
  
      @Id 
      @Column(name = "alias_id")
      private Long id;
  
      @Column(name="gene_symbol")
      private String symbol;
  
      @ManyToOne(fetch=FetchType.LAZY) 
      @JoinColumn(name="entrez_gene_id")
      private Gene gene;
  
      // etc...
  
  }
  </code></pre>
  
  <p>Query string parameters are passed from the <code>Controller</code> class to the <code>Service</code> class as key-value pairs, where they are processed and assembled into <code>Predicates</code>:</p>
  
  <pre><code>@Service
  public class GeneService {
  
      @Autowired private GeneRepository repository;
      @Autowired private GeneSpecificationBuilder builder;
  
      public List&lt;Gene&gt; findGenes(Map&lt;String,Object&gt; params){
          return repository.findAll(builder.getSpecifications(params));
      }
  
      //etc...
  
  }
  
  @Component
  public class GeneSpecificationBuilder {
  
      public Specifications&lt;Gene&gt; getSpecifications(Map&lt;String,Object&gt; params){
          Specifications&lt;Gene&gt; = null;
          for (Map.Entry param: params.entrySet()){
              Specification&lt;Gene&gt; specification = null;
              if (param.getKey().equals("symbol")){
                  specification = symbolEquals((String) param.getValue());
              } else if (param.getKey().equals("species")){
                  specification = speciesEquals((String) param.getValue());
              } //etc
              if (specification != null){
                 if (specifications == null){
                     specifications = Specifications.where(specification);
                 } else {
                     specifications.and(specification);
                 }
              }
          } 
          return specifications;
      }
  
      private Specification&lt;Gene&gt; symbolEquals(String symbol){
          return new Specification&lt;Gene&gt;(){
              @Override public Predicate toPredicate(Root&lt;Gene&gt; root, CriteriaQuery&lt;?&gt; query, CriteriaBuilder builder){
                  return builder.equal(root.get("symbol"), symbol);
              }
          };
      }
  
      // etc...
  
  }
  </code></pre>
  
  <p>In this example, every time I want to retrieve a <code>Gene</code> record, I also want its associated <code>GeneAttribute</code> and <code>GeneSymbolAlias</code> records.  This all works as expected, and a request for a single <code>Gene</code> will fire off 3 queries: one each to the <code>Gene</code>, <code>GeneAttribute</code>, and <code>GeneSymbolAlias</code> tables.  </p>
  
  <p>The problem is that there is no reason that 3 queries need to run to get a single <code>Gene</code> entity with embedded attributes and aliases.  This can be done in plain SQL, and it can be done with a JPQL query in my Spring Data JPA repository:</p>
  
  <pre><code>@Query(value = "select g from Gene g left join fetch g.attributes join fetch g.aliases where g.symbol = ?1 order by g.entrezGeneId")
  List&lt;Gene&gt; findBySymbol(String symbol);
  </code></pre>
  
  <p>How can I replicate this fetching strategy using Specifications?  I found <a href="https://stackoverflow.com/questions/15482235/spring-data-jpa-fetching">this question here</a>, but it only seems to make lazy fetches into eager fetches.</p>