CDR Schemas
CDR (Common Data Representation) is the binary serialisation used by DDS and ROS 2. MAPS supports plain XCDR1 samples, including big- and little-endian encoding, through the schema library's CdrFormatter.
The formatter requires a definition of the payload layout. It can compile a supported subset of DDS IDL, an ordered JSON Schema with CDR metadata, or a native ordered CDR field schema. The definition is compiled once when the formatter is created; the same compiled field layout is reused for subsequent messages.
1. Description
CDR is a schema-driven binary format. The order, width and alignment of fields determine the exact wire representation.
- Signed and unsigned integer widths of 8, 16, 32 and 64 bits
float32,float64, Boolean, 8-bit character and UTF-8 string values- Nested structures, fixed-length arrays and variable-length sequences
- Plain XCDR1 encapsulation headers (
CDR_BEandCDR_LE) - JSON encoding/decoding, structured field lookups and selector access through
ParsedObject
CDR differs from CBC: CDR uses byte alignment and fixed-width primitive encodings, whereas CBC is a bit-packed layout.
2. Schema Definition
The schema object of a SchemaConfig with format: "cdr" must contain exactly one of:
fields— an ordered native CDR field description.idl— source text containing a supported IDL definition, with optionaltypeName.properties— a JSON Schema object with explicitx-cdr-orderand numeric formats.
The optional littleEndian property selects the encoding endianness (default: true). Decoding reads the endianness from the incoming CDR header.
2.1 IDL
Example Reading.idl:
module telemetry {
typedef unsigned long SensorId;
struct Position {
float latitude;
float longitude;
};
struct Reading {
SensorId sensorId;
Position position;
double temperature;
sequence<short> samples;
};
};
Supply the IDL as a string in schema.idl, and select telemetry::Reading using schema.typeName. If the IDL contains exactly one struct, the type name may be omitted.
The current IDL parser supports structs, modules, typedefs, named type references, primitives, fixed-size arrays and unbounded sequences. It is not a general-purpose OMG IDL compiler. Enums, unions, annotations, bounded sequences and other unsupported declarations are rejected.
2.2 Native ordered CDR schema
{
"fields": [
{ "name": "sensorId", "type": "uint32" },
{ "name": "temperature", "type": "float64" },
{ "name": "samples", "type": "sequence", "element": "int16" },
{
"name": "location",
"type": "struct",
"fields": [
{ "name": "latitude", "type": "float32" },
{ "name": "longitude", "type": "float32" }
]
}
]
}
Field order is significant. Each field requires name and type. Structures use fields; collections use element, and fixed arrays also require length. Supported type aliases include short/int16, long/int32, longlong/int64, float/float32 and double/float64.
2.3 JSON Schema with explicit CDR layout
Ordinary JSON Schema does not specify CDR field ordering or integer widths. MAPS therefore requires x-cdr-order at each object level, and explicit format or x-cdr-type for numeric fields.
{
"type": "object",
"x-cdr-order": ["sensorId", "temperature", "samples"],
"properties": {
"samples": {
"type": "array",
"items": { "type": "integer", "format": "int16" }
},
"temperature": { "type": "number", "format": "float64" },
"sensorId": { "type": "integer", "format": "uint32" }
}
}
An array with identical minItems and maxItems is compiled as a fixed array; an array without those limits is a sequence. Bounded variable-length sequences are not yet supported. $ref resolution is not currently implemented.
3. SchemaConfig Example
CDR schemas use the same registration and lifecycle metadata model as other MAPS formats.
{
"versionId": "1",
"name": "Temperature-CDR",
"description": "Temperature reading encoded using plain XCDR1",
"format": "cdr",
"schema": {
"fields": [
{ "name": "sensorId", "type": "uint32" },
{ "name": "temperature", "type": "float64" },
{ "name": "timestamp", "type": "int64" }
]
}
}
For IDL, replace the schema value with:
{
"idl": "struct Reading { unsigned long sensorId; double temperature; long long timestamp; };",
"typeName": "Reading"
}
The .idl filename is not a separate SchemaConfig format. The caller reads the IDL file and supplies its contents to the CDR configuration.
4. Java Usage
4.1 Loading an IDL file
String idl = Files.readString(Path.of("Reading.idl"), StandardCharsets.UTF_8);
CdrSchemaConfig config = new CdrSchemaConfig();
config.setIdl(idl, "telemetry::Reading");
MessageFormatter formatter =
MessageFormatterFactory.getInstance().getFormatter(config);
The example uses java.nio.file.Files, Path and StandardCharsets alongside CdrSchemaConfig, MessageFormatter and MessageFormatterFactory.
4.2 Loading a CDR JSON schema file
String source = Files.readString(Path.of("Reading.cdr"), StandardCharsets.UTF_8);
JsonObject definition = JsonParser.parseString(source).getAsJsonObject();
CdrSchemaConfig config = new CdrSchemaConfig();
config.setSchema(definition);
MessageFormatter formatter =
MessageFormatterFactory.getInstance().getFormatter(config);
For an extended JSON Schema, use config.setJsonSchema(definition). Both inputs are compiled on formatter creation.
4.3 Encoding and decoding an event
JsonObject event = new JsonObject();
event.addProperty("sensorId", 7);
event.addProperty("temperature", 21.5);
event.addProperty("timestamp", 1794301200000L);
byte[] payload = formatter.parseFromJson(event);
JsonObject decoded = formatter.parseToJson(payload, ParseMode.STRICT);
ParsedObject parsed = formatter.parse(payload, ParseMode.STRICT);
Object temperature = parsed.get("temperature");
This example uses the three-field Temperature-CDR schema above. parse() exposes structured lookup through the shared ParsedObject API, including nested field paths and array indexes. With ParseMode.IGNORE, a failed parse() falls back to the unparsed byte payload.
5. Wire Representation
Plain XCDR1 samples begin with a four-byte encapsulation header:
| Header | Meaning |
|---|---|
00 00 00 00 | Plain CDR, big-endian |
00 01 00 00 | Plain CDR, little-endian |
Values follow in schema order, with the required CDR alignment. Strings carry a 32-bit length including the terminating NUL; sequences carry a 32-bit element count. Arrays have a fixed element count defined by the schema.
For example, a single uint32 field with the value 305419896 (0x12345678) encodes as:
Little-endian: 00 01 00 00 78 56 34 12
Big-endian: 00 00 00 00 12 34 56 78
6. Limitations and Best Practices
- Plain XCDR1 only. XCDR2, parameter-list CDR and IDL unions are not supported by this formatter.
- Match the exact source schema. Field reordering or changing widths will change the binary layout.
- Preserve the source IDL or native CDR layout when registering and versioning schemas.
- The
uint64binary codec andparseToJson()can represent the full unsigned range, but exactuint64numeric values throughParsedObjectand some selector paths remain a known limitation. Do not assume all 64-bit unsigned identifiers remain exact when accessed as untyped Java numbers. - This is a payload formatter, not a DDS transport, discovery service or ROS 2 client.
The schemas repository includes JUnit tests and independently sourced ROS 2 and eProsima Fast-CDR golden vectors for supported XCDR1 layouts.