Home | Contact | Pricing | News | Events | Partners | Mailing List | Site Map
Gnat Pro. Powerful tools. Frontline Support. Ada expertise.

Gem #58: Ada / Java exception handling

Author: Quentin Ochem, AdaCore

Abstract: Ada Gem #58 — Ada and Java are two languages that rely heavily on exceptions. A large part of the Ada data model is based on the fact that data is checked at run time, and will raise various kinds of exceptions such as Constraint_Error when constraints are violated. Similarly, there are many cases where Java performs checks that can raise exceptions, among the most common being checks on casts and null dereferences. It is therefore extremely important to support exceptions that are properly propagated from one language to the other and even potentially caught/handled, without having to worry about the language of origin.

« Previous Gem | Next Gem » | Gems Menu

Let’s get started…


Let’s consider the following API:

with AJIS.Annotations; use AJIS.Annotations;

package API is

   function Compute (I : Integer) return Integer;

   type An_Operation is access function (I : Integer) return Integer;

   function Indirect_Compute (Data : Integer; Operation : An_Operation) 
     return Integer;
   pragma Annotate (AJIS, Assume_Escaped, False, Indirect_Compute, “Operation”);

end API;

with the following implementation:

package body API is

   function Compute (I : Integer) return Integer is
      Tmp : Natural := I;
   begin
      return Tmp + 1;
   end Compute;

   function Indirect_Compute (Data : Integer; Operation : An_Operation)
     return Integer
   is
   begin
      return Operation.all (Data);
   exception
      when Constraint_Error =>
         return 0;
   end Indirect_Compute;

end API;

The Compute subprogram uses a temporary variable of subtype Natural, and will raise a Constraint_Error if a negative value is passed for I. On the other hand, the Indirect_Compute subprogram catches all Constraint_Errors, and returns 0 if one occurs.


Generating the binding code

As with the previous Ada/Java interfacing Gems, the generation of the binding is straightforward:

ada2java api.ads –b test –o ada –c java –L my_lib –P api.gpr
Note that you need an api.gpr project file, defined as follows:
with “ajis”;

project API is

end API;

Writing the Java code

Let’s now play a bit with this code. As you can see, Java classes are generated for the Ada exceptions, such as test.Standard.Constraint_Error. These exceptions will end up as regular Java exceptions, which we can catch, for example, in the following code:

import test.API.API_Package;
import test.Standard.Constraint_Error;

public class My_Main {

   public static void main (String [] argv) {

      try {
         int x = API_Package.Compute (-1);
      } catch (Constraint_Error e) {
      System.out.println (e.getMessage ());
      }
   }
}

And just like that, we have an exception raised from Ada, transformed into a Java exception, and finally caught in a Java block. But let’s do something a little more ambitious. Let’s raise an exception from Ada, have this exception pass through the Java frames, and then end up back in Ada:

import test.API.API_Package;
import test.API.An_Operation;
import test.Standard.Constraint_Error;

public class My_Main {

   public static void main (String [] argv) {
      int x = API_Package.Indirect_Compute (-1,
                  new An_Operation () {
                       public int An_Operation_Body (int I) {
                            return API_Package.Compute (I);
                       }
                  }
               );
   }
}

So, here we have a callback called from Ada, implemented in Java, that calls the Ada Compute procedure. Let’s see what happens in detail. First, Indirect_Compute is called by Java, goes into Ada, which then calls the subprogram passed as an access parameter, resulting in a call to Java. This Java function then calls the Ada Compute operation, which will raise an exception due to passing -1. So at the point of the exception, the call stack looks like this:

[1] Java : main
[2] Ada : Indirect_Compute
[3] Java : An_Operation_Body
[4] Ada : Compute <- the exception is raised here

The exception first goes from [4] to [3], as in the previous example. In this case however, it is not caught, so it is propagated to the caller, [2], which happens to be Ada code again. Fortunately, the glue code generated between [2] and [3] is able to translate the exception back from Java to the original Ada exception, and continue the propagation. In this case, there’s an exception handler in [2], which handles Constraint_Error, and will catch the one initially raised at [4].


Compiling and running

Just as in the other Ada/Java interfacing Gems, the compile and run commands on Linux break down as follows:

gprbuild –p –P ada/my_lib.gpr
LD_LIBRARY_PATH=`pwd`/ada/lib/:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH
CLASSPATH=`pwd`:`pwd`/java:<your AJIS installation>/lib/ajis.jar:$CLASSPATH
javac My_Main.java
java My_Main

 

Posted by Posted in AJIS, Development Log, Devt log - Gem of the Week

Have your own idea for a Gem?

If you have an idea for a Gem you would like to contribute please feel free to contact us at: gems@adacore.com

Discussion

4 responses to “Gem #58: Ada / Java exception handling”


  1. Hugues Bonnin said:

    just a typo : change the “-1″ actual argument in call of dereferenced “Operation” in “Indirect_Compute” body by “Data”…


  2. Quentin Ochem said:

    Fixed – thanks for the remark!


  3. Daniel Bigelow said:

    just a typo: Indirect_Compute in the body should be a function, in which case the anonymous inner class that implements An_Operation needs to return Compute(I).


  4. Gary Dismukes said:

    Corrections made. Thanks!

Leave a Reply