Embedded entities are lifecycle-managed objects that enable zero-garbage composition of complex messages. They are reusable, pooled objects embedded within messages or state objects.
Overview
Embedded entities allow you to compose complex, nested data structures within messages and state while maintaining zero-garbage characteristics. Instead of allocating new objects for each nested structure, embedded entities are pooled and reused across message processing cycles.
Declaring Embedded Entities
Embedded entities are declared in ADM using the entity type with the embedded="true" attribute:
Embedded entities have a strict lifecycle that must be managed correctly to achieve zero-garbage operation. The ADM code generator produces methods to manage this lifecycle:
Method
Description
Returns
getXXX()
Returns a reference to the embedded entity. Object remains owned by the parent.
Read-only reference
takeXXX()
Removes the embedded entity from the parent and transfers ownership to the caller. The parent's field becomes null.
Transferred entity
lendXXX()
Returns a reference for modification. Object ownership remains with the parent.
Mutable reference
setXXX(Entity)
Sets the embedded entity. If a non-null entity already exists, it is disposed. The provided entity is copied if not already owned.
void
Using getXXX()
The getXXX() accessor returns a read-only reference to the embedded entity. The parent retains ownership and the returned object should not be modified:
Important: The returned entity may be reset or reused after the message handler returns. Do not hold references to embedded entities beyond the scope of the handler.
Using takeXXX()
The takeXXX() method transfers ownership of the embedded entity from the parent to the caller:
After calling takeXXX(), the parent's field becomes null, and the caller is responsible for disposing the entity when finished.
Using lendXXX()
The lendXXX() method returns a reference for modification while the parent retains ownership:
The lendXXX() pattern is the most common for zero-garbage updates to embedded entities.
Using setXXX()
The setXXX() method sets the embedded entity value:
If an entity already exists in the parent when setXXX() is called, the old entity is automatically disposed.
Serialization and Deserialization
Embedded entities are automatically serialized and deserialized with their parent message. When a message containing embedded entities is sent, the entities are serialized as part of the message payload. When received, they are deserialized and populated from the message content.
Pass-Through Fields
Embedded entities support "pass-through" behavior where incoming message entities can be efficiently transferred to outbound messages without deep copying:
This pattern avoids copying the embedded entity's data, achieving zero-garbage pass-through.
@EventHandler
public void onOrder(Order order) {
OrderLine line = order.getLine();
if (line != null) {
String symbol = line.getSymbol();
// Read fields, but don't modify
}
}
@EventHandler
public void onOrder(Order order) {
// Take ownership of the line
OrderLine line = order.takeLine();
// Parent's line field is now null
assert order.getLine() == null;
// We now own the line and can modify it
line.setQuantity(100);
// Must dispose when done to return to pool
line.dispose();
}
@EventHandler
public void onOrder(Order order) {
// Get a mutable reference
OrderLine line = order.lendLine();
if (line == null) {
// Create if doesn't exist - parent creates and owns
line = order.setLine(new OrderLineXbufEntity());
}
// Modify directly - parent still owns
line.setQuantity(100);
line.setPrice(150.25);
// No dispose needed - parent still owns
}
@EventHandler
public void onOrder(Order order) {
// Create a new line
OrderLine line = new OrderLineXbufEntity();
line.setSymbol("AAPL");
line.setQuantity(100);
// Set on parent - parent takes ownership
order.setLine(line);
// Parent now owns it, no dispose needed
}
@EventHandler
public void onOrder(Order incomingOrder, MessageView view) {
// Create outbound order
OrderAck ack = new OrderAckXbufMessage();
// Take from incoming (transfers ownership)
OrderLine line = incomingOrder.takeLine();
// Set on outgoing (transfers ownership again)
ack.setLine(line);
// Send ack
view.send(ack);
}
OrderLine line = order.lendLine();
if (line == null) {
order.setLine(new OrderLineXbufEntity());
line = order.lendLine();
}
line.setQuantity(100);
OrderLine line = order.takeLine();
if (line != null) {
line.dispose(); // Returns to pool
}
// order.getLine() is now null
OrderLine line = order.lendLine();
if (line != null) {
line.setSymbol("AAPL");
line.setQuantity(100);
line.setPrice(150.25);
}