3.3.9 Using Builtin Annotations

RTI Code Generator supports the following builtin annotations, which can be used in your IDL File:

These annotations are described two standard documents: Interface Definition Language (Version 4) and Extensible and Dynamic Topic Types for DDS (Version 1.2).

In addition, RTI provides the following RTI-specific annotations:

3.3.9.1 The @key Annotation

To declare a key for your data type, insert the @key annotation in the IDL file before one or more fields of the data type.

With each key, Connext DDS associates an internal 16-byte representation, called a key-hash.

If the maximum size of the serialized key is greater than 16 bytes, to generate the key-hash, Connext DDS computes the MD5 key-hash of the serialized key in network-byte order. Otherwise (if the maximum size of the serialized key is <= 16 bytes), the key-hash is the serialized key in network-byte order.

Only struct definitions in IDL may have key fields. When RTI Code Generator encounters @key, it considers the previously declared field in the enclosing structure to be part of the key. Table 3.11 Example Keys shows some examples of keys.

Table 3.11 Example Keys

Type

Key Fields

struct NoKey { 
long member1;
long member2;
}

 

struct SimpleKey {
@key long member1;
long member2;
}

member1

struct NestedNoKey {
SimpleKey member1;
long member2;
}

 

struct NestedKey {
@key SimpleKey member1;
long member2;
}

member1.member1

struct NestedKey2 { 
@key NoKey member1;
long member2;
}

member1.member1

member1.member2

valuetype BaseValueKey {
@key public long member1;
}

member1

valuetype DerivedValueKey :BaseValueKey { 
@key public long member2;
}

member1

member2

valuetype DerivedValue : BaseValueKey { 
public long member2;
}

member1

struct ArrayKey { 
@key long member1[3];
}

member1[0]

member1[1]

member1[2]

3.3.9.2 The @nested Annotation

By default, RTI Code Generator generates user-level type-specific methods for all structures/unions found in an IDL file. These methods include the methods used by DataWriters and DataReaders to send and receive data of a given type. General methods for writing and reading that take a void pointer are not offered by Connext DDS because they are not type safe. Instead, type-specific methods must be created to support a particular data type.

We use the term ‘top-level type’ to refer to the data type for which you intend to create a DCPS Topic that can be published or subscribed to. For top-level types, RTI Code Generator must create all of the type-specific methods previously described in addition to the code to serialize/deserialize those types. However, some of structures/unions defined in the IDL file are only embedded within higher-level structures and are not meant to be published or subscribed to individually. For non-top-level types, the DataWriters and DataReaders methods to send or receive data of those types are superfluous and do not need to be created. Although the existence of these methods is not a problem in and of itself, code space can be saved if these methods are not generated in the first place.

You can mark non-top-level types in an IDL file with the annotation @nested to tell RTI Code Generator not to generate type-specific methods. Code will still be generated to serialize and deserialize those types, since they may be embedded in top-level types.

The top-level directive can also be used but with the opposite meaning. @top_level or //@top-level (true) indicates that the type is top level, therefore, @top_level (false) would be equivalent to @nested.

In this example, RTI Code Generator will generate DataWriter/DataReader code for TopLevelStruct only:

@nested
struct EmbeddedStruct {
    short member;
}; 
struct TopLevelStruct {
    EmbeddedStruct member;
};
struct TopLevelStruct{
    EmbeddedStruct member;
};

3.3.9.3 The @value Annotation

The @value annotation can be used to set specific values to members of enumerations. For example:

enum MyEnum {
    @value (17) e17,
    @value (2) e2,
    @value (3) e3
}

It is equivalent to:

enum MyEnum {
    e17 =17,
    e2 = 2,
    e3 =3
}

3.3.9.4 The @external Annotation

A member declared as external using the @external annotation (or the * modifier) within an aggregated type indicates that it is desirable for the implementation to store the member in storage external to the enclosing aggregated type object.

For example:

struct MyStruct {
    @external long member;
}

This is equivalent to the following structure, although the usage of the @external annotation is preferred because it is standard:

struct MyStruct {
    long *member;
};

The @external annotation only has effect in C, C++, Modern C++, and Ada applications where the members will be mapped to references (pointers). In other languages, the annotation is ignored because the members are always mapped as references.

In Modern C++ the annotation maps to the type dds::core::external<T>, a type similar to shared_ptr.

3.3.9.5 The @copy and Related Annotations

