
Gem #58: Ada / Java exception handling
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





