title: Specification/Predicate to Search Nested Objects
body: <p>I'm using Spring Boot with Spring JPA and Specification Executor. I have my Specification/Predicate combo successfully searching the simple attributes within my class. However, I am having difficulties searching the objects within. Do they need a separate Specification? I have a class that has 2 Many To One mapping classes within and would like to search those fields from within the same class.</p>
  
  <p>Predicate Implementation</p>
  
  <pre><code>public Specification&lt;User&gt; getSpecification(SpecificationField field, Object searchCriteria){
      return new Specification&lt;User&gt;() {
      @Override
      public Predicate toPredicate(Root&lt;User&gt; root, CriteriaQuery&lt;?&gt; query, CriteriaBuilder cb) {
  
      if(searchCriteria instanceof String){
          searchCriteria.toString().trim().toLowerCase();
      }
  
      switch(field){
      case USER_GROUP:    
          return cb.equal(cb.lower(root.&lt;String&gt; get("group").get("name")), searchCriteria);
      case USER_ROLE: 
          return cb.equal(cb.lower(root.&lt;String&gt; get("role").get("name")), searchCriteria);
      case USER_EMAIL: 
          return cb.equal(cb.lower(root.&lt;String&gt; get("email")), searchCriteria);
      case USER_FIRSTNAME: 
          return cb.equal(cb.lower(root.&lt;String&gt; get("firstName")), searchCriteria);
      case USER_LASTNAME: 
          return cb.equal(cb.lower(root.&lt;String&gt; get("lastName")), searchCriteria);
      case USER_USERNAME: 
          return cb.equal(cb.lower(root.&lt;String&gt; get("username")), searchCriteria);
      default:
          assert true;
          return null;
      }
  </code></pre>
  
  <hr>
  
  <p>User Class</p>
  
  <pre><code>@Id
  @GeneratedValue
  @Column(name = "USER_ID")
  private Long id;
  
  @Column(name = "USER_FIRSTNAME", nullable = false)
  private String firstName;
  
  @Column(name = "USER_LASTNAME", nullable = false)
  private String lastName;
  
  @Column(name = "USER_EMAIL", nullable = false, unique = true)
  private String email;
  
  @Column(name = "USER_USERNAME", nullable = false, unique = true)
  private String username;
  
  @Column(name = "USER_PASSWORD", nullable = false)
  private String encryptedPassword;
  
  @ManyToOne
  @JoinColumn(name = "USER_ROLE", nullable = false)
  private Role role;
  
  @ManyToOne
  @JoinColumn(name = "USER_GROUP", nullable = false)
  private Group group;
  </code></pre>
  
  <hr>
  
  <p>Role Class</p>
  
  <pre><code>@Id
  @GeneratedValue
  @Column(name = "ROLE_ID")
  private Long id;
  
  @Column(name = "ROLE_NAME", nullable = false, unique = true)
  private String name;
  </code></pre>
  
  <hr>
  
  <p>Group Class</p>
  
  <pre><code>@Id
  @GeneratedValue
  @Column(name = "GROUP_ID")
  private Long id;
  
  @Column(name = "GROUP_NAME", nullable = false, unique = true)
  private String name;
  
  @Column(name = "GROUP_TOKEN", nullable = false, unique = true)
  private String token;
  </code></pre>
  
  <h2>--------------------------------------------------------------------------</h2>
  
  <p>EDIT: </p>
  
  <p>Came up with this Predicate implementation for the nested objects.</p>
  
  <pre><code>Root&lt;Group&gt; group = query.from(Group.class);
  Root&lt;Role&gt; role = query.from(Role.class);
  
  switch(field){
  case USER_GROUP:
      return cb.equal(cb.lower(group.&lt;String&gt; get("name")), searchCriteria);
  case USER_ROLE: 
      return cb.equal(cb.lower(role.&lt;String&gt; get("name")), searchCriteria);
  </code></pre>
  
  <p>This is working better, but not great. I have the possible group name values of DEV, UAT, or PROD. If I give any of these I get all the Users in my Database. If I don't I don't get any Users back. How can I do a text search on the name of this nested object? </p>
  
  <p>Thanks.</p>