org.hibernate.engine.jdbc.internal.BasicFormatterImplの改修について


現在、org.hibernate.engine.jdbc.internal.BasicFormatterImplを使用してSQL文にフォーマットをかけようとしています  
自分の作成したコードは以下です。（一部抜粋）  
inputに以下を渡しました。

[code]

    INSERT INTO table_name (US_id,List_id,sort1) VALUES (':US_ID',':LIST_ID',':SORT1')
    
[/code]

javaでの実際の呼び出し元

[code]

        String formattedSql = customSqlFormatter(sql);
    
        private static String customSqlFormatter(String sql) {
            // 実装を追加してSQLを抽出
            BasicFormatterImpl formatter = new BasicFormatterImpl();
            return formatter.format(sql);
        }
    
[/code]

結果は以下のようになってしまいます。

[code]

    INSERT
    INTO
    table_name
    (US_id,List_id,sort1)
    VALUES
    (':US_ID',':LIST_ID',':SORT1')
    
[/code]

期待値としては以下になるかと思っていました。どのように修正したらいいでしょうか。

また、カンマを先頭で改行した場合もどのように修正を入れたらよいでしょうか。  
ご教授お願いします。

[code]

    INSERT
    INTO
    table_name
    (US_id,
    List_id,
    sort1)
    VALUES
    (':US_ID',
    ':LIST_ID',
    ':SORT1')
    
[/code]

また、カンマを先頭で改行した場合もどのように修正を入れたらよいでしょうか。  
ご教授お願いします。

rg.hibernate.engine.jdbc.internal.BasicFormatterImplの詳細は以下になります。

[code]

    /*
     * Hibernate, Relational Persistence for Idiomatic Java
     *
     * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
     * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
     */
    package org.hibernate.engine.jdbc.internal;
    
    import java.util.HashSet;
    import java.util.LinkedList;
    import java.util.Locale;
    import java.util.Set;
    import java.util.StringTokenizer;
    
    import org.hibernate.internal.util.StringHelper;
    
    /**
     * Performs formatting of basic SQL statements (DML + query).
     *
     * @author Gavin King
     * @author Steve Ebersole
     */
    public class BasicFormatterImpl implements Formatter {
    
        private static final Set<String> BEGIN_CLAUSES = new HashSet<String>();
        private static final Set<String> END_CLAUSES = new HashSet<String>();
        private static final Set<String> LOGICAL = new HashSet<String>();
        private static final Set<String> QUANTIFIERS = new HashSet<String>();
        private static final Set<String> DML = new HashSet<String>();
        private static final Set<String> MISC = new HashSet<String>();
    
        static {
            BEGIN_CLAUSES.add("left");
            BEGIN_CLAUSES.add("right");
            BEGIN_CLAUSES.add("inner");
            BEGIN_CLAUSES.add("outer");
            BEGIN_CLAUSES.add("group");
            BEGIN_CLAUSES.add("order");
    
            END_CLAUSES.add("where");
            END_CLAUSES.add("set");
            END_CLAUSES.add("having");
            END_CLAUSES.add("from");
            END_CLAUSES.add("by");
            END_CLAUSES.add("join");
            END_CLAUSES.add("into");
            END_CLAUSES.add("union");
    
            LOGICAL.add("and");
            LOGICAL.add("or");
            LOGICAL.add("when");
            LOGICAL.add("else");
            LOGICAL.add("end");
    
            QUANTIFIERS.add("in");
            QUANTIFIERS.add("all");
            QUANTIFIERS.add("exists");
            QUANTIFIERS.add("some");
            QUANTIFIERS.add("any");
    
            DML.add("insert");
            DML.add("update");
            DML.add("delete");
    
            MISC.add("select");
            MISC.add("on");
        }
    
        private static final String INDENT_STRING = "    ";
        private static final String INITIAL = System.lineSeparator() + INDENT_STRING;
    
        @Override
        public String format(String source) {
            return new FormatProcess(source).perform();
        }
    
        private static class FormatProcess {
            boolean beginLine = true;
            boolean afterBeginBeforeEnd;
            boolean afterByOrSetOrFromOrSelect;
            boolean afterOn;
            boolean afterBetween;
            boolean afterInsert;
            int inFunction;
            int parensSinceSelect;
            private LinkedList<Integer> parenCounts = new LinkedList<Integer>();
            private LinkedList<Boolean> afterByOrFromOrSelects = new LinkedList<Boolean>();
    
            int indent = 1;
    
            StringBuilder result = new StringBuilder();
            StringTokenizer tokens;
            String lastToken;
            String token;
            String lcToken;
    
            public FormatProcess(String sql) {
                tokens = new StringTokenizer(sql, "()+*/-=<>'`\"[]," + StringHelper.WHITESPACE, true);
            }
    
            public String perform() {
    
                result.append(INITIAL);
    
                while (tokens.hasMoreTokens()) {
                    token = tokens.nextToken();
                    lcToken = token.toLowerCase(Locale.ROOT);
    
                    if ("'".equals(token)) {
                        String t;
                        do {
                            t = tokens.nextToken();
                            token += t;
                        }
                        // cannot handle single quotes
                        while (!"'".equals(t) && tokens.hasMoreTokens());
                    } else if ("\"".equals(token)) {
                        String t;
                        do {
                            t = tokens.nextToken();
                            token += t;
                        } while (!"\"".equals(t) && tokens.hasMoreTokens());
                    }
                    // SQL Server uses "[" and "]" to escape reserved words
                    // see SQLServerDialect.openQuote and SQLServerDialect.closeQuote
                    else if ("[".equals(token)) {
                        String t;
                        do {
                            t = tokens.nextToken();
                            token += t;
                        } while (!"]".equals(t) && tokens.hasMoreTokens());
                    }
    
                    if (afterByOrSetOrFromOrSelect && ",".equals(token)) {
                        commaAfterByOrFromOrSelect();
                    } else if (afterOn && ",".equals(token)) {
                        commaAfterOn();
                    }
    
                    else if ("(".equals(token)) {
                        openParen();
                    } else if (")".equals(token)) {
                        closeParen();
                    }
    
                    else if (BEGIN_CLAUSES.contains(lcToken)) {
                        beginNewClause();
                    }
    
                    else if (END_CLAUSES.contains(lcToken)) {
                        endNewClause();
                    }
    
                    else if ("select".equals(lcToken)) {
                        select();
                    }
    
                    else if (DML.contains(lcToken)) {
                        updateOrInsertOrDelete();
                    }
    
                    else if ("values".equals(lcToken)) {
                        values();
                    }
    
                    else if ("on".equals(lcToken)) {
                        on();
                    }
    
                    else if (afterBetween && lcToken.equals("and")) {
                        misc();
                        afterBetween = false;
                    }
    
                    else if (LOGICAL.contains(lcToken)) {
                        logical();
                    }
    
                    else if (isWhitespace(token)) {
                        white();
                    }
    
                    else {
                        misc();
                    }
    
                    if (!isWhitespace(token)) {
                        lastToken = lcToken;
                    }
    
                }
                return result.toString();
            }
    
            private void commaAfterOn() {
                out();
                indent--;
                newline();
                afterOn = false;
                afterByOrSetOrFromOrSelect = true;
            }
    
            private void commaAfterByOrFromOrSelect() {
                out();
                newline();
            }
    
            private void logical() {
                if ("end".equals(lcToken)) {
                    indent--;
                }
                newline();
                out();
                beginLine = false;
            }
    
            private void on() {
                indent++;
                afterOn = true;
                newline();
                out();
                beginLine = false;
            }
    
            private void misc() {
                out();
                if ("between".equals(lcToken)) {
                    afterBetween = true;
                }
                if (afterInsert) {
                    newline();
                    afterInsert = false;
                } else {
                    beginLine = false;
                    if ("case".equals(lcToken)) {
                        indent++;
                    }
                }
            }
    
            private void white() {
                if (!beginLine) {
                    result.append(" ");
                }
            }
    
            private void updateOrInsertOrDelete() {
                out();
                indent++;
                beginLine = false;
                if ("update".equals(lcToken)) {
                    newline();
                }
                if ("insert".equals(lcToken)) {
                    afterInsert = true;
                }
            }
    
            private void select() {
                out();
                indent++;
                newline();
                parenCounts.addLast(parensSinceSelect);
                afterByOrFromOrSelects.addLast(afterByOrSetOrFromOrSelect);
                parensSinceSelect = 0;
                afterByOrSetOrFromOrSelect = true;
            }
    
            private void out() {
                result.append(token);
            }
    
            private void endNewClause() {
                if (!afterBeginBeforeEnd) {
                    indent--;
                    if (afterOn) {
                        indent--;
                        afterOn = false;
                    }
                    newline();
                }
                out();
                if (!"union".equals(lcToken)) {
                    indent++;
                }
                newline();
                afterBeginBeforeEnd = false;
                afterByOrSetOrFromOrSelect = "by".equals(lcToken) || "set".equals(lcToken) || "from".equals(lcToken);
            }
    
            private void beginNewClause() {
                if (!afterBeginBeforeEnd) {
                    if (afterOn) {
                        indent--;
                        afterOn = false;
                    }
                    indent--;
                    newline();
                }
                out();
                beginLine = false;
                afterBeginBeforeEnd = true;
            }
    
            private void values() {
                indent--;
                newline();
                out();
                indent++;
                newline();
            }
    
            private void closeParen() {
                parensSinceSelect--;
                if (parensSinceSelect < 0) {
                    indent--;
                    parensSinceSelect = parenCounts.removeLast();
                    afterByOrSetOrFromOrSelect = afterByOrFromOrSelects.removeLast();
                }
                if (inFunction > 0) {
                    inFunction--;
                    out();
                } else {
                    if (!afterByOrSetOrFromOrSelect) {
                        indent--;
                        newline();
                    }
                    out();
                }
                beginLine = false;
            }
    
            private void openParen() {
                if (isFunctionName(lastToken) || inFunction > 0) {
                    inFunction++;
                }
                beginLine = false;
                if (inFunction > 0) {
                    out();
                } else {
                    out();
                    if (!afterByOrSetOrFromOrSelect) {
                        indent++;
                        newline();
                        beginLine = true;
                    }
                }
                parensSinceSelect++;
            }
    
            private static boolean isFunctionName(String tok) {
                if (tok == null || tok.length() == 0) {
                    return false;
                }
    
                final char begin = tok.charAt(0);
                final boolean isIdentifier = Character.isJavaIdentifierStart(begin) || '"' == begin;
                return isIdentifier && !LOGICAL.contains(tok) && !END_CLAUSES.contains(tok)
                        && !QUANTIFIERS.contains(tok) && !DML.contains(tok) && !MISC.contains(tok);
            }
    
            private static boolean isWhitespace(String token) {
                return StringHelper.WHITESPACE.contains(token);
            }
    
            private void newline() {
                result.append(System.lineSeparator());
                for (int i = 0; i < indent; i++) {
                    result.append(INDENT_STRING);
                }
                beginLine = true;
            }
        }
    
    }
    
[/code]




package名に `internal` とある通り、外部に公開することを意図したクラスでなく、希望されているようなカスタマイズ性は無さそうなので無理です。




package名に `internal` とある通り、外部に公開することを意図したクラスでなく、希望されているようなカスタマイズ性は無さそうなので無理です。

