Purpose: To provide a comprehensive user guide and reference for all standard annotations available in Chronicle Wire, detailing their purpose, usage, and impact on serialisation.
Chronicle Wire leverages Java annotations to provide developers with fine-grained control over the serialisation and deserialisation process. Annotations offer a declarative way to customise data representation, optimise for performance or size, add metadata, and aid in schema evolution, often without needing to write complex custom marshalling logic.
This document serves as a comprehensive guide to the standard annotations provided by Chronicle Wire. For each annotation, it details:
-
Its primary purpose and intended use case.
-
Where it can be applied (e.g., fields, types).
-
Any attributes or parameters it accepts.
-
Its specific behaviour and impact on different wire formats (text vs. binary).
-
Practical examples to illustrate its usage.
Understanding these annotations is key to effectively tailoring Chronicle Wire to your specific application needs, whether for human readability, extreme performance, or robust data versioning. This guide aims to fulfil the requirements for such documentation by being that guide.
Chronicle Wire annotations can be broadly categorised based on their primary function:
-
Data Conversion & Formatting: These annotations alter how a Java data type is represented on the wire, often to optimise for space, performance, or human readability in text formats.
-
Schema Definition & Metadata: These annotations provide metadata about fields or types, which can influence how data is structured, aid in schema evolution, or add descriptive information.
-
Marshalling Control (Less Common for Direct Wire Annotations): While direct field inclusion/exclusion is often handled by Java’s
transientkeyword or the inherent behaviour ofMarshallable, some annotations might subtly influence what or how data is marshalled.
This guide will explore annotations primarily from the first two categories.
These annotations are crucial for controlling the on-wire representation of your data.
- Purpose
-
The
@LongConversionannotation is a powerful meta-annotation used to specify that alongfield in Java should be converted to and from a different representation (typically a String) when serialised to text-based wire formats, while remaining alongin binary formats. This is extremely useful for compactly storing short textual identifiers or codes within an 8-byte long. - Target
-
Field (of type
long) - Attributes
value(Class<? extends LongConverter>)-
Specifies the
LongConverterimplementation class to use for the conversion. - Behaviour
-
-
Text Formats (YAML, JSON): The
LongConverter’s `asString(long)method is called to produce a String representation for the output. During input,parse(CharSequence)is called to convert the String back to along. -
Binary Formats: The field is serialised directly as a standard
long(typically 8 bytes). The conversion logic is not applied.
-
- Use Case
-
Storing short alphanumeric IDs, symbols, or codes (e.g., currency pairs, stock tickers, status codes) that can be mapped to a
longfor efficient storage and processing, but need to be human-readable in configurations or logs. - Example
-
While
@LongConversionis the base, Chronicle Wire provides several convenient pre-defined annotations that use specific converters:
- Annotations
-
@Base32,@Base64,@Base85(these are meta-annotated with@LongConversionpointing to respectiveBaseNLongConverterimplementations). - Purpose
-
To store short strings (composed of characters from the respective BaseN alphabet) within a
int, up to 5 characters, orlongupt o 10 characters.-
@Base32: Uses a 32-character alphabet. Can store up to 12 characters in along. -
@Base64: Uses a 64-character alphabet (A-Z, a-z, 0-9, +, /). Can store up to 10 characters in along. -
@Base85: Uses an 85-character alphabet. Can store up to 10 (sometimes 11 depending on exact character values) characters more efficiently than Base64 for certain character sets.
-
@Base64)import net.openhft.chronicle.wire.SelfDescribingMarshallable;
import net.openhft.chronicle.wire.converter.Base64;
public class StockInfo extends SelfDescribingMarshallable {
@Base64
private long stockSymbol; // e.g., "GOOGL"
private double price;
public StockInfo(String symbolStr, double price) {
this.stockSymbol = Base64.INSTANCE.parse(symbolStr); // Use the converter instance
this.price = price;
}
public String getStockSymbol() {
return Base64.INSTANCE.asString(this.stockSymbol);
}
// ... price getter
}# In YAML output:
!StockInfo {
symbol: GOOGL, // ShortText encoded as Base 85
price: 123.45 // 64-bit floating point
}- Status
-
Stable
- Purpose
-
Provides a concise way to convert short strings (up to ten characters) to and from a
intup to 5 characters, orlongup to 10 characters. using theShortTextLongConverter. It is a specialised form of@LongConversionand internally relies on the same Base85-based encoding as@Base85.
The difference between @ShortText and @Base85 is that @ShortText truncates leading spaces and @Base85 truncates leading zeros.
e.g. @ShortText will convert " 123" to "123" and @Base85 will convert "000123" to "123".
- Target
-
Field (of type
long) - Behaviour
-
-
Text Formats: Values appear as Base 85 strings.
-
Binary Formats: Values are stored as eight-byte longs.
-
- Use Case
-
Compact storage of short identifiers or codes while keeping them readable in YAML/JSON. It acts as a shorthand for
@LongConversion(ShortTextLongConverter.class).
@ShortText)import net.openhft.chronicle.wire.converter.ShortText;
public class Order extends SelfDescribingMarshallable {
@ShortText
private long market;
}- Annotations
-
@NanoTime - Purpose
-
To format
longfields representing timestamps (nanoseconds or milliseconds since epoch, respectively) as human-readable ISO 8601 date-time strings in text formats, while storing them aslongvalues in binary formats and in Java. - Target
-
Field (of type
long) - Behaviour
-
-
Text Formats (YAML, JSON): Converts the
longtimestamp to an ISO 8601 string (e.g.,2023-10-27T10:15:30.123456789Z). -
Binary Formats: Stores the
longvalue directly.
-
- Use Case
-
Storing precise timestamps efficiently while allowing easy human inspection in logs or configuration files.
@NanoTime)import net.openhft.chronicle.wire.SelfDescribingMarshallable;
import net.openhft.chronicle.wire.converter.NanoTime; // The annotation
public class LogEntry extends SelfDescribingMarshallable {
@NanoTime
private long eventTimestamp;
private String message;
public LogEntry(long eventTimestamp, String message) {
this.eventTimestamp = eventTimestamp;
this.message = message;
}
// ... getters
}!LogEntry {
eventTimestamp: 2025-05-30T07:30:05.123456789Z, // ISO 8601 format
message: System initialised
}These annotations provide additional information about fields or types, primarily aiding in schema evolution, binary format stability, or human-readable documentation.
- Status
-
Road Map
- Purpose
-
To assign a persistent, explicit numeric identifier to a field. This is primarily used in some binary wire formats (
BINARY,BINARY_LIGHT) where fields might be identified by number instead of, or in addition to, their names. - Target
-
Field
- Attributes
value(int)-
The unique numeric identifier for the field.
- Behaviour
-
-
Binary Formats: The specified field number is written to the wire instead of/alongside the field name. This allows the Java field name to be refactored (renamed) without breaking binary compatibility, as long as the
@FieldNumberremains the same. -
Text Formats: Generally has no direct effect on the output (field names are used).
-
- Use Case
-
Ensuring long-term binary compatibility and allowing safe refactoring of field names in
Marshallableclasses when using number-based binary field identification. - Example
import net.openhft.chronicle.wire.FieldNumber;
import net.openhft.chronicle.wire.SelfDescribingMarshallable;
public class FinancialInstrument extends SelfDescribingMarshallable {
@FieldNumber(1)
private String instrumentId; // Was perhaps "ticker" before, renamed to "instrumentId"
@FieldNumber(2)
private double lastPrice;
// ...
}|
Important
|
Ensure field numbers are unique within a class hierarchy if polymorphism and shared binary formats are involved. |
- Purpose
-
To give a
Marshallabletype an explicit, repeatable field serialisation order instead of relying on reflection order. - Target
-
Type
- Attributes
value(String[])-
The names of all non-static, non-transient marshallable fields declared directly on the annotated class, in the order they should be written. Names are trimmed before validation and lookup.
- Behaviour
-
-
Text Formats: Fields are emitted in the declared order, which keeps string and YAML assertions stable across JVMs.
-
Binary Formats: Named-field binary formats use the same marshaller field order when writing fields. Formats that omit field names remain sensitive to sender and receiver schema agreement.
-
Inheritance: The annotation applies only to fields declared directly on the annotated class. Inherited fields keep the order declared by their own class.
-
Validation: Chronicle Wire rejects incomplete lists, duplicate names, blank names, and names that do not resolve to marshallable fields.
-
- Use Case
-
Stabilising serialised output for classes whose field order is part of a test fixture, text dump, or fieldless/named binary compatibility contract.
- Example
import net.openhft.chronicle.wire.FieldOrder;
import net.openhft.chronicle.wire.SelfDescribingMarshallable;
@FieldOrder({"baseId", "createdTime"})
class Base extends SelfDescribingMarshallable {
long createdTime;
long baseId;
}
@FieldOrder({"symbol", "price", "quantity"})
class Trade extends Base {
double price;
String symbol;
long quantity;
}The resulting order is baseId, createdTime, then symbol, price, quantity.
- Purpose
-
To add a descriptive comment to a field, which will be included in some text-based wire formats, typically YAML.
- Target
-
Field
- Attributes
value(String)-
The comment text.
- Behaviour
-
-
YAML Format: The comment is usually rendered preceding the field.
-
JSON/Binary Formats: This annotation is generally ignored.
-
- Use Case
-
Improving the readability and self-documentation of configuration files or data dumps generated in YAML format.
- Example
import net.openhft.chronicle.wire.Comment;
import net.openhft.chronicle.wire.SelfDescribingMarshallable;
public class AppConfig extends SelfDescribingMarshallable {
@Comment("The network port for the primary service")
private int servicePort;
@Comment("Connection timeout in milliseconds")
private int connectionTimeoutMs;
// ...
}AppConfig {
# The network port for the primary service
servicePort: 8080,
# Connection timeout in milliseconds
connectionTimeoutMs: 5000
}-
Be Purposeful: Use annotations where they add clear value, such as improving readability in text formats (
@Comment,@NanoTime), optimising binary size/performance (@LongConversion,@FieldNumber), or ensuring schema stability (@FieldNumber,@FieldOrder). -
Understand Format Impact: Be aware that some annotations only affect text formats (e.g.,
@Comment), while others primarily impact binary formats (e.g., `@FieldNumber’s core use). -
Consistency: Apply annotations consistently across related
Marshallableclasses for predictable behaviour. -
Test Thoroughly: When using annotations that affect data representation or schema (like
@LongConversion,@FieldNumber, or@FieldOrder), thoroughly test both serialisation and deserialisation, especially across different versions of your classes if schema evolution is a concern. -
Consult Javadoc: The Javadoc for each annotation is the ultimate source of truth for its specific attributes and behaviour in the version of Chronicle Wire you are using.
-
Keep it Simple: While powerful, avoid over-using annotations if simpler solutions suffice. The default behaviour of
SelfDescribingMarshallableis often sufficient for many use cases.
This guide provides a solid foundation for understanding and utilising the annotations within Chronicle Wire to build efficient, flexible, and maintainable Java applications.
-
Architecture Overview - Understand the internal architecture of Chronicle Wire
-
Working with Annotations - Practical examples of using annotations
-
Role of Annotations in Schema Evolution - How annotations help with schema evolution
-
Error Handling and Diagnostics - Troubleshooting and error handling
-
Documentation Home - Return to the main documentation page