HHH-16022 fix extremely ugly errors when HQL parsing failed
the formatting of syntax errors was terrible
This commit is contained in:
parent
f511282ce3
commit
43a3bc5883
|
@ -8,6 +8,9 @@ package org.hibernate.query.hql.internal;
|
|||
|
||||
import java.util.BitSet;
|
||||
|
||||
import org.antlr.v4.runtime.CommonToken;
|
||||
import org.antlr.v4.runtime.InputMismatchException;
|
||||
import org.antlr.v4.runtime.NoViableAltException;
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.grammars.hql.HqlLexer;
|
||||
import org.hibernate.grammars.hql.HqlParser;
|
||||
|
@ -32,6 +35,8 @@ import org.antlr.v4.runtime.atn.PredictionMode;
|
|||
import org.antlr.v4.runtime.dfa.DFA;
|
||||
import org.antlr.v4.runtime.misc.ParseCancellationException;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
* Standard implementation of {@link HqlTranslator}.
|
||||
*
|
||||
|
@ -39,26 +44,6 @@ import org.antlr.v4.runtime.misc.ParseCancellationException;
|
|||
*/
|
||||
public class StandardHqlTranslator implements HqlTranslator {
|
||||
|
||||
protected static final ANTLRErrorListener ERR_LISTENER = new ANTLRErrorListener() {
|
||||
|
||||
@Override
|
||||
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
|
||||
throw new ParsingException( "At position " + line + ":" + charPositionInLine + ", " + msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportAmbiguity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, boolean exact, BitSet ambigAlts, ATNConfigSet configs) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportAttemptingFullContext(Parser recognizer, DFA dfa, int startIndex, int stopIndex, BitSet conflictingAlts, ATNConfigSet configs) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportContextSensitivity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, int prediction, ATNConfigSet configs) {
|
||||
}
|
||||
};
|
||||
|
||||
private final SqmCreationContext sqmCreationContext;
|
||||
private final SqmCreationOptions sqmCreationOptions;
|
||||
|
||||
|
@ -105,11 +90,50 @@ public class StandardHqlTranslator implements HqlTranslator {
|
|||
// Build the parse tree
|
||||
final HqlParser hqlParser = HqlParseTreeBuilder.INSTANCE.buildHqlParser( hql, hqlLexer );
|
||||
|
||||
ANTLRErrorListener errorListener = new ANTLRErrorListener() {
|
||||
@Override
|
||||
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
|
||||
String errorText = "At " + line + ":" + charPositionInLine;
|
||||
if ( offendingSymbol instanceof CommonToken ) {
|
||||
String token = ( (CommonToken) offendingSymbol ).getText();
|
||||
if ( token != null && !token.isEmpty() ) {
|
||||
errorText += " and token '" + token + "'";
|
||||
}
|
||||
}
|
||||
errorText += ", ";
|
||||
if ( e instanceof NoViableAltException ) {
|
||||
errorText += msg.substring( 0, msg.indexOf("'") );
|
||||
String lineText = hql.lines().collect( toList() ).get( line-1 );
|
||||
String text = lineText.substring( 0, charPositionInLine ) + "*" + lineText.substring( charPositionInLine );
|
||||
errorText += "'" + text + "'";
|
||||
}
|
||||
else if ( e instanceof InputMismatchException ) {
|
||||
errorText += msg.substring( 0,msg.length()-1 ).replace(" expecting {", ", expecting one of the following tokens: ");
|
||||
}
|
||||
else {
|
||||
errorText += msg;
|
||||
}
|
||||
throw new ParsingException( errorText );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportAmbiguity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, boolean exact, BitSet ambigAlts, ATNConfigSet configs) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportAttemptingFullContext(Parser recognizer, DFA dfa, int startIndex, int stopIndex, BitSet conflictingAlts, ATNConfigSet configs) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportContextSensitivity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, int prediction, ATNConfigSet configs) {
|
||||
}
|
||||
};
|
||||
|
||||
// try to use SLL(k)-based parsing first - its faster
|
||||
hqlLexer.addErrorListener( ERR_LISTENER );
|
||||
hqlLexer.addErrorListener( errorListener );
|
||||
hqlParser.getInterpreter().setPredictionMode( PredictionMode.SLL );
|
||||
hqlParser.removeErrorListeners();
|
||||
hqlParser.addErrorListener( ERR_LISTENER );
|
||||
hqlParser.addErrorListener( errorListener );
|
||||
hqlParser.setErrorHandler( new BailErrorStrategy() );
|
||||
|
||||
try {
|
||||
|
|
|
@ -3745,7 +3745,7 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
|
|||
catch (IllegalArgumentException e) {
|
||||
final Throwable cause = e.getCause();
|
||||
assertThat( cause, instanceOf( ParsingException.class ) );
|
||||
assertTrue( cause.getMessage().contains( "mismatched input ')' expecting {<EOF>" ) );
|
||||
assertTrue( cause.getMessage().contains( "mismatched input ')'" ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue