title: Specifications and (null) Many-To-One Relationship
body: <p>I have an MVC Controller that return a List of Contacts as JSON. On frontend side i use jquery datatables plugin. There is a searchfield on the frontend to filter the entity list.</p>
  
  <p>my entities:</p>
  
  <pre><code>@Entity
  public class Contact implements Serializable {
  
      protected final static Logger   LOGGER              = LoggerFactory.getLogger(Contact.class);
  
      private static final long       serialVersionUID    = -3691953100225344828L;
  
      @Id
      @GeneratedValue(generator = "hibernate-uuid")
      @Column(length = 36, unique = true)
      private String                  id;
  
      @Version
      @JsonIgnore
      private int                     version;
  
      private String                  firstname;
      private String                  lastname;
  
      @ManyToOne
      private Company                 company;
  
      ... GETTER/SETTER ...
  }
  </code></pre>
  
  <p>and</p>
  
  <pre><code>@Entity
  public class Company implements Serializable {
  
      protected final static Logger   LOGGER              = LoggerFactory.getLogger(Company.class);
  
      private static final long       serialVersionUID    = -7863930456400256944L;
  
      @Id
      @GeneratedValue(generator = "hibernate-uuid")
      @Column(length = 36, unique = true)
      private String                  id;
  
      private String                  companyName;
      private String                  companyName1;
      private String                  companyName2;
  
      ... GETTER/SETTER ...
  }
  </code></pre>
  
  <p>I use server side processing for the search field and on server side i use specifications.</p>
  
  <pre><code>public class ContactSpecifications {
  
      public static Specification&lt;Contact&gt; contactFirstnameLike(final String needle) {
          return new Specification&lt;Contact&gt;() {
  
              @Override
              public Predicate toPredicate(Root&lt;Contact&gt; root, CriteriaQuery&lt;?&gt; query, CriteriaBuilder cb) {
                  return cb.like(cb.lower(root.&lt;String&gt; get(Contact_.firstname)), needle != null ? needle.toLowerCase() : null);
              }
          };
      }
  
      public static Specification&lt;Contact&gt; contactLastnameLike(final String needle) {
          return new Specification&lt;Contact&gt;() {
  
              @Override
              public Predicate toPredicate(Root&lt;Contact&gt; root, CriteriaQuery&lt;?&gt; query, CriteriaBuilder cb) {
                  return cb.like(cb.lower(root.&lt;String&gt; get(Contact_.lastname)), needle != null ? needle.toLowerCase() : null);
              }
          };
      }
  
      public static Specification&lt;Contact&gt; contactFullnameLike(final String needle) {
          return new Specification&lt;Contact&gt;() {
  
              @Override
              public Predicate toPredicate(Root&lt;Contact&gt; root, CriteriaQuery&lt;?&gt; query, CriteriaBuilder cb) {
                  return cb.or(cb.like(cb.lower(root.&lt;String&gt; get(Contact_.lastname)), needle != null ? needle.toLowerCase() : null), cb.like(cb.lower(root.&lt;String&gt; get(Contact_.firstname)), needle != null ? needle.toLowerCase() : null));
              }
          };
      }
  
      public static Specification&lt;Contact&gt; contactCompanyCompanyNameLike(final String needle) {
          return new Specification&lt;Contact&gt;() {
  
              @Override
              public Predicate toPredicate(Root&lt;Contact&gt; root, CriteriaQuery&lt;?&gt; query, CriteriaBuilder cb) {
                  final Path&lt;Company&gt; company = root.&lt;Company&gt; get(Contact_.company);
                  return cb.like(cb.lower(company.&lt;String&gt; get(Company_.companyName)), needle != null ? needle.toLowerCase() : null);
              }
          };
      }
  }
  </code></pre>
  
  <p>My db query</p>
  
  <pre><code> contactRepository.findAll(specifications, new PageRequest(0,100));
  </code></pre>
  
  <p>and specifications are</p>
  
  <pre><code> specifications = Specifications.where(ContactSpecifications.contactFullnameLike(needle)).or(ContactSpecifications.contactCompanyCompanyNameLike(needle));
  </code></pre>
  
  <p>needle is the search key from the frontend and mask with surrounding % (for example "%asdf%")</p>
  
  <p>My problem is, if the contact has no company the specifications not working as expected.</p>
  
  <p>For example i have 3 Contacts:</p>
  
  <ol>
  <li>Lastname: Schmitz, Firstname: Max, Company: (null)</li>
  <li>Lastname: Schmitz, Firstname: Moritz, Company: XY</li>
  <li><p>Lastname: Muster, Firstname: Max, Company: XY</p>
  
  <ul>
  <li>If i now enter Schmitz as search key, only contact 2 returned, contact 1 not.</li>
  <li>If i enter max as search key, only contact 3 returned, contact 1 not</li>
  <li>Only if the search key is null/empty, all contacts returned</li>
  </ul></li>
  </ol>
  
  <p>I miss something?</p>
  
  <p>kind regards
  Rizzi</p>