Force antlr3 to immediately exit when a rule fails - error-handling

I've got a rule like this:
declaration returns [RuntimeObject obj]:
DECLARE label value { $obj = new RuntimeObject($label.text, $value.text); };
Unfortunately, it throws an exception in the RuntimeObject constructor because $label.text is null. Examining the debug output and some other things reveals that the match against "label" actually failed, but the Antlr runtime "helpfully" continues with the match for the purpose of giving a more helpful error message (http://www.antlr.org/blog/antlr3/error.handling.tml).
Okay, I can see how this would be useful for some situations, but how can I tell Antlr to stop doing that? The defaultErrorHandler=false option from v2 seems to be gone.

I don't know much about Antlr, so this may be way off base, but the section entitled "Error Handling" on this migration page looks helpful.
It suggests you can either use #rulecatch { } to disable error handling entirely, or override the mismatch() method of the BaseRecogniser with your own implementation that doesn't attempt to recover. From your problem description, the example on that page seems like it does exactly what you want.

You could also override the reportError(RecognitionException) method, to make it rethrow the exception instead of print it, like so:
#parser::members {
#Override
public void reportError(RecognitionException e) {
throw new RuntimeException(e);
}
}
However, I'm not sure you want this (or the solution by ire_and_curses), because you will only get one error per parse attempt, which you can then fix, just to find the next error. If you try to recover (ANTLR does it okay) you can get multiple errors in one try, and fix all of them.

You need to override the mismatch and recoverFromMismatchedSet methods to ensure an exception is thrown immediately (examples are for Java):
#members {
protected void mismatch(IntStream input, int ttype, BitSet follow) throws RecognitionException {
throw new MismatchedTokenException(ttype, input);
}
public Object recoverFromMismatchedSet(IntStream input, RecognitionException e, BitSet follow) throws RecognitionException {
throw e;
}
}
then you need to change how the parser deals with those exceptions so they're not swallowed:
#rulecatch {
catch (RecognitionException e) {
throw e;
}
}
(The bodies of all the rule-matching methods in your parser will be enclosed in try blocks, with this as the catch block.)
For comparison, the default implementation of recoverFromMismatchedSet inherited from BaseRecognizer:
public Object recoverFromMismatchedSet(IntStream input, RecognitionException e, BitSet follow) throws RecognitionException {
if (mismatchIsMissingToken(input, follow)) {
reportError(e);
return getMissingSymbol(input, e, Token.INVALID_TOKEN_TYPE, follow);
}
throw e;
}
and the default rulecatch:
catch (RecognitionException re) {
reportError(re);
recover(input,re);
}

Related

KotlinLogging Throws NoSuchMethod Exception

I'm using this library:
"io.github.microutils:kotlin-logging:2.0.4"
with this logging implementation:
"ch.qos.logback:logback-classic:1.2.3"
In my code I call:
private val logger = KotlinLogging.logger{}
and then use this logger as follows:
logger.debug("message")
this runs fine until I try to debug my code at which point the following to two NoSuchMethodErrors pop up in the library:
private static IMarkerFactory bwCompatibleGetMarkerFactoryFromBinder() throws
NoClassDefFoundError {
try {
return StaticMarkerBinder.getSingleton().getMarkerFactory();
} catch (NoSuchMethodError var1) {
return StaticMarkerBinder.SINGLETON.getMarkerFactory();
}
}
And:
private static MDCAdapter bwCompatibleGetMDCAdapterFromBinder() throws
NoClassDefFoundError {
try {
return StaticMDCBinder.getSingleton().getMDCA();
} catch (NoSuchMethodError var1) {
return StaticMDCBinder.SINGLETON.getMDCA();
}
}
(the first time I try to log something)
Others on my team do not experience this issue. they are on macs, in case that matters.
If, I just continue running the code everything is fine as the exception is caught, but I don't want to hit continue twice anytime I want to debug. I'm willing to ignore exceptions if that is possible, or better yet, fix the underlying issue.

Closing resources created in failed constructor

