protected void createFromJoinElement(
      AST path, AST alias, int joinType, AST fetchNode, AST propertyFetch, AST with)
      throws SemanticException {
    boolean fetch = fetchNode != null;
    if (fetch && isSubQuery()) {
      throw new QueryException("fetch not allowed in subquery from-elements");
    }
    // The path AST should be a DotNode, and it should have been evaluated already.
    if (path.getType() != SqlTokenTypes.DOT) {
      throw new SemanticException("Path expected for join!");
    }
    DotNode dot = (DotNode) path;
    int hibernateJoinType = JoinProcessor.toHibernateJoinType(joinType);
    dot.setJoinType(hibernateJoinType); // Tell the dot node about the join type.
    dot.setFetch(fetch);
    // Generate an explicit join for the root dot node.   The implied joins will be collected and
    // passed up
    // to the root dot node.
    dot.resolve(true, false, alias == null ? null : alias.getText());
    FromElement fromElement = dot.getImpliedJoin();
    fromElement.setAllPropertyFetch(propertyFetch != null);

    if (with != null) {
      if (fetch) {
        throw new SemanticException("with-clause not allowed on fetched associations; use filters");
      }
      handleWithFragment(fromElement, with);
    }

    if (log.isDebugEnabled()) {
      log.debug(
          "createFromJoinElement() : "
              + getASTPrinter().showAsString(fromElement, "-- join tree --"));
    }
  }