.. _Mapping_Ada_to_Java: ******************* Mapping Ada to Java ******************* To allow an Ada package to be used from Java, ``ada2java`` generates one or more Java classes (source files that will need to be compiled to bytecodes by a Java compiler) based on the content of the visible part of the Ada package spec. This section explains and illustrates the mapping for each of the various kinds of entities declared in a package that can be used from Java. In brief: * Although there are some exceptions to this rule, in general a type and certain of its associated subprograms declared in an Ada package are mapped to a Java class with methods corresponding to the Ada subprograms. Such entities are said to be *attached* to the resulting class. .. index:: Attachment (of entities to a class) * Other entities declared in the Ada package map to static members defined in a 'default class' generated by ``ada2java``. In particular, variables and constants in the Ada package map to private static fields in the default class and are accessed through ''getter'' (and 'setter' for variables) methods. Such entities are said to be *unattached*. .. index:: Default class If the default class is generated, its name is that of the original Ada package (with the same casing as the identifier in the package declaration) suffixed with ``_Package``. In the examples, only the portions of the Java classes needed by users of the classes are shown. .. _Types: Types ===== Types used in the Ada package map to Java types in the generated class(es). This section explains the correspondence. As a general rule, note that while most forms of type declarations have a correspondence in Java, subtype declarations are ignored, as there is no equivalent to subtypes in Java. However, subtype constraints imposed on Ada entities, such as variables or formal parameters, must be respected when referenced from Java, and can result in exceptions when constraints are violated. .. _Scalar_Types: Scalar Types ------------ .. index:: Scalar types (mapping to Java) The following table shows how Ada scalar types are mapped to Java primitive types: +-------------------------+-------------+ | Ada type | Java type | +=========================+=============+ | Integer type <= 32 bits | ``int`` | +-------------------------+-------------+ | Integer type > 32 bits | ``long`` | +-------------------------+-------------+ | ``Boolean`` | ``boolean`` | +-------------------------+-------------+ | ``Character`` | ``char`` | +-------------------------+-------------+ | Other enumeration type | ``int`` | +-------------------------+-------------+ | Fixed-point type | ``double`` | +-------------------------+-------------+ | Floating-point type | ``double`` | +-------------------------+-------------+ .. index:: Constraint checks Constraint checks generated in the Ada glue code detect errors that may result from the range mismatches between Ada and Java. For example, since a 16-bit Ada integer will be mapped to 32-bit ``int`` in Java, the Java code might attempt to pass an out-of-range value to Ada. This will raise a ``Constraint_Error`` exception in Ada, which will be propagated back to Java as an ``AdaException`` exception. For an enumeration type, a Java final class is created, with the same name as the enumeration type. This class defines the possible values for the enumeration. .. index:: Enumeration types (mapping to Java) Example: :: package Pckg is type Enum is (A, B, C); end Pckg; will give: :: package Pckg; public final class Enum { public static final int A = 0; public static final int B = 1; public static final int C = 2; } Representation clauses for enumeration types are not currently supported. A discussion of subprogram formal parameters of scalar types may be found in :ref:`Subprogram_parameters`. .. _Arrays: Arrays ------ .. index:: Array types (mapping to Java) Mapping Ada arrays to Java arrays would be very expensive, since it would imply a copy of the whole array each time a parameter has to be passed. Thus for efficiency an Ada array type is mapped to a dedicated 'proxy' class with methods that serve as accessors to attributes and components. For example: :: package Ex1 is type T1 is array(Integer range <>) of Float; end Ex1; will yield the following class: :: public final class T1 extends com.adacore.ajis.internal.ada.AdaProxy { ... public T1 (int First_1, int Last_1){...} final public double Get_Element_At (int Index_1){...} final public void Set_Element_At (int Index_1, double Value){...} final public int First (){...} final public int Last (){...} final public int Length (){...} } A subprogram that takes a parameter of the Ada array type is mapped to a method taking a parameter of the corresponding Java 'proxy' class; note that this method is located in the default class, and not in the proxy class. .. _Strings: Strings ------- .. index:: Strings (mapping to Java) Directly passing ``String`` data between Ada and Java would require expensive copying, and thus an alternative approach is used. The Ada type ``String`` is mapped to the Java class ``AdaString``, which encapsulates the accesses. More specifically, an Ada parameter of type ``String`` of any mode, and an Ada ``access String`` parameter, are both mapped to a Java parameter of type ``AdaString``. For efficiency, an ``AdaString`` object caches both its Ada and Java string values after they have been computed. As an example, if the Ada spec is: :: package Pckg is procedure P (V : String); end Pckg; then the generated Java will be: :: public final class Pckg_Package { public static void P (V : AdaString) {...} } If we now write: :: AdaString str = new AdaString ("A string from Java"); Pckg_Package.P (str); Pckg_Package.P (str); Only the first call will require the expensive string translation from Java to Ada. The second invocation will directly use the cached value. Please note that Java strings are UTF16-encoded, whereas the corresponding Ada strings will be UTF8-encoded. This may have significant impact when computing character offset on Java strings. .. index:: UTF-8 encoding .. index:: UTF-16 encoding .. _Simple_Record_Types: Simple Record Types ------------------- .. index:: Record types (mapping to Java) Simple (that is, not tagged) record types are mapped to Java final classes. Components are accessed through a set of generated accessors ('getter' / 'setter' methods). As a current limitation, ``ada2java`` does not yet support accessing discriminant components. Example: :: package Pckg is type R is record F1 : Integer; F2 : Float; end record; end Pckg; will give: :: package Pckg; public final class R { public R () {...} public final int F1 () {...} public final void F1 (int Value) {...} public final double F2 () {...} public final void F2 (double Value) {.../} } A component that has an access-to-record type is treated as though it were of the record type itself. For example: :: package Pckg is type R is record F1 : Integer; F2 : Float; end record; type S is record G1 : R; G2 : access R; end record; end Pckg; will result in both a class ``R`` as above, and the following class ``S``: :: package Pckg; public final class S { public S () {...} public R G1 () {...} public void G1 (R Value) {...} public R G2 () {...} public void G2 (R Value) {...} } Only one level of indirection is implemented; ``ada2java`` does not support access to access-to-record. A private (untagged) type is treated like a record type, except that it does not have any component-accessing methods. (A later release of ``ada2java`` will generate methods for accessing discriminants if the type has any.) .. _Tagged_Types: Tagged Types ------------ .. index:: Tagged types (mapping to Java) A tagged type is mapped to a Java class of the same name. If the Ada type is abstract, then the Java type will be abstract as well. .. _General_principles: General principles ^^^^^^^^^^^^^^^^^^ A primitive (i.e., dispatching) subprogram of a tagged type is mapped to a corresponding Java instance method. A current restriction is that the first parameter of the Ada subprogram must be a controlling parameter; otherwise the subprogram is mapped to a method in the default class. (Thus a function that delivers a value of the tagged type, but has no controlling parameter, is mapped to a method in the default class, and not to a method in the class corresponding to the Ada type.) The first Ada parameter is mapped to the Java method's implicit ``this`` parameter. A subprogram with a class-wide parameter is mapped to a method of the tagged type's Java class whose corresponding parameter has the Java class type. However, as this is not properly a dispatching primitive of the Ada type, it is declared as a final method. .. index:: Class-wide parameters (mapping to Java) As an example: :: package Ex1 is type T is tagged null record; procedure P1 (X : in out T; F : Float); procedure P2 (X : T'Class); procedure Q1 (I : Integer; X : T); procedure Q2 (I : Integer; X : T'Class); function F return T; end Ex1; is mapped to: :: public final class Ex1_Package { ... static public void Q1 (int I, Ex1.T X){...} static public void Q2 (int I, Ex1.T X){...} static public T F (){...} } // Ex1_Package public class T extends com.adacore.ajis.internal.ada.AdaProxy { ... public void P1 (double F){...} final public void P2 (){...} } // T .. _Ada_type_hierarchies: Ada type hierarchies ^^^^^^^^^^^^^^^^^^^^ Hierarchies of Ada types are preserved in the generated Java classes. Therefore, the following structure: :: type R is tagged record; type R_Child is new R with null record; will result in: :: public class R {...} public class R_Child extends R {...} Consistency of Java types is guaranteed at run time. For example, the following function: :: package Pckg is function F return R'Class; end Pckg; will result in: :: public final class Pckg_Package { public R F () {...} } However, if the actual type of the returned object is ``R_Child``, then the value returned by the Java function will be of the Java type corresponding to ``R_Child``. .. _Java_class_hierarchies: Java class hierarchies ^^^^^^^^^^^^^^^^^^^^^^ It is possible to extend a Java class that was generated by ``ada2java`` from an Ada tagged type. For example: :: package Rec_Pckg type Rec is tagged null record; procedure P (R : Rec); end Rec_Pckg; results in a Java class ``Rec`` with an instance method ``P``: :: class Rec extends com.adacore.ajis.internal.ada.AdaProxy { ... public void P(){...} } You can then write: :: class Rec_Child extends Rec { public void P () { System.out.println ("Hello from Java"); } } ... Rec ref = new Rec_Child(); ref.P(); // Displays "Hello from Java" .. _Global_Variables_and_Constants: Global Variables and Constants ============================== .. index:: Global variables (mapping to Java) A package containing global variables (that is, variables declared in the package spec's visible part) is mapped to a default class containing 'getter' and 'setter' methods for accessing and updating the variables. Global constants are treated analogously, but they have only a 'getter' method. Variables of limited types also only have a 'getter' method. Note that Ada named numbers, which are really just values intended for use in static compile-time computations, are not mapped to Java. For example: :: package Globals is V : Integer; C : constant Integer := 100; N : constant := 3.14159; end Globals; will result in the default class: :: public class Globals_Package { static public int V (){...} static public void V (int Value){...} static public int C (){...} } .. _Subprograms: Subprograms =========== .. index:: Subprograms (mapping to Java) Ada procedures and functions are mapped to Java methods. Nondispatching subprograms are marked as ``final``. Dispatching subprograms are discussed in :ref:`Tagged_Types`. .. _Method_placement: Method placement ---------------- In general, nondispatching subprograms are mapped to methods defined in the default class. .. index:: Default class For example, if the input package spec is: :: package Pkg is function F return Integer; end Pkg; then ``ada2java`` will generate the following default class: :: public class Pkg_Package{ ... public static int F(){...} } However, there are cases where the subprogram can be attached to the class of its first parameter. Attachment can be enabled / disabled depending on user requirement. In this case, the explicit initial Ada parameter is mapped to the implicit ``this`` parameter in Java. See :ref:`Managing_Attachment_to_Java_Proxies` for further details. .. index:: Attachment (of entities to a class) .. _Subprogram_parameters: Subprogram parameters --------------------- .. index:: Parameters (mapping to Java) The following rules and restrictions apply to the types of subprogram formal parameters: * Scalar types * Access-to-scalar types are not supported. * A scalar type with mode ``in`` is mapped to the corresponding Java type. For example: :: procedure P (V : Integer); will result in: :: public void P (int V) {...} * A formal scalar with mode ``out`` or ``in out`` will be mapped to a corresponding 'wrapper' class: ``BooleanRef``, ``CharacterRef``, ``DoubleRef``, ``IntegerRef``, and ``LongRef`` respectively encapsulating the primitive type ``boolean``, ``character``, ``double``, ``int`` and ``long``). Each of these classes defines ``setValue`` and ``getValue`` methods for accessing the encapsulated value. The Java application needs to construct an object of the relevant wrapper class and pass it to the method that corresponds to the Ada subprogram. After the return from the method, the Java application can invoke the ``getValue`` method to retrieve the new value of the actual parameter. * Record and private types * An Ada ``in``, ``in out``, or ``out`` formal parameter of a record or private type (either tagged or untagged), is mapped to a Java formal parameter of the class corresponding to the Ada type. Similarly, an Ada formal parameter of an access-to-record-type or access-to-private-type (either anonymous or named) is mapped to a Java formal parameter of the class corresponding to the Ada type. Example: :: package Example is type R is null record; type Access_R is access all R; procedure P(V1 : R; V2 : out R; V3 : in out R; V4 : access R; V5 : Access_R); end Example; The resulting Java class is: :: public final class Example_Pckg { ... public void P (R V1, R V2, R V3, R V4, R V5){...} } * An Ada ``out`` or ``in out`` parameter of an access-to-record (or access-to-private) type is mapped to a nested class. For example: :: package Example is type R is null record; type Access_R is access all R; procedure P(V : out Access_R); end Example; will generate the default class and a class for ``R`` :: public class Example_Package { ... static public void P (R.Ref V){...} } public class R extends com.adacore.ajis.internal.ada.AdaProxy { ... public static class Ref implements com.adacore.ajis.IProxyRef { public void setValue (Object r) {...} public Object getValue () {...} } } The Java application needs to construct an object of the class ``R.Ref`` and pass it to ``P``. On return, the ``getValue`` method may be called to retrieve the value in the ``out`` parameter returned by the Ada procedure. * Further indirection, such as an access-to-access type for a formal parameter, is not supported. .. _Overloaded_operators: Overloaded operators -------------------- Java doesn't allow operators overloading. When operators are overloaded in Ada, the corresponding Java name is set by the binding generator to ``OP_``. For example: :: type Complex is record ... function "+" (Left, Right : T) return T; will generate on the Java side: :: public class Complex { public Complex OP_PLUS (Complex Right) { ... } } Here's a list of the equivalence between Ada operators and Java names: +--------------+--------------+ | Ada operator | Java name | +==============+==============+ | ``=`` | ``OP_EQUAL`` | +--------------+--------------+ | ``>`` | ``OP_GT`` | +--------------+--------------+ | ``<`` | ``OP_LT`` | +--------------+--------------+ | ``>=`` | ``OP_GE`` | +--------------+--------------+ | ``<=`` | ``OP_LE`` | +--------------+--------------+ | ``or`` | ``OP_OR`` | +--------------+--------------+ | ``and`` | ``OP_AND`` | +--------------+--------------+ | ``xor`` | ``OP_XOR`` | +--------------+--------------+ | ``+`` | ``OP_PLUS`` | +--------------+--------------+ | ``-`` | ``OP_MINUS`` | +--------------+--------------+ | ``/`` | ``OP_DIV`` | +--------------+--------------+ | ``*`` | ``OP_MUL`` | +--------------+--------------+ | ``**`` | ``OP_EXP`` | +--------------+--------------+ .. _Subprogram_Access_Types: Subprogram Access Types ======================= Accesses to subprograms - sometimes referred to as callbacks - can't be directly bound to Java. It is not possible to give a reference to a Java function in a type-safe fashion. ada2java generates an abstract class with an abstract member of the correct profile for each access type to be bound, the implementation of its abstract primitive being the implementation of the subprogram access. For example: :: type P_Acc is access all procedure (V : Integer); procedure Call_P_Acc (Proc : P_Acc); pragma Annotate (AJIS, Assume_Escaped, False, Call_P_Acc, "Proc"); will be bound into: :: abstract public class P_Acc { abstract public P_Acc_Proc (int V); } void Call_P_Acc (P_Acc Proc); and can be used in, for example, the following scenario: :: Proc p = new Proc () { public P_Acc_Proc (int V) { System.out.println ("CALLED WITH " + V); } }; Pckg_Package.Call_P_Acc (p); Note the use of the pragma ``Annotate`` on the ``Call_P_Acc`` method. The Java implementations of bound subprogram access types are not actually accesses to subprograms, but instances of Java objects. It's not possible to store such an object on the Ada side afterwards, since the complete information can't be kept in the access type. Therefore, the programmer must ensure that no escape of the value is done, and take responsiblity for that by declaring the parameter as being not escaped. Further details on escapement can be found in :ref:`Restrictions_on_Proxy-Owned_Objects_passed_to_Subprograms`. .. _Exceptions: Exceptions ========== Exceptions are bound into classes derived from ``com.adacore.ajis.NativeException`` It is then possible to throw or handle them directly in Java code. Example: :: package Example is An_Exception : exception; procedure Raise_An_Exception; end Example; package body Example is procedure Raise_An_Exception is begin raise An_Exception; end Raise_An_Exception; end Example; The resulting Java class is: :: public final class An_Exception extends com.adacore.ajis.NativeException { ... } And can be used in e.g.: :: try { Example_Package.Raise_An_Exception (); } catch (An_Exception e) { // process the exception } .. _Renamings: Renamings ========= .. index:: Renamings (mapping to Java) Renamings of objects and subprograms are supported by ``ada2java``. Object renamings are mapped in the same way as global objects, by means of 'setter' and 'getter' methods in the default class for the containing package. A subprogram renaming is represented by a method with the name of the renaming that invokes the renamed subprogram, declared in the appropriate class. In other words, the same rules that apply to other subprograms apply to subprogram renamings. .. _Generics: Generics ======== Generic packages and subprogram can't be directly bound to Java. However, packages and subprograms instances and bound like regular packages and subprograms. .. _Predefined_Environment: Predefined Environment ====================== .. index:: Predefined environment (mapping to Java) In order to access descendants of ``Ada`` or ``GNAT`` from Java, you need to manually invoke ``ada2java`` on the Ada source files from the GNAT installation directories, to generate the corresponding Java binding classes. This step will be automated in a future release of GNAT-AJIS. .. _Current_Limitations: Current Limitations =================== .. index:: Current limitations The following features are not supported: * *Discriminants.* Discriminants are not accessible from the Java class generated for a discriminated type. * *Anonymous arrays.* Objects with an anonymous array type are not supported, but array type declarations which declare a constrained first subtype are supported. * *Interfaces.* No mapping is currently provided from Ada interface types to Java interfaces. * *Tasking features.* Tasks and protected objects/types are ignored.