Gem #57: Ada / Java cross dispatching

by Quentin Ochem —AdaCore

Let's get started…


Consider the following API:

package API is
   type A_Tagged_Type is tagged null record;

   procedure Print_Me (V : A_Tagged_Type; Me : String);

   type An_Ada_Child is new A_Tagged_Type with null record;

   procedure Print_Me (V : An_Ada_Child; Me : String);

   procedure Call_Print_Me (Str : String; Val : A_Tagged_Type’Class);
end API;

package body API is
   procedure Print_Me (V : A_Tagged_Type; Me : String) is
   begin
      Put_Line ("FROM A TAGGED TYPE: " & Me);
   end Print_Me;

   procedure Print_Me (V : An_Ada_Child; Me : String) is
   begin
      Put_Line ("FROM AN ADA CHILD: " & Me);
   end Print_Me;

   procedure Call_Print_Me (Str : String; Val : A_Tagged_Type’Class) is
   begin
      Print_Me (Val, Str);
   end Call_Print_Me;
end API;

Note that the call in the Ada Call_Print_Me is dispatching, so if I write in Ada:

V1 : A_Tagged_Type;
V2 : An_Ada_Child;
Call_Print_Me ("V1", V1);
Call_Print_Me ("V2", V2);

It will call the Print_Me of the actual object, so that the output will be:

FROM A TAGGED TYPE: V1
FROM AN ADA CHILD: V2

Generating the binding code

As usual, generating the whole binding is done through a simple command:

ada2java api.ads –b test –o ada –c java –L my_lib

Writing the Java code

We now have two classes, test.API.A_Tagged_Type and test.API.An_Ada_Child, both of them regular non-final java classes, with An_Ada_Child derived explicitly from A_Tagged_Type. So we can write an example similar to what we did in Ada:

import test.API_Package;
import test.API.A_Tagged_Type;
import test.API.An_Ada_Child;
import test.Standard.AdaString;

public class My_Main {

public static void main (String [] argv) {
   A_Tagged_Type v1 = new A_Tagged_Type ();
   An_Ada_Child v2 = new An_Ada_Child ();
   API_Package.Call_Print_Me (new AdaString ("V1"), v1);
   API_Package.Call_Print_Me (new AdaString ("V2"), v2);
}

which will have exactly the same effect. But we can go even further; it is possible to derive the class A_Tagged_Type in Java, and override its primitive. Let’s do that in a class nested in My_Main, such as:

static class A_Java_Child extends A_Tagged_Type {
   public void Print_Me (AdaString Me) {
      System.out.println ("FROM A JAVA CHILD" + Me);
   }
}

Note that here, what was an Ada dispatching primitive is now a Java member function. The first parameter of the Ada subprogram, the controlling operand “V”, has been bound to the Java implicit “this” parameter, so that the member ends up having only one explicit parameter instead of two. Incidentally, this kind of construction would not have been possible if the first parameter of the Ada primitive had not been controlling, and ada2java would have warned us about this.

Now we can use instances of this object just as instances of any of its parents, for example:

public static void main (String [] argv) {
   A_Tagged_Type v1 = new A_Tagged_Type ();
   An_Ada_Child v2 = new An_Ada_Child ();
   A_Tagged_Type v3 = new A_Java_Child ();
   API_Package.Call_Print_Me (new AdaString ("V1"), v1);
   API_Package.Call_Print_Me (new AdaString ("V2"), v2);
   API_Package.Call_Print_Me (new AdaString ("V3"), v3);
}

And just like that, we have put in place a cross-language-dispatching call between Ada and Java. On the Ada side, the code generated by the binding generator and the AJIS run-time will be able to detect that this last object has a type extended in Java, and that the dispatching call has to be resolved using the Java object.


Compiling and running

As in the earlier Ada/Java interfacing Gems, the compile and run commands on Linux breaks 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

which displays on the screen:

FROM A TAGGED TYPE: V1
FROM AN ADA CHILD: V2
FROM A JAVA CHILD: V3

About the Author

Quentin Ochem has a software engineering background, specialized in software development for critical applications. He has over 10 years of experience in Ada development. He works today as a technical account manager for AdaCore, following projects related to avionics, railroad, space and defense industries. He also teaches the avionics standard DO-178B course at the EPITA University in Paris.