Assume I have a class C that holds resources that need to be closed as member variables.
public class C {
private ClosableResource1 closableResource1;
private ClosableResource2 closableResource2;
.....
public C(){
closableResource1 = new ClosableResource1();
closableResource2 = new ClosableResource2();
.....
// some logic that can fail
}
close(){
closableResource1.close()
closableResource2.close()
.....
}
}
If the constructor succeeds I can be sure that close() will be called eventually by some entity manager and all the resources will be freed.
But how can I make sure I close the resources when the constructor fails? The failure can happen because I have additional logic in the constructor that can throw exception or I get some RuntimeException outside of my control?
Some things I though of:
Wrapping the constructor body with a try-catch block. Then, assuming I have a lot of closable members I'll have to have a big if statement in the catch block checking which resources were already initializing and only close them.
Offloading the ClosableResources creation to some init() function. Then I would have to make sure init() succeeded every time I try to use the object.
Is there some elegant solution? Or is this much more implementation specific then that?
You can do something like below:
public class C {
private List<AutoCloseable> closableResources = new ArrayList();
private ClosableResource1 closableResource1;
private ClosableResource2 closableResource2;
.....
public C() {
closableResource1 = new ClosableResource1();
closableResources.add(closableResource1)
closableResource2 = new ClosableResource2();
closableResources.add(closableResource2);
.....
try {
// some logic that can fail
} catch(Exception e) {
close();
}
}
close(){
for (AutoCloseable closableResource : closableResources) {
if (closableResource != null) {
closableResource.close();
}
}
}
}
Surrounding your code with try-catch and closing all your resources in catch is the correct solution here. Also read about method finalize() (Here is one tutorial). In general, I would recommend one method that cleans up all the resources (like you suggested method close(), I would call it though cleanup()) and call that method in your catch section and in your finalize() method
I asked and answered a very similar question here. It is very important that a constructor either succeeds or fails completely i.e. leaving no resources open. In order to achieve that I would follow each resource creation statement by a try-catch block. The catch block closes the resource and rethrows the exception so it is not lost:
public C() {
closableResource1 = new ClosableResource1();
closableResource2 = new ClosableResource2();
try {
// .....
// some logic that can fail and throw MyCheckedException or some RuntimeException
} catch (RuntimeException | MyCheckedException e) {
try {closableResource1.close();} catch (Exception ignore) {}
try {closableResource1.close();} catch (Exception ignore) {}
throw e;
}
}
If creating a resource can fail you need nested try-catch blocks as demonstrated here.
Here's a wild idea: create a class called something like DefusableCloser (that you can "defuse", like an explosive device being made safe):
class DefusableCloser implements AutoCloseable {
boolean active = true;
final AutoCloseable closeable;
DefusableCloser(AutoCloseable closeable) {
this.closeable = closeable;
}
#Override public void close() throws Exception {
if (active) closeable.close();
}
}
Now you can use this in a try-with-resources block:
c1 = new CloseableResource();
try (DefusableCloseable d1 = new DefusableCloseable(c1)) {
c2 = new CloseableResource();
try (DefusableCloseable d2 = new DefusableCloseable(c2)) {
// Do the other stuff which might fail...
// Finally, deactivate the closeables.
d1.active = d2.active = false;
}
}
If execution doesn't reach d1.active = d2.active = false;, the two closeables (or one, if the exception was in creating the second resource) will be closed. If execution does reach that line, they won't be closed and you can use them.
The advantage of doing it like this is that the exceptions will be correctly handled.
Note that the ordering is important: don't be tempted to create the two CloseableResources first, then the two DefusableCloseables: doing that won't handle an exception from creating the second CloseableResource. And don't put the creation of the CloseableResources into the TWR, as that would guarantee their closure.
For closing the resources in your class' close() method, you can also use try-with-resources to ensure that both resources are closed:
try (c1; c2) {}
You don't actually have to declare a new variable in the TWR syntax: you can just effectively say "close the resource for this existing variable afterwards", as shown here.

What's the point of the use function in Kotlin

I'm trying to use the inline function use with a FileInputStream instead of the classic try/catch IOException so that
try {
val is = FileInputStream(file)
// file handling...
}
catch (e: IOException) {
e.printStackTrace()
}
becomes
FileInputStream(file).use { fis ->
// do stuff with file
}
My question is, why use the function use if it stills throws exception? Do I have to wrap use in a try/catch? This seems ridiculous.
From Kotlin documentation:
Executes the given block function on this resource and then closes it
down correctly whether an exception is thrown or not.
When you use an object that implements the Closeable interface, you need to call the close() method when you are done with it, so it releases any system resources associated with the object.
You need to be careful and close it even when an exception is thrown. In this kind of situation that is error prone, cause you might not know or forget to handle it properly, it is better to automate this pattern. That's exactly what the use function does.
Your try-catch does not close the resource so you are comparing apples to oranges. If you close the resource in finally block:
val is = FileInputStream(file)
try {
...
}
catch (e: IOException) {
...
}
finally {
is.close()
}
is definitely more verbose than use which handles closing the resource.

