You are here: Part 2: Core Concepts > Data Types and DDS Data Samples > Creating User Data Types with IDL > Using Custom Directives

Using Custom Directives

The following RTI Code Generator-specific directives can be used in your IDL file:

//@key (see The @key Directive)
//@copy  (see The @copy and Related Directives)
//@copy-c
//@copy-cppcli
//@copy-java
//@copy-java-begin
//@copy-declaration
//@copy-c-declaration
//@copy-cppcli-declaration
//@copy-java-declaration
//@copy-java-declaration-begin
//@resolve-name [true | false]  (see The @resolve-name Directive)
//@top-level [true | false]  (see The @top-level Directive)

Notes:

struct A {
    long a; //@key
            //@ID 20
    long b;
}; //@Extensibility FINAL_EXTENSIBILITY
   //@top-level false

The directives are case-sensitive. For instance, you must use //@key (not //@Key).

The @key Directive

To declare a key for your data type, insert the @key directive in the IDL file after 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. shows some examples of keys.

Example Keys

Type

Key Fields

struct NoKey { 
long member1;
long member2;
}

 

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

member1

struct NestedNoKey {
SimpleKey member1;
long member2;
}

 

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

member1.member1

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

member1.member1

member1.member2

valuetype BaseValueKey {
public long member1; //@key
}

member1

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

member1

member2

valuetype DerivedValue : BaseValueKey { 
public long member2;
}

member1

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

member1[0]

member1[1]

member1[2]

The @copy and Related Directives

To copy a line of text verbatim into the generated code files, use the @copy directive in the IDL file. This feature 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 directive only applies to the first type that is immediately below in the IDL file. A similar directive 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 directive.

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

The @resolve-name Directive

By default, the 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 thatyou arerunning 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 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 false directive. For example:

#include "Bar.idl"
module PackageName {
    struct Foo {
        Bar barField; //@resolve-name false
    };
};

When this directive is used, then for the field preceding the directive, RTI Code Generator will assume that the type is a 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 The @copy and Related Directives).

When used at the end of the declaration of a structure in IDL, then the directive applies to all types within the structure, including the base type if defined. For example:

struct MyStructure: MyBaseStructure
{
    Foo member1;
    Bar member2;
};    //@resolve-name false

The @top-level Directive

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 directive ‘//@top-level false’ 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.

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

struct EmbeddedStruct{
    short member;
}; //@top-level false
struct TopLevelStruct{
    EmbeddedStruct member;
};

© 2016 RTI