title: What's the difference between ANTLR4's errorListener and errorHandler?
body: <p>I want to get the specific error message of ANTLR4's parser.
  And I found that there are two way to handle error: errorListener and errorHandler.</p>
  
  <pre><code>// set error handler
  parser.removeErrorListeners();
  parser.addErrorListener(new QueryErrorListener());
  
  parser.setErrorHandler(new BailErrorStrategy());
  </code></pre>
  
  <p>But I'm confused about the difference between them.</p>
  
  <p>I found that, errorListener can get the specific error message, but it can only print it or log it, can't throw a exception.</p>
  
  <p>The implemention of errorListener as bellow:</p>
  
  <pre><code>public class QueryErrorListener extends BaseErrorListener {
  
      private static final Logger LOGGER = LoggerFactory.getLogger(QueryDispatcher.class);
  
  
      @Override
      public void syntaxError(Recognizer&lt;?, ?&gt; recognizer, Object offendingSymbol,
                              int line, int charPositionInLine, String msg,
                              RecognitionException e)
      {
          List&lt;String&gt; stack = ((Parser)recognizer).getRuleInvocationStack(); Collections.reverse(stack);
          String errorMessage = "line "+line+":"+charPositionInLine+" at "+
                  offendingSymbol+": "+msg;
          LOGGER.error("rule stack: "+stack);
          LOGGER.error(errorMessage);
          QueryParseErrorStrategy queryParseErrorStrategy = new QueryParseErrorStrategy();
  
      }
  }
  </code></pre>
  
  <p>At the same time, the errorHandler can only throw a exception ParseCancellationException without any specific message. </p>
  
  <pre><code>public class BailErrorStrategy extends DefaultErrorStrategy {
      /** Instead of recovering from exception {@code e}, re-throw it wrapped
       *  in a {@link ParseCancellationException} so it is not caught by the
       *  rule function catches.  Use {@link Exception#getCause()} to get the
       *  original {@link RecognitionException}.
       */
      @Override
      public void recover(Parser recognizer, RecognitionException e) {
          for (ParserRuleContext context = recognizer.getContext(); context != null; context = context.getParent()) {
              context.exception = e;
          }
  
          throw new ParseCancellationException(e);
      }
  
      /** Make sure we don't attempt to recover inline; if the parser
       *  successfully recovers, it won't throw an exception.
       */
      @Override
      public Token recoverInline(Parser recognizer)
          throws RecognitionException
      {
          InputMismatchException e = new InputMismatchException(recognizer);
          for (ParserRuleContext context = recognizer.getContext(); context != null; context = context.getParent()) {
              context.exception = e;
          }
  
          throw new ParseCancellationException(e);
      }
  
      /** Make sure we don't attempt to recover from problems in subrules. */
      @Override
      public void sync(Parser recognizer) { }
  }
  </code></pre>
  
  <p>I've try to find a solution, add a transfer method to get detail message from ParseCancellationException, as bellow.</p>
  
  <p>I found that I can get some message from a Token object of RecognitionException, but I can only find the line/charPositionInLine/offendingSymbol message, I don't know where is the detail message, like "missing 'xxx', expect 'yyy'"</p>
  
  <pre><code>public class ANTLRExceptionTransfer {
  
      public static SemanticException transfer(RecognitionException re) {
          String errorMsg = "";
          Recognizer&lt;?, ?&gt; recognizer = re.getRecognizer();
          Token offendingSymbol = re.getOffendingToken();
          int line = offendingSymbol.getLine();
          int charPositionInLine = offendingSymbol.getCharPositionInLine();
          // ????????
          String msg = "";
  
          List&lt;String&gt; stack = ((Parser)recognizer).getRuleInvocationStack();
          Collections.reverse(stack);
  
          String errorMessage = "rule stack: "+stack;
          errorMessage = "\nline "+line+":"+charPositionInLine+" at "+
                  offendingSymbol+": "+msg;
          return new SemanticException(errorMessage);
  
  
      }
  }
  </code></pre>
  
  <p>Is it the right way to use errorHandler?
  How can I get a exception with specific error message?</p>