HHH-12511 Make ASTPrinter threadsafe and have code reuse their instances

This commit is contained in:
Sanne Grinovero 2018-04-12 18:40:31 +01:00
parent 782f023a5a
commit 0546eaac3b
11 changed files with 56 additions and 69 deletions

View File

@ -20,6 +20,7 @@ import org.hibernate.hql.internal.antlr.HqlBaseParser;
import org.hibernate.hql.internal.antlr.HqlTokenTypes; import org.hibernate.hql.internal.antlr.HqlTokenTypes;
import org.hibernate.hql.internal.ast.util.ASTPrinter; import org.hibernate.hql.internal.ast.util.ASTPrinter;
import org.hibernate.hql.internal.ast.util.ASTUtil; import org.hibernate.hql.internal.ast.util.ASTUtil;
import org.hibernate.hql.internal.ast.util.TokenPrinters;
import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
@ -41,11 +42,6 @@ public final class HqlParser extends HqlBaseParser {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( HqlParser.class ); private static final CoreMessageLogger LOG = CoreLogging.messageLogger( HqlParser.class );
private final ParseErrorHandler parseErrorHandler; private final ParseErrorHandler parseErrorHandler;
private final ASTPrinter printer = getASTPrinter();
private static ASTPrinter getASTPrinter() {
return new ASTPrinter( org.hibernate.hql.internal.antlr.HqlTokenTypes.class );
}
/** /**
* Get a HqlParser instance for the given HQL string. * Get a HqlParser instance for the given HQL string.
@ -362,7 +358,7 @@ public final class HqlParser extends HqlBaseParser {
} }
private void showAst(AST ast, PrintWriter pw) { private void showAst(AST ast, PrintWriter pw) {
printer.showAst( ast, pw ); TokenPrinters.HQL_TOKEN_PRINTER.showAst( ast, pw );
} }
@Override @Override

View File

@ -65,6 +65,7 @@ import org.hibernate.hql.internal.ast.util.LiteralProcessor;
import org.hibernate.hql.internal.ast.util.NodeTraverser; import org.hibernate.hql.internal.ast.util.NodeTraverser;
import org.hibernate.hql.internal.ast.util.SessionFactoryHelper; import org.hibernate.hql.internal.ast.util.SessionFactoryHelper;
import org.hibernate.hql.internal.ast.util.SyntheticAndFactory; import org.hibernate.hql.internal.ast.util.SyntheticAndFactory;
import org.hibernate.hql.internal.ast.util.TokenPrinters;
import org.hibernate.hql.spi.QueryTranslator; import org.hibernate.hql.spi.QueryTranslator;
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator; import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.IdentifierGenerator;
@ -118,7 +119,6 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
private final AliasGenerator aliasGenerator = new AliasGenerator(); private final AliasGenerator aliasGenerator = new AliasGenerator();
private final LiteralProcessor literalProcessor; private final LiteralProcessor literalProcessor;
private final ParseErrorHandler parseErrorHandler; private final ParseErrorHandler parseErrorHandler;
private final ASTPrinter printer;
private final String collectionFilterRole; private final String collectionFilterRole;
private FromClause currentFromClause; private FromClause currentFromClause;
@ -171,7 +171,6 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
this.tokenReplacements = tokenReplacements; this.tokenReplacements = tokenReplacements;
this.collectionFilterRole = collectionRole; this.collectionFilterRole = collectionRole;
this.hqlParser = parser; this.hqlParser = parser;
this.printer = new ASTPrinter( SqlTokenTypes.class );
} }
// handle trace logging ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // handle trace logging ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -194,7 +193,7 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
private String buildTraceNodeName(AST tree) { private String buildTraceNodeName(AST tree) {
return tree == null return tree == null
? "???" ? "???"
: tree.getText() + " [" + printer.getTokenTypeName( tree.getType() ) + "]"; : tree.getText() + " [" + TokenPrinters.SQL_TOKEN_PRINTER.getTokenTypeName( tree.getType() ) + "]";
} }
@Override @Override
@ -1337,7 +1336,7 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
} }
public ASTPrinter getASTPrinter() { public ASTPrinter getASTPrinter() {
return printer; return TokenPrinters.SQL_TOKEN_PRINTER;
} }
public ArrayList<ParameterSpecification> getParameterSpecs() { public ArrayList<ParameterSpecification> getParameterSpecs() {

View File

@ -42,6 +42,7 @@ import org.hibernate.hql.internal.ast.tree.UpdateStatement;
import org.hibernate.hql.internal.ast.util.ASTPrinter; import org.hibernate.hql.internal.ast.util.ASTPrinter;
import org.hibernate.hql.internal.ast.util.ASTUtil; import org.hibernate.hql.internal.ast.util.ASTUtil;
import org.hibernate.hql.internal.ast.util.NodeTraverser; import org.hibernate.hql.internal.ast.util.NodeTraverser;
import org.hibernate.hql.internal.ast.util.TokenPrinters;
import org.hibernate.hql.spi.FilterTranslator; import org.hibernate.hql.spi.FilterTranslator;
import org.hibernate.hql.spi.ParameterTranslations; import org.hibernate.hql.spi.ParameterTranslations;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
@ -262,8 +263,6 @@ public class QueryTranslatorImpl implements FilterTranslator {
} }
} }
private static final ASTPrinter SQL_TOKEN_PRINTER = new ASTPrinter( SqlTokenTypes.class );
private HqlSqlWalker analyze(HqlParser parser, String collectionRole) throws QueryException, RecognitionException { private HqlSqlWalker analyze(HqlParser parser, String collectionRole) throws QueryException, RecognitionException {
final HqlSqlWalker w = new HqlSqlWalker( this, factory, parser, tokenReplacements, collectionRole ); final HqlSqlWalker w = new HqlSqlWalker( this, factory, parser, tokenReplacements, collectionRole );
final AST hqlAst = parser.getAST(); final AST hqlAst = parser.getAST();
@ -272,7 +271,7 @@ public class QueryTranslatorImpl implements FilterTranslator {
w.statement( hqlAst ); w.statement( hqlAst );
if ( LOG.isDebugEnabled() ) { if ( LOG.isDebugEnabled() ) {
LOG.debug( SQL_TOKEN_PRINTER.showAsString( w.getAST(), "--- SQL AST ---" ) ); LOG.debug( TokenPrinters.SQL_TOKEN_PRINTER.showAsString( w.getAST(), "--- SQL AST ---" ) );
} }
w.getParseErrorHandler().throwQueryException(); w.getParseErrorHandler().throwQueryException();
@ -304,11 +303,9 @@ public class QueryTranslatorImpl implements FilterTranslator {
return parser; return parser;
} }
private static final ASTPrinter HQL_TOKEN_PRINTER = new ASTPrinter( HqlTokenTypes.class );
void showHqlAst(AST hqlAst) { void showHqlAst(AST hqlAst) {
if ( LOG.isDebugEnabled() ) { if ( LOG.isDebugEnabled() ) {
LOG.debug( HQL_TOKEN_PRINTER.showAsString( hqlAst, "--- HQL AST ---" ) ); LOG.debug( TokenPrinters.HQL_TOKEN_PRINTER.showAsString( hqlAst, "--- HQL AST ---" ) );
} }
} }

View File

@ -23,6 +23,7 @@ import org.hibernate.hql.internal.ast.tree.Node;
import org.hibernate.hql.internal.ast.tree.ParameterContainer; import org.hibernate.hql.internal.ast.tree.ParameterContainer;
import org.hibernate.hql.internal.ast.tree.ParameterNode; import org.hibernate.hql.internal.ast.tree.ParameterNode;
import org.hibernate.hql.internal.ast.util.ASTPrinter; import org.hibernate.hql.internal.ast.util.ASTPrinter;
import org.hibernate.hql.internal.ast.util.TokenPrinters;
import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
@ -57,7 +58,6 @@ public class SqlGenerator extends SqlGeneratorBase implements ErrorReporter {
private ParseErrorHandler parseErrorHandler; private ParseErrorHandler parseErrorHandler;
private SessionFactoryImplementor sessionFactory; private SessionFactoryImplementor sessionFactory;
private LinkedList<SqlWriter> outputStack = new LinkedList<SqlWriter>(); private LinkedList<SqlWriter> outputStack = new LinkedList<SqlWriter>();
private final ASTPrinter printer = new ASTPrinter( SqlTokenTypes.class );
private List<ParameterSpecification> collectedParameters = new ArrayList<ParameterSpecification>(); private List<ParameterSpecification> collectedParameters = new ArrayList<ParameterSpecification>();
@ -81,7 +81,7 @@ public class SqlGenerator extends SqlGeneratorBase implements ErrorReporter {
private String buildTraceNodeName(AST tree) { private String buildTraceNodeName(AST tree) {
return tree == null return tree == null
? "???" ? "???"
: tree.getText() + " [" + printer.getTokenTypeName( tree.getType() ) + "]"; : tree.getText() + " [" + TokenPrinters.SQL_TOKEN_PRINTER.getTokenTypeName( tree.getType() ) + "]";
} }
@Override @Override

View File

@ -16,6 +16,7 @@ import org.hibernate.hql.internal.antlr.SqlTokenTypes;
import org.hibernate.hql.internal.ast.util.ASTAppender; import org.hibernate.hql.internal.ast.util.ASTAppender;
import org.hibernate.hql.internal.ast.util.ASTIterator; import org.hibernate.hql.internal.ast.util.ASTIterator;
import org.hibernate.hql.internal.ast.util.ASTPrinter; import org.hibernate.hql.internal.ast.util.ASTPrinter;
import org.hibernate.hql.internal.ast.util.TokenPrinters;
import org.hibernate.type.Type; import org.hibernate.type.Type;
import antlr.SemanticException; import antlr.SemanticException;
@ -157,7 +158,7 @@ public class SelectClause extends SelectExpressionList {
if ( type == null ) { if ( type == null ) {
throw new QueryException( throw new QueryException(
"No data type for node: " + selectExpression.getClass().getName() + " " "No data type for node: " + selectExpression.getClass().getName() + " "
+ new ASTPrinter( SqlTokenTypes.class ).showAsString( (AST) selectExpression, "" ) + TokenPrinters.SQL_TOKEN_PRINTER.showAsString( (AST) selectExpression, "" )
); );
} }
//sqlResultTypeList.add( type ); //sqlResultTypeList.add( type );

View File

@ -11,6 +11,7 @@ import java.util.List;
import org.hibernate.hql.internal.antlr.SqlTokenTypes; import org.hibernate.hql.internal.antlr.SqlTokenTypes;
import org.hibernate.hql.internal.ast.util.ASTPrinter; import org.hibernate.hql.internal.ast.util.ASTPrinter;
import org.hibernate.hql.internal.ast.util.TokenPrinters;
import antlr.collections.AST; import antlr.collections.AST;
@ -44,7 +45,7 @@ public abstract class SelectExpressionList extends HqlSqlWalkerNode {
else { else {
throw new IllegalStateException( throw new IllegalStateException(
"Unexpected AST: " + n.getClass().getName() + " " "Unexpected AST: " + n.getClass().getName() + " "
+ new ASTPrinter( SqlTokenTypes.class ).showAsString( n, "" ) + TokenPrinters.SQL_TOKEN_PRINTER.showAsString( n, "" )
); );
} }
p++; p++;

View File

@ -20,52 +20,24 @@ import antlr.collections.AST;
/** /**
* Utility for generating pretty "ASCII art" representations of syntax trees. * Utility for generating pretty "ASCII art" representations of syntax trees.
* *
* This class is threadsafe: reuse instances as needed.
*
* @author Joshua Davis * @author Joshua Davis
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class ASTPrinter { public class ASTPrinter {
private final Map<Integer,String> tokenTypeNameCache; private final Map<Integer,String> tokenTypeNameCache;
private final boolean showClassNames;
/** /**
* Constructs a printer. * Constructs a printer. Package protected: use the constants from {TokenPrinters}
* <p/> * @see TokenPrinters
* Delegates to {@link #ASTPrinter(Class, boolean)} with {@link #isShowClassNames showClassNames} as <tt>true</tt>
* *
* @param tokenTypeConstants The token types to use during printing; typically the {vocabulary}TokenTypes.java * @param tokenTypeConstants The token types to use during printing; typically the {vocabulary}TokenTypes.java
* interface generated by ANTLR. * interface generated by ANTLR.
*/ */
public ASTPrinter(Class tokenTypeConstants) { ASTPrinter(Class tokenTypeConstants) {
this( ASTUtil.generateTokenNameCache( tokenTypeConstants ), true ); this.tokenTypeNameCache = ASTUtil.generateTokenNameCache( tokenTypeConstants );
}
public ASTPrinter(boolean showClassNames) {
this( (Map) null, showClassNames );
}
/**
* Constructs a printer.
*
* @param tokenTypeConstants The token types to use during printing; typically the {vocabulary}TokenTypes.java
* interface generated by ANTLR.
* @param showClassNames Should the AST class names be shown.
*/
public ASTPrinter(Class tokenTypeConstants, boolean showClassNames) {
this( ASTUtil.generateTokenNameCache( tokenTypeConstants ), showClassNames );
}
private ASTPrinter(Map<Integer,String> tokenTypeNameCache, boolean showClassNames) {
this.tokenTypeNameCache = tokenTypeNameCache;
this.showClassNames = showClassNames;
}
/**
* Getter for property 'showClassNames'.
*
* @return Value for property 'showClassNames'.
*/
public boolean isShowClassNames() {
return showClassNames;
} }
/** /**
@ -117,10 +89,7 @@ public class ASTPrinter {
*/ */
public String getTokenTypeName(int type) { public String getTokenTypeName(int type) {
final Integer typeInteger = type; final Integer typeInteger = type;
String value = null; String value = tokenTypeNameCache.get( typeInteger );
if ( tokenTypeNameCache != null ) {
value = tokenTypeNameCache.get( typeInteger );
}
if ( value == null ) { if ( value == null ) {
value = typeInteger.toString(); value = typeInteger.toString();
} }
@ -161,19 +130,17 @@ public class ASTPrinter {
} }
private void showNode(PrintWriter pw, AST ast) { private void showNode(PrintWriter pw, AST ast) {
String s = nodeToString( ast, isShowClassNames() ); String s = nodeToString( ast );
pw.println( s ); pw.println( s );
} }
public String nodeToString(AST ast, boolean showClassName) { public String nodeToString(AST ast) {
if ( ast == null ) { if ( ast == null ) {
return "{node:null}"; return "{node:null}";
} }
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
buf.append( "[" ).append( getTokenTypeName( ast.getType() ) ).append( "] " ); buf.append( "[" ).append( getTokenTypeName( ast.getType() ) ).append( "] " );
if ( showClassName ) { buf.append( StringHelper.unqualify( ast.getClass().getName() ) ).append( ": " );
buf.append( StringHelper.unqualify( ast.getClass().getName() ) ).append( ": " );
}
buf.append( "'" ); buf.append( "'" );
String text = ast.getText(); String text = ast.getText();

View File

@ -0,0 +1,24 @@
/*
* 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.hql.internal.ast.util;
import org.hibernate.hql.internal.antlr.HqlTokenTypes;
import org.hibernate.hql.internal.antlr.SqlTokenTypes;
import org.hibernate.sql.ordering.antlr.GeneratedOrderByFragmentRendererTokenTypes;
/**
* Commonly used token printers expressed as constants.
*/
public interface TokenPrinters {
ASTPrinter HQL_TOKEN_PRINTER = new ASTPrinter( HqlTokenTypes.class );
ASTPrinter SQL_TOKEN_PRINTER = new ASTPrinter( SqlTokenTypes.class );
ASTPrinter ORDERBY_FRAGMENT_PRINTER = new ASTPrinter( GeneratedOrderByFragmentRendererTokenTypes.class );
}

View File

@ -9,6 +9,7 @@ package org.hibernate.sql.ordering.antlr;
import org.hibernate.NullPrecedence; import org.hibernate.NullPrecedence;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.hql.internal.ast.util.ASTPrinter; import org.hibernate.hql.internal.ast.util.ASTPrinter;
import org.hibernate.hql.internal.ast.util.TokenPrinters;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
@ -25,7 +26,6 @@ import antlr.collections.AST;
public class OrderByFragmentRenderer extends GeneratedOrderByFragmentRenderer { public class OrderByFragmentRenderer extends GeneratedOrderByFragmentRenderer {
private static final Logger LOG = Logger.getLogger( OrderByFragmentRenderer.class.getName() ); private static final Logger LOG = Logger.getLogger( OrderByFragmentRenderer.class.getName() );
private static final ASTPrinter printer = new ASTPrinter( GeneratedOrderByFragmentRendererTokenTypes.class );
private final SessionFactoryImplementor sessionFactory; private final SessionFactoryImplementor sessionFactory;
@ -56,7 +56,7 @@ public class OrderByFragmentRenderer extends GeneratedOrderByFragmentRenderer {
private String buildTraceNodeName(AST tree) { private String buildTraceNodeName(AST tree) {
return tree == null return tree == null
? "???" ? "???"
: tree.getText() + " [" + printer.getTokenTypeName( tree.getType() ) + "]"; : tree.getText() + " [" + TokenPrinters.ORDERBY_FRAGMENT_PRINTER.getTokenTypeName( tree.getType() ) + "]";
} }
@Override @Override

View File

@ -11,6 +11,7 @@ import java.util.Set;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.hql.internal.ast.util.ASTPrinter; import org.hibernate.hql.internal.ast.util.ASTPrinter;
import org.hibernate.hql.internal.ast.util.TokenPrinters;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
@ -55,8 +56,7 @@ public class OrderByFragmentTranslator {
} }
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
ASTPrinter printer = new ASTPrinter( OrderByTemplateTokenTypes.class ); LOG.trace( TokenPrinters.ORDERBY_FRAGMENT_PRINTER.showAsString( parser.getAST(), "--- {order-by fragment} ---" ) );
LOG.trace( printer.showAsString( parser.getAST(), "--- {order-by fragment} ---" ) );
} }
// Render the parsed tree to text. // Render the parsed tree to text.

View File

@ -18,6 +18,8 @@ import org.hibernate.hql.internal.ast.util.ASTIterator;
import org.hibernate.hql.internal.ast.util.ASTParentsFirstIterator; import org.hibernate.hql.internal.ast.util.ASTParentsFirstIterator;
import org.hibernate.hql.internal.ast.util.ASTPrinter; import org.hibernate.hql.internal.ast.util.ASTPrinter;
import org.hibernate.hql.internal.ast.util.ASTUtil; import org.hibernate.hql.internal.ast.util.ASTUtil;
import org.hibernate.hql.internal.ast.util.TokenPrinters;
import org.hibernate.testing.junit4.BaseUnitTestCase; import org.hibernate.testing.junit4.BaseUnitTestCase;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@ -36,7 +38,7 @@ public class ASTIteratorTest extends BaseUnitTestCase {
HqlParser parser = HqlParser.getInstance( input ); HqlParser parser = HqlParser.getInstance( input );
parser.statement(); parser.statement();
AST ast = parser.getAST(); AST ast = parser.getAST();
ASTPrinter printer = new ASTPrinter( HqlTokenTypes.class ); ASTPrinter printer = TokenPrinters.HQL_TOKEN_PRINTER;
printer.showAst( ast, new PrintWriter( System.out ) ); printer.showAst( ast, new PrintWriter( System.out ) );
ASTIterator iterator = new ASTIterator( ast ); ASTIterator iterator = new ASTIterator( ast );
int count = 0; int count = 0;