/**
  * Check if one of the parents in the hierarchy for this join is a propertyPath-less parent before
  * reaching the root.
  *
  * <p>In Hibernate 5.1.0, the hql is not properly converted to sql when such a case exists.
  */
 private boolean isChildOfClassJoin(TypeSafeQueryJoin<?> join) {
   TypeSafeQueryProxyData data = join.getData();
   while (data.getParent() != null) {
     TypeSafeQueryProxyData parent = data.getParent();
     if (parent.getParent() == null) {
       // root found, no class join in between
       return false;
     } else if (parent.getPropertyPath() == null) {
       // property path -less parent found before root
       // this is a class join
       return true;
     }
     data = parent;
   }
   return false;
 }
  /**
   * Create a join on for a property joined entity which is the child of a class joined entity. This
   * is a work around because hibernate doesn't properly convert the hql to sql in this case. (the
   * hql looks fine, but the sql throws an SqlGrammarException and the sql property join is missing)
   */
  private void appendPropertyAsClassJoin(
      HqlQueryValueImpl from, TypeSafeQueryJoin<?> join, HqlQueryBuilderParams params) {
    // example: 'left join Product hobj1 on ...'
    TypeSafeQueryProxyData data = join.getData();
    String alias = data.getAlias();
    StringBuilder joinSB =
        new StringBuilder(" ")
            .append(getJoinTypeString(data.getEffectiveJoinType()))
            .append(" ")
            .append(helper.getEntityName(data.getPropertyType()))
            .append(" ")
            .append(alias)
            .append(" on ");
    if (data.getProxyType().isCollection()) {
      String parentId = data.getParent().getIdentifierPath();
      // parent.parentIdentifier = child.parentPath.parentIdentifier
      String mappedByProperty = helper.getMappedByProperty(data);
      joinSB
          .append(data.getParent().getAlias())
          .append(".")
          .append(parentId)
          .append(" = ")
          .append(alias)
          .append(".")
          .append(mappedByProperty)
          .append(".")
          .append(parentId);
    } else {
      String childId = data.getIdentifierPath();
      // child.childIdentifier = parent.childPath.childIdentifier
      joinSB
          .append(alias)
          .append(".")
          .append(childId)
          .append(" = ")
          .append(data.getParent().getAlias())
          .append(".")
          .append(data.getPropertyPath())
          .append(".")
          .append(childId);
    }
    from.appendHql(joinSB.toString());

    // append additional "with" restrictions if such exist (continue after identity restriction):
    appendAdditionalRestrictions(from, join, " and ", params);
  }
  private void appendPropertyJoin(
      HqlQueryValueImpl from, TypeSafeQueryJoin<?> join, HqlQueryBuilderParams params) {
    TypeSafeQueryProxyData data = join.getData();
    // example: 'left join fetch' 'hobj1'.'propertyPath' 'hobj2'
    from.appendHql(
        new StringBuilder(" ")
            .append(getJoinTypeString(data.getEffectiveJoinType()))
            .append(" ")
            .append(data.getParent().getAlias())
            .append(".")
            .append(data.getPropertyPath())
            .append(" ")
            .append(data.getAlias())
            .toString());

    // append additional "with" restrictions if such exist:
    appendAdditionalRestrictions(from, join, " with ", params);
  }