public void serializeUnion(Expression<?> union, QueryMetadata metadata, boolean unionAll) {
        final List<? extends Expression<?>> groupBy = metadata.getGroupBy();
        final Predicate having = metadata.getHaving();
        final List<OrderSpecifier<?>> orderBy = metadata.getOrderBy();
        final Set<QueryFlag> flags = metadata.getFlags();
        final boolean hasFlags = !flags.isEmpty();

        // with
        if (hasFlags) {
            boolean handled = false;
            boolean recursive = false;
            for (QueryFlag flag : flags) {
                if (flag.getPosition() == Position.WITH) {
                    if (flag.getFlag() == SQLTemplates.RECURSIVE) {
                        recursive = true;
                        continue;
                    }
                    if (handled) {
                        append(", ");
                    }
                    handle(flag.getFlag());
                    handled = true;
                }
            }
            if (handled) {
                if (recursive) {
                    prepend(templates.getWithRecursive());
                } else {
                    prepend(templates.getWith());
                }
                append("\n");
            }
        }

        // union
        Stage oldStage = stage;
        handle(union);

        // group by
        if (hasFlags) {
            serialize(Position.BEFORE_GROUP_BY, flags);
        }
        if (!groupBy.isEmpty()) {
            stage = Stage.GROUP_BY;
            append(templates.getGroupBy()).handle(COMMA, groupBy);
        }
        if (hasFlags) {
            serialize(Position.AFTER_GROUP_BY, flags);
        }

        // having
        if (hasFlags) {
            serialize(Position.BEFORE_HAVING, flags);
        }
        if (having != null) {
            stage = Stage.HAVING;
            append(templates.getHaving()).handle(having);
        }
        if (hasFlags) {
            serialize(Position.AFTER_HAVING, flags);
        }

        // order by
        if (hasFlags) {
            serialize(Position.BEFORE_ORDER, flags);
        }
        if (!orderBy.isEmpty()) {
            stage = Stage.ORDER_BY;
            append(templates.getOrderBy());
            skipParent = true;
            handleOrderBy(orderBy);
            skipParent = false;
        }
        if (hasFlags) {
            serialize(Position.AFTER_ORDER, flags);
        }

        // end
        if (hasFlags) {
            serialize(Position.END, flags);
        }

        // reset stage
        stage = oldStage;
    }
Return a list of expressions that can be used to uniquely define the query sources

@param joins
@return identifier columns
querydsl-sql/src/main/java/com/querydsl/sql/SQLSerializer.java