Having trouble rereading a Lucene TokenStream

I am using Lucene 4.6, and am apparently unclear on how to reuse a TokenStream, because I get the exception:
java.lang.IllegalStateException: TokenStream contract violation: reset()/close() call missing, reset() called multiple times, or subclass does not call super.reset(). Please see Javadocs of TokenStream class for more information about the correct consuming workflow.
at the start of the second pass. I've read the Javadoc, but I'm still missing something. Here is a simple example that throws the above exception:
#Test
public void list() throws Exception {
String text = "here are some words";
TokenStream ts = new StandardTokenizer(Version.LUCENE_46, new StringReader(text));
listTokens(ts);
listTokens(ts);
}
public static void listTokens(TokenStream ts) throws Exception {
CharTermAttribute termAtt = ts.addAttribute(CharTermAttribute.class);
try {
ts.reset();
while (ts.incrementToken()) {
System.out.println("token text: " + termAtt.toString());
}
ts.end();
}
finally {
ts.close();
}
}
I've tried not calling TokenStream.end() or TokenStream.close() thinking maybe they should only be called at the very end, but I get the same exception.
Can anyone offer a suggestion?
The Exception lists, as a possible issue, calling reset() multiple times, which you are doing. This is explicitly not allowed in the implementation of Tokenizer. Since the the java.io.Reader api does not guarantee support of the reset() operation by all subclasses, the Tokenizer can't assume that the Reader passed in can be reset, after all.
You may simply construct a new TokenStream, or I believe you could call Tokenizer.setReader(Reader) (in which case you certainly must close() it first).

How to tell the Session to throw the error query[NHibernate]?

I made a test class against the repository methods shown below:
public void AddFile<TFileType>(TFileType FileToAdd) where TFileType : File
{
try
{
_session.Save(FileToAdd);
_session.Flush();
}
catch (Exception e)
{
if (e.InnerException.Message.Contains("Violation of UNIQUE KEY"))
throw new ArgumentException("Unique Name must be unique");
else
throw e;
}
}
public void RemoveFile(File FileToRemove)
{
_session.Delete(FileToRemove);
_session.Flush();
}
And the test class:
try
{
Data.File crashFile = new Data.File();
crashFile.UniqueName = "NonUniqueFileNameTest";
crashFile.Extension = ".abc";
repo.AddFile(crashFile);
Assert.Fail();
}
catch (Exception e)
{
Assert.IsInstanceOfType(e, typeof(ArgumentException));
}
// Clean up the file
Data.File removeFile = repo.GetFiles().Where(f => f.UniqueName == "NonUniqueFileNameTest").FirstOrDefault();
repo.RemoveFile(removeFile);
The test fails. When I step in to trace the problem, I found out that when I do the _session.flush() right after _session.delete(), it throws the exception, and if I look at the sql it does, it is actually submitting a "INSERT INTO" statement, which is exactly the sql that cause UNIQUE CONSTRAINT error. I tried to encapsulate both in transaction but still same problem happens. Anyone know the reason?
Edit
The other stay the same, only added Evict as suggested
public void AddFile<TFileType>(TFileType FileToAdd) where TFileType : File
{
try
{
_session.Save(FileToAdd);
_session.Flush();
}
catch (Exception e)
{
_session.Evict(FileToAdd);
if (e.InnerException.Message.Contains("Violation of UNIQUE KEY"))
throw new ArgumentException("Unique Name must be unique");
else
throw e;
}
}
No difference to the result.
Call _session.Evict(FileToAdd) in the catch block. Although the save fails, FileToAdd is still a transient object in the session and NH will attempt to persist (insert) it the next time the session is flushed.
NHibernate Manual "Best practices" Chapter 22:
This is more of a necessary practice than a "best" practice. When
an exception occurs, roll back the ITransaction and close the ISession.
If you don't, NHibernate can't guarantee that in-memory state
accurately represents persistent state. As a special case of this,
do not use ISession.Load() to determine if an instance with the given
identifier exists on the database; use Get() or a query instead.