To copy a line of text verbatim into the generated code files, use the @copy annotation in the IDL file. The @copy annotation can only be applied using the comment syntax (//@). The @copy annotation is particularly useful when you want your generated code to contain text that is valid in the target programming language but is not valid IDL. It is often used to add user comments or headers or preprocessor commands into the generated code.

//@copy (// Modification History)
//@copy (// --------------------
//@copy (// 17Jul05aaa, Created.)
//@copy
//@copy (// #include “MyTypes.h”)

These variations allow you to use the same IDL file for multiple languages:

@copy-c

Copies code if the language is C or C++

@copy-cppcli

Copies code if the language is C++/CLI

@copy-java

Copies code if the language is Java.

@copy-ada

Copies code if the language is Ada.

For example, to add import statements to generated Java code:

//@copy-java (import java.util.*;)

The above line would be ignored if the same IDL file was used to generate non-Java code.

In C, C++, and C++/CLI, the lines are copied into all of the foo*.[h, c, cxx, cpp] files generated from foo.idl. For Java, the lines are copied into all of the *.java files that were generated from the original “.idl” file. The lines will not be copied into any additional files that are generated using the -example command line option.

@copy-java-begin copies a line of text at the beginning of all the Java files generated for a type. The annotation only applies to the first type that is immediately below in the IDL file. A similar annotation for Ada files is also available, @copy-ada-begin.

If you want RTI Code Generator to copy lines only into the files that declare the data types—foo.h for C, C++, and C++/CLI, foo.java for Java—use the //@copy*declaration forms of this annotation.

Note that the first whitespace character to follow //@copy is considered a delimiter and will not be copied into generated files. All subsequent text found on the line, including any leading whitespaces will be copied.

//@copy-declaration

Copies the text into the file where the type is declared (<type>.h for C and C++, or <type>.java for Java)

//@copy-c-declaration

Same as //@copy-declaration, but for C and C++ code

//@copy-cppcli-declaration

Same as //@copy-declaration, but for C++/CLI code

//@copy-java-declaration

Same as //@copy-declaration, but for Java-only code

//@copy-ada-declaration

Same as //@copy-declaration, but for Ada-only code

//@copy-java-declaration-begin

Same as //@copy-java-declaration, but only copies the text into the file where the type is declared

//@copy-ada-declaration-begin

Same as //@copy-java-declaration-begin, but only for Ada-only code

3.3.9.6 The @resolve_name Annotation

By default, RTI Code Generator tries to resolve all the references to types and constants in an IDL file. For example:

module PackageName {
    struct Foo {
        Bar barField;
    };
};

The compilation of the previous IDL file will report an error like the following:

ERROR com.rti.ndds.nddsgen.Main Foo.idl line x:x member type 'Bar' not found

In most cases, this is the expected behavior. However, in some cases, you may want to skip the resolution step. For example, assume that the Bar type is defined in a separate IDL file and that you are running RTI Code Generator without an external preprocessor by using the command-line option -ppDisable (maybe because the preprocessor is not available in their host platform, see 3.3.8 Preprocessor Directives):

Bar.idl

module PackageName {
    struct Bar {
        long field;
    };
};

Foo.idl

#include "Bar.idl"
module PackageName {
    struct Foo {
        Bar barField;
    };
};

In this case, compiling Foo.idl would generate the 'not found' error. However, Bar is defined in Bar.idl. To specify that RTI Code Generator should not resolve a type reference, use the //@resolve_name annotation and set the value to false. For example:

#include "Bar.idl"
module PackageName {
    struct Foo {
        @resolve_name(false) Bar barField;
    };
};

When this annotation is used, then for the field to which it applies, RTI Code Generator will assume that the type is an unkeyed 'structure' and it will use the type name unmodified in the generated code.

Java mapping:

package PackageName;
public class Foo {    
    public Bar barField = Bar.create();
};

C++ mapping:

namespace PackageName {
class Foo {
    public:
        Bar barField;
    };
};

It is up to you to include the correct header files (or if using Java, to import the correct packages) so that the compiler resolves the ‘Bar’ type correctly. If needed, this can be done using the copy directives (see 3.3.9.5 The @copy and Related Annotations).

When applied to an aggregated type in IDL, the annotation applies to all types within the type, including the base type if defined. For example:

@resolve_name(false)
struct MyStructure: MyBaseStructure
{
    Foo member1;
    Bar member2;
};

3.3.9.7 The @use_vector annotation

The @use_vector annotation can be used in Modern C++ to indicate that a bounded sequence should be mapped to std::vector; otherwise it will be mapped to rti:core::bounded_sequence.

For example :

struct MyStruct {
    @use_vector sequence<long, 10> my_bounded_seq;
}

As an alternative, you can use rtiddsgen's -alwaysUseStdVector option to indicate that all bounded sequences should be mapped to std::vector. Unbounded sequences always map to std::vector.

3.3.9.8 The @transfer_mode annotation

The @transfer_mode annotation can be used to indicate how to send a sample of the annotated type. There are two possible values for this annotation: SHMEM_REF and INBAND.

The annotation can be used only while generating code for C and C++ (Traditional and Modern) APIs. For other languages, the annotation is ignored.

@transfer_mode(SHMEM_REF) indicates that a sample can be sent as a shared memory reference instead of sending the serialized sample, when the DataReader(s) are on the same node as the DataWriter writing the sample. See 23.5 Zero Copy Transfer Over Shared Memory for more information.

@transfer_mode(INBAND) indicates that a sample is always serialized and sent inband using the underlying transports. This is the default mode when the annotation is not present.

The use of @transfer_mode annotation without a parameter is not allowed and will generate an error during code generation.

It is sufficient to mark only the top-level types with the @transfer_mode annotation. In this example, a sample of type CameraImage can be sent as a shared memory reference, even though the included type Dimension is not explicitly annotated:

struct Dimension {
    long height;
    long width;
};
@transfer_mode(SHMEM_REF)
struct CameraImage {
   long long timestamp;
   Dimension dimension;
   octet data[8294400][4];
};

RTI Code Generator will return an error while parsing the IDL file if the following requirements are not met:

The @transfer_mode annotation can be applied to modules, structs, valuetypes, and unions. When applied to a module, all the types within the module inherit the language binding value specified in the module.

3.3.9.9 The @language_binding Annotation

The @language_binding annotation allows selecting the language binding for a type, either the plain language binding (default option when the annotation is not specified) or the RTI FlatData™ language binding.

PLAIN is the regular language binding that maps IDL types to their regular C or C++ representation as C structs or C++ classes.

FLAT_DATA is a special language binding in which the in-memory representation is the same as the wire representation. See 23.4 FlatData Language Binding for a detailed description.

For example:

@language_binding(PLAIN) // or no annotation
struct MyNormalType {
    ...
};
@language_binding(FLAT_DATA)
struct MyFlatType {
    ...
};

A few notes about the @language_binding annotation:

© 2020 RTI