Visual J# Exception Hierarchies 

Visual J# generates two types of error messages: Java-language and .NET Framework exceptions.

  • Java-language exceptions are derived from java.lang.Throwable. These fall into two categories:

    Exception Description

    Checked

    If a method results in a checked exception being thrown, the compiler issues an error unless the code that calls the method has a try-catch block to catch the checked exception.

    Runtime

    Derived from java.lang.RuntimeException. The compiler does not enforce any such catching by the calling code.

  • .NET Framework exceptions, which are derived from Exception. These exceptions do not have the previously mentioned type of categorization.

Many of the Java-language runtime exceptions have semantic equivalents in the .NET Framework; for example, java.lang.NullPointerException is similar to NullReferenceException. See Visual J# Exceptions for a table that maps Java-language runtime exceptions to their .NET Framework counterparts.

When you catch a Java-language runtime exception in your source code, the Visual J# compiler ensures that the resulting executable code catches its .NET Framework equivalent as well. For example:

try 
{
    methodWithNullReference();
} 
catch (java.lang.NullPointerException e) 
{
    // Catches both java.lang.NullPointerException
    // and System.NullReferenceException.
    e.printStackTrace();
}

There are two possible ways a null reference exception could originate in this example:

  • It is explicitly thrown in methodWithNullReference as a NullPointerException.

    -or-

  • It actually arises at run time as a .NET Framework NullReferenceException.

The catch (java.lang.NullPointerException e) clause catches both NullPointerException and NullReferenceException.

You can concentrate on Java language-specific exceptions and can generally ignore the .NET Framework exceptions that have Java-language equivalents. However, the catch clause should specify.NET Framework exceptions that do not have Java-language equivalents, which is the case if the exception does not show in the table in Visual J# Exceptions.

Changes in Exception Mapping

Visual J# 2005 introduces a change in the exception mapping behavior. In the past, it was not possible to include catch all exceptions in a single catch clause, as is normally possible in the Java language by catching java.lang.Throwable. In previous versions, .NET Framework exceptions would not be caught by a catch clause catching java.lang.Throwable. Changes have been made in the Visual J# compiler so that it is possible to catch all exceptions using a single catch clause catching java.lang.Throwable. It is still possible to catch .NET Framework exceptions in a separate catch clause if that is the preferred behavior.

The following examples show various possible sets of catch clauses and the behavior of each. If, in addition to catching java.lang.Throwable, explicit catch clauses are included catching various .NET Framework exceptions, the behavior depends on whether the exception is mapped or unmapped, as defined in the previous section. Mapped exceptions will be caught by the java.lang.Throwable catch clause; unmapped exceptions will still be caught by the specific catch clause for that unmapped exception.

Example 1

// Example 1: Throwable catches all exceptions.
try 
{
    // ...
} 
catch (Throwable t) 
{
    // ...
}

The above catch statement now catches all exceptions. The following code shows the J# equivalent of the intermediate language code generated:

try 
{
    // ...
} 
catch (System.Exception ex) 
{
    // The original runtime filter is replaced with this
    // catch clause.
    Throwable t = Throwable.wrapException(ex);
    if (t == null) rethrow;
    // ...
}
catch (Throwable t)
{
    // ...
}

Example 2

To get the entire stack frame, you need to unwrap the inner exception by calling get_InnerException(), and then get_StackTrace() on the unwrapped inner exception.

// Example 2: Explicitly catching .NET Framework exceptions still works 
// but we get more details with the get_StackTrace() method.
try 
{
    // ...
}
catch (Throwable t)
{
  System.out.println(t.get_InnerException().get_StackTrace());
} 
catch (System.Exception except) 
{
    // ...
}

In the previous case, if a catch clause explicitly catching Exception exists, java.lang.Throwable only catches Java-language exceptions. No mapping is done.

Example 3

// Example 3: Catching an unmapped .NET exception subclass.
try 
{
    // ...
}
catch (Throwable t) 
{
    // ...
} 
catch (ExceptionUnmapped except) 
{
    // ...
}

Previously, any exceptions matching ExceptionUnmapped will still be caught by the ExceptionUnmapped catch clause, not the java.lang.Throwable clause. The following code shows the result of the mapping:

try 
{
    // ...
} 
catch (ExceptionUnmapped except) 
{
    // ...
} 
catch (System.Exception ex) 
{
    // Note the change in order of the catch clauses
    // so that binary behavior is maintained.
    Throwable t = Throwable.wrapException(ex);
    if (t == null)
    {
        rethrow;
    }
} 
catch (Throwable t)
{
    // ...
}

Example 4

// Example 4: Catching a mapped .NET Framework Exception subclass.
try 
{
    // ...
} 
catch (Throwable t) 
{
    // ...
} 
catch (ExceptionMapped except) 
{
    // ...
}

In the previous case, mapped exceptions are caught by the java.lang.Throwable clause and the compiler issues an error saying that the catch clause is unreachable.

As far as the debugger is concerned, java.lang.Throwable and Exception are still two different classes of exceptions. For example, you may need to set the default debugger behavior for each of these two groups of exceptions separately.

See Also

Other Resources

Language Support