diff --git a/AGENTS.md b/AGENTS.md
index 7893d737ad..39074fc5d8 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -1,5 +1,7 @@
# Guidance for AI agents, bots, and humans contributing to Chronicle Software's OpenHFT projects.
+Follow the root `AGENTS.md` for base rules; this file adds Chronicle-Wire specifics. Durable docs live in `src/main/docs/` with the landing page at `README.adoc`.
+
LLM-based agents can accelerate development only if they respect our house rules. This file tells you:
* how to run and verify the build;
@@ -11,8 +13,8 @@ LLM-based agents can accelerate development only if they respect our house rules
| Requirement | Rationale |
|--------------|-----------|
| **British English** spelling (`organisation`, `licence`, *not* `organization`, `license`) except technical US spellings like `synchronized` | Keeps wording consistent with Chronicle's London HQ and existing docs. See the [University of Oxford style guide](https://www.ox.ac.uk/public-affairs/style-guide) for reference. |
-| **ISO-8859-1** (code-points 0-255). Avoid smart quotes, non-breaking spaces and accented characters. | ISO-8859-1 survives every toolchain Chronicle uses, incl. low-latency binary wire formats that expect the 8th bit to be 0. |
-| If a symbol is not available in ISO-8859-1, use a textual form such as `micro-second`, `>=`, `:alpha:`, `:yes:`. This is the preferred approach and Unicode must not be inserted. | Extended or '8-bit ASCII' variants are *not* portable and are therefore disallowed. |
+| **ISO-8859-1** (code-points 0-255). Avoid smart quotes, non-breaking spaces and accented characters. | ISO-8859-1 survives every toolchain Chronicle uses. |
+| If a symbol is not available in ISO-8859-1, use a textual form such as `>=`, `:alpha:`, `:yes:`. This is the preferred approach and Unicode must not be inserted. | Extended or '8-bit ASCII' variants are *not* portable and are therefore disallowed. |
| Tools to check ASCII compliance include `iconv -f ascii -t ascii` and IDE settings that flag non-ASCII characters. | These help catch stray Unicode characters before code review. |
## Javadoc guidelines
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000000..056bb5908f
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,346 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Repository Overview
+
+Chronicle-Wire is a high-performance, low-latency serialisation library providing a format-agnostic Wire API over Chronicle Bytes. It supports multiple wire formats (YAML, JSON, CSV, binary) with the same API, enabling easy format switching and schema evolution. Chronicle-Wire is part of the OpenHFT Chronicle stack and sits in Layer 1 (Data Structures & Serialisation).
+
+**Key Features:**
+- Multiple wire formats (text and binary) with a unified API
+- Zero-allocation, off-heap serialisation
+- Schema evolution support (field reordering, optional fields, type changes)
+- MethodWriter/MethodReader for event-driven architectures
+- Integration with Chronicle Queue, Map, Network, and Services
+
+**Dependencies:**
+- `chronicle-core` - Low-level utilities, resource management
+- `chronicle-bytes` - Off-heap memory access
+- `chronicle-threads` - Thread management
+- `compiler` - Runtime Java compilation for method writers/readers
+
+## Build Commands
+
+### Prerequisites
+
+- **Java 1.8** (required - later versions may cause warnings)
+- Maven 3.6+
+
+### Core Build Commands
+
+```bash
+# Clean build with tests
+mvn clean verify
+
+# Build without tests (faster iteration)
+mvn clean install -DskipTests
+
+# Run specific test class
+mvn test -Dtest=ClassName
+
+# Run specific test method
+mvn test -Dtest=ClassName#methodName
+```
+
+### Code Quality Checks
+
+```bash
+# Run Checkstyle (disabled by default)
+mvn checkstyle:check -Dcheckstyle.skip=false
+
+# Run SpotBugs
+mvn spotbugs:check
+
+# Sort POM file (on demand, not automatic)
+mvn sortpom:sort
+```
+
+### Performance Testing
+
+```bash
+# Run JLBH benchmarks
+mvn test -Prun-benchmarks
+
+# Run network performance tests (requires two terminals)
+# Terminal 1: Start gateway
+mvn exec:java@Gateway
+
+# Terminal 2: Run latency test
+mvn exec:java@EchoClient -Durl=tcp://localhost:1248
+
+# Terminal 2: Run throughput test
+mvn exec:java@EchoThroughput -Durl=tcp://localhost:1248
+```
+
+## Project Structure
+
+```
+Chronicle-Wire/
+├── src/
+│ ├── main/
+│ │ ├── java/net/openhft/chronicle/wire/
+│ │ │ ├── *.java # Core Wire implementation
+│ │ │ ├── converter/ # LongConverter implementations
+│ │ │ ├── domestic/ # Domestic message channel support
+│ │ │ ├── internal/ # Internal utilities (not public API)
+│ │ │ └── utils/ # Utility classes
+│ │ └── docs/ # AsciiDoc documentation (canonical)
+│ │ ├── architecture-overview.adoc
+│ │ ├── functional-requirements.adoc
+│ │ ├── wire-cookbook.adoc
+│ │ └── ...
+│ └── test/
+│ └── java/net/openhft/chronicle/wire/ # Unit and integration tests
+├── demo/ # Example applications
+├── marshallingperf/ # Marshalling performance benchmarks
+├── microbenchmarks/ # JMH microbenchmarks
+├── docs/ # Additional documentation
+├── AGENTS.md # AI agent contribution guidelines
+├── README.adoc # User-facing documentation
+└── pom.xml
+```
+
+## Architecture Overview
+
+### Core Abstractions
+
+**Wire API:**
+- `Wire` - Main interface for serialisation/deserialisation
+- `WireIn` - Reading operations
+- `WireOut` - Writing operations
+- `WireType` - Enum selecting format (TEXT, BINARY, JSON, YAML, CSV, RAW, etc.)
+
+**Marshallable Pattern:**
+- `Marshallable` - Interface for custom serialisation
+- `SelfDescribingMarshallable` - Auto-generates `toString()`, `equals()`, `hashCode()`
+- `BytesInBinaryMarshallable` - Optimised binary format without field names
+- `DocumentContext` - Message framing and lifecycle management
+
+**Method Writers/Readers:**
+- `MethodWriter` - Converts method calls to wire events (bytecode generation)
+- `MethodReader` - Reads wire events and invokes methods
+- Used for event-driven architectures and Chronicle Queue integration
+
+**Annotations:**
+- `@FieldNumber(n)` - Assign field numbers for compact binary encoding
+- `@MethodId(n)` - Assign method IDs for compact method encoding
+- `@LongConversion(Converter.class)` - Custom long converters (timestamps, base64, etc.)
+- `@AsMarshallable` - Force marshalling instead of pass-by-name for DynamicEnum
+
+### Wire Format Hierarchy
+
+```
+Text Formats: Binary Formats:
+- TextWire (YAML) - BinaryWire (self-describing)
+- JSONWire - RawWire (minimal metadata)
+- CSVWire - FieldlessBinaryWire
+- YamlWire
+
+Special:
+- ReadAnyWire (auto-detect format)
+```
+
+### Key Design Patterns
+
+- **Strategy Pattern:** `WireType` selects serialisation strategy
+- **Flyweight Pattern:** Objects act as views over `Bytes` data
+- **Single Writer Principle:** One writer per `Bytes` instance
+- **Zero-Copy:** Direct access to off-heap memory via Chronicle Bytes
+- **Dynamic Compilation:** MethodWriter/Reader generated at runtime via `compiler` module
+
+## Common Development Tasks
+
+### Running a Single Test
+
+```bash
+# By class name
+mvn test -Dtest=MarshallableTest
+
+# By method
+mvn test -Dtest=MarshallableTest#testSimpleMarshallable
+
+# With system property (e.g., UTC timezone required for some tests)
+mvn test -Dtest=Issue327Test -Duser.timezone=UTC
+```
+
+### Adding a New Wire Format
+
+1. Implement `Wire` interface or extend `AbstractWire`
+2. Add entry to `WireType` enum
+3. Implement `WireIn` and `WireOut` methods
+4. Add tests in `src/test/java/.../wire/`
+5. Update documentation in `src/main/docs/`
+
+### Working with Marshallable Objects
+
+**Basic DTO:**
+```java
+class MyData extends SelfDescribingMarshallable {
+ String field1;
+ int field2;
+ // No need for toString(), equals(), hashCode()
+}
+```
+
+**Custom Serialisation:**
+```java
+class CustomData implements Marshallable {
+ @Override
+ public void writeMarshallable(WireOut wire) {
+ wire.write("field1").text(field1)
+ .write("field2").int32(field2);
+ }
+
+ @Override
+ public void readMarshallable(WireIn wire) {
+ field1 = wire.read("field1").text();
+ field2 = wire.read("field2").int32();
+ }
+}
+```
+
+### Schema Evolution
+
+Chronicle-Wire supports:
+- Adding/removing fields (use `unexpectedField()` handler)
+- Changing field order
+- Optional fields with defaults
+- Field type changes (with caution)
+- Version numbers in `BytesInBinaryMarshallable`
+
+See `src/main/docs/wire-schema-evolution.adoc` for details.
+
+## Testing Strategy
+
+**Test Categories:**
+- Unit tests: `*Test.java` - Verify individual components
+- Integration tests: `*IT.java` - Multi-component scenarios
+- Performance tests: `*JLBH.java` - Latency benchmarks using JLBH framework
+- JMH benchmarks: `microbenchmarks/` - Detailed microbenchmarks
+
+**Resource Management:**
+Use `assertReferencesReleased()` from `chronicle-test-framework` to verify off-heap resources are freed:
+
+```java
+@Test
+public void testExample() {
+ try (Bytes> bytes = Bytes.allocateElasticOnHeap()) {
+ // test code
+ }
+ // chronicle-test-framework verifies cleanup
+}
+```
+
+## Documentation Standards
+
+- **Format:** AsciiDoc (`.adoc`)
+- **Location:** `src/main/docs/` (canonical) or legacy `docs/`
+- **Language:** British English (e.g., "serialisation", "behaviour")
+- **Encoding:** ISO-8859-1 (avoid Unicode, smart quotes)
+- **Source highlighter:** `:source-highlighter: rouge`
+
+**Key Documentation Files:**
+- `architecture-overview.adoc` - High-level architecture
+- `functional-requirements.adoc` - Functional requirements catalog
+- `wire-cookbook.adoc` - Practical recipes
+- `wire-schema-evolution.adoc` - Schema evolution guide
+- `wire-faq.adoc` - Common questions
+- `decision-log.adoc` - Architectural decisions
+
+See `AGENTS.md` for detailed documentation guidelines.
+
+## Code Style
+
+Chronicle-Wire follows OpenHFT conventions:
+
+- **Indentation:** 4 spaces (no tabs)
+- **Brace style:** K&R (opening brace on same line)
+- **Naming:**
+ - Classes: `PascalCase`
+ - Methods/variables: `camelCase`
+ - Constants: `UPPER_SNAKE_CASE`
+- **Javadoc:** Focus on behavior, constraints, thread-safety - not restating the obvious
+- **ISO-8859-1 only:** No Unicode characters
+
+### Checkstyle
+
+The project uses `chronicle-baseline-checkstyle.xml`. Test sources are globally exempt.
+
+To run manually:
+```bash
+mvn checkstyle:check -Dcheckstyle.skip=false \
+ -Dcheckstyle.config.location=net/openhft/quality/checkstyle27/chronicle-baseline-checkstyle.xml
+```
+
+## Performance Considerations
+
+Chronicle-Wire is designed for low-latency, zero-allocation operation:
+
+- **Reuse objects:** Use `reset()` and object pooling to avoid allocation
+- **Off-heap access:** Work directly with `Bytes` to minimise GC pressure
+- **Binary formats:** Use `BinaryWire` or `RawWire` for production hot paths
+- **Text formats:** Use `TextWire`/`JSONWire` for configuration and debugging
+- **Method Writers:** Bytecode-generated, minimal overhead for event dispatch
+- **LongConverters:** Store metadata (timestamps, IDs) efficiently in long fields
+
+## Integration with Other Chronicle Components
+
+**Chronicle Queue:**
+- Uses `Wire` for message serialisation
+- `MethodWriter` creates tailer/appender proxies
+- `MethodReader` processes queue excerpts
+
+**Chronicle Map:**
+- Marshallable keys and values
+- Off-heap persistence via Wire serialisation
+
+**Chronicle Network:**
+- Wire formats for TCP message protocols
+- `ChronicleChannel` extends `MarshallableIn`/`MarshallableOut`
+
+**Chronicle Services:**
+- Event contracts via `MethodWriter`/`MethodReader`
+- Microservice message dispatch
+
+## Troubleshooting
+
+### Build Failures
+
+**Compiler warnings breaking build:**
+- Ensure Java 1.8 is used (not 11, 17, 21)
+- Check `JAVA_HOME` points to JDK 8
+
+**Test failures:**
+- Some tests require UTC timezone: `-Duser.timezone=UTC`
+- Resource cleanup: Verify `assertReferencesReleased()` in test framework
+
+### Dynamic Compilation Issues
+
+MethodWriter/Reader use runtime compilation. If compilation fails:
+
+1. Check `compiler` dependency is available
+2. Verify classpath includes source interfaces
+3. For Spring Boot fat JARs, extract Chronicle JARs (see README.adoc "Spring Boot" section)
+
+### Schema Evolution Problems
+
+- Check `unexpectedField()` handler for unknown fields
+- Verify field types are compatible
+- Use version numbers in `BytesInBinaryMarshallable` for breaking changes
+
+## Important Notes
+
+1. **Java Version:** Always use Java 1.8 for builds to avoid compiler warnings
+2. **Off-heap Resources:** Must be explicitly released - use try-with-resources and test framework assertions
+3. **Thread Safety:** Wire instances are not thread-safe - use one per thread or synchronise access
+4. **Performance Testing:** Use JLBH for realistic latency measurements (not JMH for latency)
+5. **Binary Compatibility:** Check `binary-compatibility-enforcer-plugin` before releases
+
+## Additional Resources
+
+- [README.adoc](README.adoc) - User guide with examples
+- [AGENTS.md](AGENTS.md) - Contribution guidelines for AI agents and humans
+- [Documentation Index](src/main/docs/index.adoc) - Complete documentation catalog
+- [TODO.md](TODO.md) - Development roadmap and architecture work
+- GitHub Issues: https://github.com/OpenHFT/Chronicle-Wire/issues
+- Chronicle Software: https://chronicle.software/
diff --git a/GEMINI.md b/GEMINI.md
new file mode 100644
index 0000000000..cf7ea8d44a
--- /dev/null
+++ b/GEMINI.md
@@ -0,0 +1,56 @@
+# Chronicle Wire Analysis
+
+## Project Overview
+
+Chronicle Wire is a high-performance, zero-garbage collection (GC) serialisation library for Java. It is designed for low-latency applications, such as inter-process communication (IPC) and in-memory state persistence. The library is part of the Chronicle stack, developed by OpenHFT.
+
+The core feature of Chronicle Wire is its ability to abstract the underlying wire format, allowing developers to switch between human-readable formats (like YAML) and compact binary formats without changing the API. This flexibility makes it suitable for a wide range of use cases, from configuration files to high-speed data transfer.
+
+### Key Features
+
+* **Multiple Wire Formats:** Supports YAML, JSON, CSV, and several binary formats.
+* **Schema Evolution:** Handles changes in data schemas, such as adding or removing fields.
+* **Low Latency:** Optimised for performance with low allocation rates.
+* **Format Conversion:** Provides automatic conversion between different wire formats.
+* **Integration:** Works seamlessly with other components of the Chronicle framework.
+
+## Building and Running
+
+The project is built using Apache Maven. The following commands can be used to build, test, and run the project.
+
+### Building the Project
+
+To build the project and install the artefacts into your local Maven repository, run the following command from the root directory of the project:
+
+```sh
+mvn clean install
+```
+
+### Running Tests
+
+To run the unit tests, use the following command:
+
+```sh
+mvn test
+```
+
+### Running Benchmarks
+
+The project includes a suite of benchmarks for measuring performance. To run the benchmarks, you can use the `run-benchmarks` profile:
+
+```sh
+mvn clean test -DskipTests -Prun-benchmarks
+```
+
+You can also run a specific benchmark using the `exec-maven-plugin`. For example, to run the `TriviallyCopyableJLBH` benchmark, you can use the command found in the `jlbh-test.sh` script:
+
+```sh
+mvn clean test-compile exec:java -Dexec.mainClass="net.openhft.chronicle.wire.TriviallyCopyableJLBH" -Dexec.classpathScope=test
+```
+
+## Development Conventions
+
+* **Code Style:** The project follows standard Java coding conventions. The use of JetBrains annotations suggests a preference for static analysis to improve code quality.
+* **Testing:** The project has a comprehensive set of unit tests written using JUnit. There is also a strong emphasis on performance testing, with a dedicated benchmark suite.
+* **Modularity:** The project is part of a larger ecosystem of libraries (the Chronicle stack) and is designed to be modular and extensible.
+* **Documentation:** The project has extensive documentation in the `README.adoc` file, as well as in the `docs` and `src/main/docs` directories.
diff --git a/README.adoc b/README.adoc
index d8e274147e..9938d7abff 100644
--- a/README.adoc
+++ b/README.adoc
@@ -1,11 +1,11 @@
= Chronicle Wire
-Chronicle Software
:pp: ++
-:css-signature: demo
+:sectnums:
:toc: macro
-:toclevels: 2
:icons: font
-:sectnums:
+:lang: en-GB
+:toclevels: 2
+:css-signature: demo
:source-highlighter: rouge
image:https://maven-badges.herokuapp.com/maven-central/net.openhft/chronicle-wire/badge.svg[link=https://maven-badges.herokuapp.com/maven-central/net.openhft/chronicle-wire]
@@ -30,9 +30,11 @@ Typical use cases include configuration files, persistence of in-memory state, a
* Schema evolution with optional field handling
* Low-latency, low-allocation serialisation of `Marshallable` POJOs
* Automatic conversion between formats
-* Integration with other Chronicle components === Why are these concerns conflated?
+* Integration with other Chronicle components
-Often you want to use these interchangeably.
+=== Why are these concerns conflated?
+
+Often you want to use these formats interchangeably.
* Configuration includes aliased type information.
This supports easy extension by adding new classes/versions, and cross-platform using type aliasing.
@@ -1143,7 +1145,8 @@ Other types are supported; for example, 32-bit integer values, and an array of 6
== Pass-by-name or Dynamic Enums
Chronicle Wire supports passing objects reference by the `name()` of the object referenced.
-This is supported trivially with `enum` which define a `name()` for you. e.g.
+This is supported trivially with `enum` which define a `name()` for you.
+e.g.
.Passing a reference to an enum using it's name
[source,java,opts=novalidate]
@@ -1299,7 +1302,10 @@ Only use them when there is likely to be a limited number of them over the life
== Using @MethodId
You can assign a method id to a method using the annotation `@MethodId(long int: id)`.
-The provided id should be unique across all classes using the same MethodReader/Writer, therefore it is safe practice to use unique method id in your entire system.A method name can be determined from its method id and this results in saving memory when calling the method.The following example shows the difference between memory usage when using method id and when not using it.In this example the method `saysomethingnice()` has been annotated with `MethodId(7)` and it has been called from `shouldDetermineMethodNamesFromMethodIds()`.
+The provided id should be unique across all classes using the same MethodReader/Writer, therefore it is safe practice to use unique method ids in your entire system.
+A method name can be determined from its method id and this results in saving memory when calling the method.
+The following example shows the difference between memory usage when using method ids and when not using them.
+In this example the method `saysomethingnice()` has been annotated with `MethodId(7)` and it has been called from `shouldDetermineMethodNamesFromMethodIds()`.
[source,java,opts=novalidate]
----
@@ -2109,12 +2115,15 @@ private static final int MASHALLABLE_VERSION = 1;
}
}
----
+
<1> You will have to remove this line if the class extends `AbstractBytesMarshallable`
=== JLBH Benchmark Performance
To explore the efficiency of the examples above, this link:https://github.com/OpenHFT/Chronicle-Wire/blob/develop/src/test/java/net/openhft/chronicle/wire/TriviallyCopyableJLBH.java[TrivallyCopyableJLBH.java] test was created.
-As can be seen on lines 18-26, we have the ability to switch between running the TriviallyCopyable House ("House1"), the BinaryWire House ("House2") or 'UNKNOWN'.Important to note is that trivially copyable objects were used in order to improve java serialisation speeds.For further understanding on trivially copyable objects, refer to link:https://dzone.com/articles/how-to-get-c-speed-in-java-serialisation[this article].
+As can be seen on lines 18-26, we have the ability to switch between running the TriviallyCopyable House ("House1"), the BinaryWire House ("House2") or 'UNKNOWN'.
+Important to note is that trivially copyable objects were used in order to improve Java serialisation speeds.
+For further understanding on trivially copyable objects, refer to link:https://dzone.com/articles/how-to-get-c-speed-in-java-serialisation[this article].
This shows that we can serialise and then de-serialise 100,000 messages in a second.The Trivially Copyable version is even faster, especially at the higher percentiles.
.Benchmark Performance Between TriviallyCopyable and BinaryWire
@@ -2178,9 +2187,9 @@ try (ChronicleContext context = ChronicleContext.newContext(url)) {
* link:src/main/docs/wire-cookbook.adoc[Cookbook]
* link:src/main/docs/wire-faq.adoc[FAQ]
* link:src/main/docs/wire-glossary.adoc[Glossary]
-* link:docs/EventsByMethod.adoc[Events by Method]
-* link:docs/YAML2SpecificationCompliance.adoc[YAML 1.2 Compliance]
-* link:docs/systemProperties.adoc[System Properties Guide]
+* link:src/main/docs/EventsByMethod.adoc[Events by Method]
+* link:src/main/docs/YAML2SpecificationCompliance.adoc[YAML 1.2 Compliance]
+* link:src/main/docs/system-properties.adoc[System Properties Guide]
== Community and Support
diff --git a/demo/src/main/java/run/chronicle/wire/demo/Example2.java b/demo/src/main/java/run/chronicle/wire/demo/Example2.java
index 69b0400b23..9a1e6e44ab 100644
--- a/demo/src/main/java/run/chronicle/wire/demo/Example2.java
+++ b/demo/src/main/java/run/chronicle/wire/demo/Example2.java
@@ -65,5 +65,4 @@ public static void main(String[] args) {
bytes.releaseLast();
bytes2.releaseLast();
}
-
}
diff --git a/demo/src/main/java/run/chronicle/wire/demo/Example4.java b/demo/src/main/java/run/chronicle/wire/demo/Example4.java
index da00e868b2..94e563c0d1 100644
--- a/demo/src/main/java/run/chronicle/wire/demo/Example4.java
+++ b/demo/src/main/java/run/chronicle/wire/demo/Example4.java
@@ -69,5 +69,4 @@ public static void main(String[] args) {
wire.bytes().releaseLast();
wire2.bytes().releaseLast();
}
-
}
diff --git a/demo/src/main/java/run/chronicle/wire/demo/Example5.java b/demo/src/main/java/run/chronicle/wire/demo/Example5.java
index c7efe96962..48255ebc3c 100644
--- a/demo/src/main/java/run/chronicle/wire/demo/Example5.java
+++ b/demo/src/main/java/run/chronicle/wire/demo/Example5.java
@@ -19,7 +19,6 @@
* - The reader (tailer) is blocked until the message is completely written.
* - Wire by default is single writer, implementations such as Queue can add support for concurrent writers
*/
-
public class Example5 {
public static void main(String[] args) {
diff --git a/demo/src/main/java/run/chronicle/wire/demo/mapreuse/IntMapper.java b/demo/src/main/java/run/chronicle/wire/demo/mapreuse/IntMapper.java
index 06419212ae..b1364e43aa 100644
--- a/demo/src/main/java/run/chronicle/wire/demo/mapreuse/IntMapper.java
+++ b/demo/src/main/java/run/chronicle/wire/demo/mapreuse/IntMapper.java
@@ -73,5 +73,4 @@ else if (cmp > 0)
}
return -(low + 1);
}
-
}
diff --git a/demo/src/main/java/run/chronicle/wire/demo/mapreuse/Mapper.java b/demo/src/main/java/run/chronicle/wire/demo/mapreuse/Mapper.java
index 668d0a9729..08b325e565 100644
--- a/demo/src/main/java/run/chronicle/wire/demo/mapreuse/Mapper.java
+++ b/demo/src/main/java/run/chronicle/wire/demo/mapreuse/Mapper.java
@@ -69,5 +69,4 @@ else if (cmp > 0)
}
return -(low + 1);
}
-
}
diff --git a/demo/src/main/java/run/chronicle/wire/demo/package-info.java b/demo/src/main/java/run/chronicle/wire/demo/package-info.java
new file mode 100644
index 0000000000..ecc262d67c
--- /dev/null
+++ b/demo/src/main/java/run/chronicle/wire/demo/package-info.java
@@ -0,0 +1,11 @@
+/*
+ * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * Demonstrations of Chronicle Wire usage.
+ *
+ * This package contains small example programs that showcase core Wire
+ * features such as marshalling, method readers and event-driven APIs.
+ */
+package run.chronicle.wire.demo;
diff --git a/marshallingperf/src/main/java/run/chronicle/wire/perf/MessageHistoryBytesMarshallableMain.java b/marshallingperf/src/main/java/run/chronicle/wire/perf/MessageHistoryBytesMarshallableMain.java
index 15bde76c70..d96853496c 100644
--- a/marshallingperf/src/main/java/run/chronicle/wire/perf/MessageHistoryBytesMarshallableMain.java
+++ b/marshallingperf/src/main/java/run/chronicle/wire/perf/MessageHistoryBytesMarshallableMain.java
@@ -10,9 +10,10 @@
import static run.chronicle.wire.perf.BytesInBytesMarshallableMain.histoOut;
/**
- * Benchmarks the performance of serialising and deserialising
- * {@link net.openhft.chronicle.wire.VanillaMessageHistory} objects using their
- * compact binary form.
+ * Benchmarks serialisation of {@link VanillaMessageHistory} using its compact binary form.
+ *
+ * Measures read and write latency when marshalling message history directly as a
+ * {@code BytesMarshallable}, avoiding the generic wire marshaller path.
*/
/*
.2.21.ea207
diff --git a/marshallingperf/src/main/java/run/chronicle/wire/perf/MessageHistoryWireMarshallableMain.java b/marshallingperf/src/main/java/run/chronicle/wire/perf/MessageHistoryWireMarshallableMain.java
index 60cb579efc..89e3f72a6a 100644
--- a/marshallingperf/src/main/java/run/chronicle/wire/perf/MessageHistoryWireMarshallableMain.java
+++ b/marshallingperf/src/main/java/run/chronicle/wire/perf/MessageHistoryWireMarshallableMain.java
@@ -12,9 +12,10 @@
import static run.chronicle.wire.perf.MessageHistoryBytesMarshallableMain.createMessageHistory;
/**
- * Benchmarks the performance of serialising and deserialising
- * {@link net.openhft.chronicle.wire.VanillaMessageHistory} using the standard
- * {@link net.openhft.chronicle.wire.WireMarshaller} mechanism (field by field).
+ * Benchmarks serialisation of {@link net.openhft.chronicle.wire.VanillaMessageHistory} using the generic wire marshaller.
+ *
+ * Uses a {@link Wire} and {@link net.openhft.chronicle.wire.WireMarshaller} to write and
+ * read the object field by field, contrasting performance with the direct binary form.
*/
/*
.2.21.ea207
diff --git a/marshallingperf/src/main/java/run/chronicle/wire/perf/StringsInBytesMarshallableMain.java b/marshallingperf/src/main/java/run/chronicle/wire/perf/StringsInBytesMarshallableMain.java
index 441c14c080..7a7797e9c7 100644
--- a/marshallingperf/src/main/java/run/chronicle/wire/perf/StringsInBytesMarshallableMain.java
+++ b/marshallingperf/src/main/java/run/chronicle/wire/perf/StringsInBytesMarshallableMain.java
@@ -13,9 +13,10 @@
import static run.chronicle.wire.perf.BytesInBytesMarshallableMain.histoOut;
/**
* Benchmarks the performance of serialising and deserialising an object
- * containing string fields using {@link net.openhft.chronicle.bytes.BytesMarshallable}.
+ * containing string fields using Chronicle {@link Bytes} based marshalling.
+ *
+ * Benchmarks in this package compare different marshalling styles and
+ * encodings, including bytes-marshallable and wire-marshallable
+ * variants, under various payloads.
+ */
+package run.chronicle.wire.perf;
diff --git a/microbenchmarks/README.adoc b/microbenchmarks/README.adoc
new file mode 100644
index 0000000000..c26f9b8356
--- /dev/null
+++ b/microbenchmarks/README.adoc
@@ -0,0 +1,415 @@
+= Wire Format abstraction library - Benchmarks
+:toc:
+:sectnums:
+:lang: en-GB
+:source-highlighter: rouge
+
+Chronicle Wire supports a separation of describing what data you want to store and retrieve and how it should be rendered/parsed.
+Wire handles a variety of formatting options for a wide range of formats.
+
+How do these options affect performance?
+
+The tests were run with -Xmx1g -XX:MaxInlineSize=400 on an isolated CPU on an i7-3970X with 32 GB of memory.
+These figures are historical; rerun the suite on current hardware before using the numbers in reports or release notes.
+
+== Tests
+
+These are latency test with the https://github.com/OpenHFT/Chronicle-Wire/tree/master/microbenchmarks/results[full Results Here]
+
+Something I found interesting is that while a typical time might be stable for a given run, you can get different results at different time.
++
+For this reason I ran the tests with 10 forks.
+By looking at the high percentiles, we tend to pick up the results of the worst run.
+
+[cols="<,^,^,^,^,>,>,>,>,>"]
+|===
+|Wire Format |Text encoding |Fixed width values? |Numeric Fields? |field-less? |Bytes |99.9 %tile |99.99 %tile |99.999 %tile |worst
+
+|YAML (TextWire) |UTF-8 |false |false |false |91 |2.81 |4.94 |8.62 |17.2
+|YAML (TextWire) |8-bit |false |false |false |91 |2.59 |4.70 |8.58 |16.8
+|JSONWire |8-bit |false |false |false |100 |3.11 |5.56 |10.62 |36.9
+|BinaryWire |UTF-8 |false |false |false |70 |1.57 |3.42 |7.14 |35.1
+|BinaryWire |UTF-8 |false |true |false |44 |0.67 |2.44 |5.93 |12.1
+|BinaryWire |UTF-8 |true |false |false |84 |1.51 |3.32 |7.22 |37.4
+|BinaryWire |UTF-8 |true |true |false |57 |0.57 |2.26 |5.09 |17.5
+|BinaryWire |UTF-8 |false |na |true |32 |0.65 |2.42 |5.53 |8.6
+|RawWire |UTF-8 |true |na |true |43 |0.49 |2.07 |4.87 |8.6
+|RawWire |8-bit |true |na |true |43 |0.40 |0.57 |2.90 |7.6
+|BytesMarshallable |8-bit |true |na |true |39 |0.17 |0.21 |2.13 |6.9
+|BytesMarshallable + stop bit encoding |8-bit |true |na |true |28 |0.21 |0.25 |2.40 |6.4
+|===
+
+All times are in µs (microseconds)
+
+"8-bit" encoding is ISO-8859-1 where characters 0 to 255 are mapped to bytes 0 to 255. I this case, (bytes) string.charAt(0)
+
+In all cases, a 4 bytes header was used to determine the length of message.
+
+== The code for all Wire formats
+
+The code to support Wire can be added to the class itself.
+These marshallers can also be added to another classes, but in general you would only do this if you can't modify the class you wish to serialize.
+
+[source,java]
+----
+@Override
+public void readMarshallable(WireIn wire) throws IllegalStateException {
+ wire.read(DataFields.price).float64(setPrice)
+ .read(DataFields.flag).bool(setFlag)
+ .read(DataFields.text).text(text)
+ .read(DataFields.side).asEnum(Side.class, setSide)
+ .read(DataFields.smallInt).int32(setSmallInt)
+ .read(DataFields.longInt).int64(setLongInt);
+}
+
+@Override
+public void writeMarshallable(WireOut wire) {
+ wire.write(DataFields.price).float64(price)
+ .write(DataFields.flag).bool(flag)
+ .write(DataFields.text).text(text)
+ .write(DataFields.side).asEnum(side)
+ .write(DataFields.smallInt).int32(smallInt)
+ .write(DataFields.longInt).int64(longInt);
+}
+----
+
+== The code for BytesMarshallable
+
+The code to support BytesMarshallable can eb added to the class marshalled.
+While this is faster than using Wire, there is no option to visualise the data without deserializing it, nor does it directly support schema changes.
+
+[source,yaml,opts=novalidate]
+----
+@Override
+public void readMarshallable(Bytes> bytes) {
+ price = bytes.readDouble();
+ longInt = bytes.readLong();
+ smallInt = bytes.readInt();
+ flag = bytes.readBoolean();
+// side = bytes.readEnum(Side.class);
+ side = bytes.readBoolean() ? Side.Buy : Side.Sell;
+ bytes.read8bit(text);
+}
+
+@Override
+public void writeMarshallable(Bytes> bytes) {
+ bytes.writeDouble(price)
+ .writeLong(longInt)
+ .writeInt(smallInt)
+// .writeEnum(side)
+ .writeBoolean(flag)
+ .writeBoolean(side == Side.Buy)
+ .write8bit(text);
+}
+----
+
+There was a small advantage in encoding the side as a boolean rather than an Enum as the later writes the name() as a String.
+
+== Comparison with other libraries
+
+[cols="<,^,^,^,^,>,>,>,>,>"]
+|===
+|Wire Format |Text encoding |Fixed width values? |Numeric Fields? |field-less? |Bytes |99.9 %tile |99.99 %tile |99.999 %tile |worst
+
+|SBE |8-bit |true |true |true |43 |0.31 |0.44 |4.11 |9.2
+|Jackson |UTF-8 |false |false |false |100 |4.95 |8.33 |1,400 |1,500
+|BSON |UTF-8 |true |false |false |96 |19.8 |1,430 |1,400 |1,600
+|Snake YAML |UTF-8 |false |false |false |89 |80.3 |4,067 |16,000 |24,000
+|BOON Json |UTF-8 |false |false |false |100 |20.7 |32.5 |11,000 |69,000
+|Externalizable |UTF-8 |true |false |false |197 |25.0 |29.7 |85,000 |120,000
+|Externalizable with Chronicle Bytes |UTF-8 |true |false |false |197 |24.5 |29.3 |85,000 |118,000
+|===
+
+All times are in µs (microseconds)
+
+== Comparison of JSON formats
+
+[cols=">,>,>,>,>,>"]
+|===
+|Wire Format |Bytes |99.9 %tile |99.99 %tile |99.999 %tile |worst
+
+|Chronicle-Wire ( JSON) |100* |3.11 |5.56 |10.62 |36.9
+|Jackson |100 |4.95 |8.3 |1,400 |1,500
+|Jackson + C-Bytes |100* |2.87 |10.1 |1,300 |1,400
+|Jackson + C-Bytes Reader/Writer |100* |3.06 |10.3 |883 |1,500
+|BSON |96 |19.8 |1,430 |1,400 |1,600
+|BSON + C-Bytes |96* |7.47 |15.1 |1,400 |11,600
+|BOON Json |100 |20.7 |32.5 |11,000 |69,000
+|===
+
+"C-Bytes" means using a recycled Chronicle Bytes buffer.
+
+Tests with "*" on Bytes mean this has been written to/read from direct memory and won't have a copy overhead when working with NIO such as TCP or Files.
+
+=== SBE (Simple Binary Encoding)
+
+SBE performs as well are BytesMarshallable.
+Even though it was slower in this test, the difference to too small to draw any conclusions.
+i.e. in a different use case, a different developer might find the difference reversed.
+
+However, I didn't find SBE simple.
+Perhaps this is because I didn't use the generation for different languages, but I found it was non-trivial to use and setup.
++
+For a flat class with just six fields it generated 9 classes, we have three support classes, and I ended up adding methods to the generated class to get it to perform as efficiently as I wanted.
+This is likely to be a lack of understanding on my part, though I might not be alone in this.
+
+=== Snake YAML
+
+Snake YAML is a fully featured YAML 1.1 parser.
+The library has to do much more work to support all the features of the YAML standard which necessarily takes longer.
++
+However, it takes a lot longer which means it may not be suitable if you need performance but you don't need a complete YAML parser.
+
+If you need to decode YAML which could come from any sources, Snake YAML is a better choice.
+
+== What does the format look like?
+
+Here some selected examples.
+The UTF-8 encoded and 8-bit encoded tests look the same in these cases as there isn't any characters >= 128.
+
+== Text Wire
+
+The main advantage of YAML based wire format is it is easier to implement with, document and debug.
+
+What you want is the ease of a text wire format but the speed of a binary wire format.
++
+Being able to switch from one to the other can save you a lot of time in development and support, but still give you the speed you want.
+
+This uses 91 bytes, Note: the "-- !!data" is added by the method to dump the data.
+This information is encoded in the first 4 bytes which contains the size.
+
+[source,yaml]
+----
+--- !!data
+price: 1234
+flag: true
+text: Hello World!
+side: Sell
+smallInt: 123
+longInt: 1234567890
+----
+
+== JSON Wire
+
+This wire produces a JSON style output.
+It has some YAML based extensions for typed data.
+
+Test json8bit used 100 bytes.
+
+[source,json]
+----
+--- !!data
+"price":1234,"longInt":1234567890,"smallInt":123,"flag":true,"text":"Hello World!","side":"Sell"
+----
+
+=== Binary Wire (default)
+
+This binary wire has be automatically decoded to text by Wires.fromSizePrefixedBlobs(Bytes)
+
+This uses 70 bytes.
+Note: the "-- !!data #binary" is added by the method to dump the data.
+This information is encoded in the first 4 bytes which contains the size.
+
+[source,yaml]
+----
+--- !!data #binary
+price: 1234
+flag: true
+text: Hello World!
+side: Sell
+smallInt: 123
+longInt: 1234567890
+----
+
+=== Binary Wire with fixed width fields.
+
+Fixed width fields support binding to values later and updating them atomically.
++
+Note: if you want to bind to specific values, there is support for this which will also ensure the values are aligned.
+
+This format uses 84 bytes
+
+[source,yaml]
+----
+--- !!data #binary
+price: 1234
+flag: true
+text: Hello World!
+side: Sell
+smallInt: 123
+longInt: 1234567890
+----
+
+=== Binary Wire with field numbers
+
+Numbered fields are more efficient to write and read, but are not as friendly to work with.
+
+Test bwireFTF used 44 bytes.
+
+[source,yaml]
+----
+--- !!data #binary
+3: 1234
+4: true
+5: Hello World!
+6: Sell
+1: 123
+2: 1234567890
+----
+
+=== Binary Wire with field numbers and fixed width values
+
+Test bwireTTF used 58 bytes.
+
+[source,yaml]
+----
+--- !!data #binary
+3: 1234
+4: true
+5: Hello World!
+6: Sell
+1: 123
+2: 1234567890
+----
+
+=== Binary Wire with variable width values only.
+
+Test bwireFTT used 32 bytes.
+
+[source,yaml]
+----
+--- !!data #binary
+1234
+true
+Hello World!
+Sell
+123
+1234567890
+----
+
+=== RawWire format
+
+Raw wire format drops all meta data.
+It must be fixed width as there is no way to use compact types.
+
+Test rwireUTF and rwire8bit used 43 bytes.
+
+----
+00000000 27 00 00 00 00 00 00 00 00 48 93 40 B1 0C 48 65 '······· ·H·@··He
+00000010 6C 6C 6F 20 57 6F 72 6C 64 21 04 53 65 6C 6C 7B llo Worl d!·Sell{
+00000020 00 00 00 D2 02 96 49 00 00 00 00 ······I· ···
+----
+
+=== BytesMarshallable
+
+The BytesMarshallable uses fixed width data types.
+
+Test bytesMarshallable used 39 bytes.
+
+----
+00000000 23 00 00 00 00 00 00 00 00 48 93 40 D2 02 96 49 #······· ·H·@···I
+00000010 00 00 00 00 7B 00 00 00 59 00 0C 48 65 6C 6C 6F ····{··· Y··Hello
+00000020 20 57 6F 72 6C 64 21 World!
+----
+
+=== BytesMarshallable with stop bit encoding
+
+This example used stop bit encoding to reduce the size of the message.
+
+Test bytesMarshallable used 28 bytes.
+
+----
+00000000 18 00 00 00 A0 A4 69 D2 85 D8 CC 04 7B 59 00 0C ······i· ····{Y··
+00000010 48 65 6C 6C 6F 20 57 6F 72 6C 64 21 Hello Wo rld!
+----
+
+== Comparison outputs
+
+=== SnakeYAML
+
+Snake YAML used the .0 on the end of the price to signify that it was a double.
++
+This added two characters but is an elegant way of encoding that it should be a double.
+
+[source,yaml]
+----
+flag: true
+longInt: 1234567890
+price: 1234.0
+side: Sell
+smallInt: 123
+text: Hello World!
+----
+
+=== Boon
+
+Test boon used 100 chars.
+
+[source,json]
+----
+{"smallInt":123,"longInt":1234567890,"price":1234.0,"flag":true,"side":"Sell","text":"Hello World!"}
+----
+
+=== Jackson
+
+Test jackson used 100 chars.
+
+----
+{"price":1234.0,"flag":true,"text":"Hello World!","side":"Sell","smallInt ":123,"longInt":1234567890}
+----
+
+=== BSON
+
+Test bson used 96 chars.
+
+----
+00000000 60 00 00 00 01 70 72 69 63 65 00 00 00 00 00 00 `····pri ce······
+00000010 48 93 40 08 66 6C 61 67 00 01 02 74 65 78 74 00 H·@·flag ···text·
+00000020 0D 00 00 00 48 65 6C 6C 6F 20 57 6F 72 6C 64 21 ····Hell o World!
+00000030 00 02 73 69 64 65 00 05 00 00 00 53 65 6C 6C 00 ··side·· ···Sell·
+00000040 10 73 6D 61 6C 6C 49 6E 74 00 7B 00 00 00 12 6C ·smallIn t·{····l
+00000050 6F 6E 67 49 6E 74 00 D2 02 96 49 00 00 00 00 00 ongInt·· ··I·····
+----
+
+=== SBE
+
+SBE has a method to extract the binary as text.
+It is likely this data structure could be optimised and made much shorter.
+
+Test sbe used 43 chars.
+
+----
+00000000 29 00 7B 00 00 00 D2 02 96 49 00 00 00 00 00 00 )·{····· ·I······
+00000010 00 00 00 48 93 40 01 0C 48 65 6C 6C 6F 20 57 6F ···H·@·· Hello Wo
+00000020 72 6C 64 21 00 00 00 00 01 00 00 rld!···· ···
+----
+
+=== Externalizable
+
+While Externalizable is more efficient than Serializable, it is still a heavy weight serialization.
++
+Where Java Serialization does well is in serializing Object Graphs instead of Object Tree, i.e. objects with circular references.
+
+Test externalizable used 293 chars.
+
+----
+00000000 AC ED 00 05 73 72 00 2A 6E 65 74 2E 6F 70 65 6E ····sr·* net.open
+00000010 68 66 74 2E 63 68 72 6F 6E 69 63 6C 65 2E 77 69 hft.chro nicle.wi
+00000020 72 65 2E 62 65 6E 63 68 6D 61 72 6B 73 2E 44 61 re.bench marks.Da
+00000030 74 61 FB 5E C8 1F BA EB 33 6F 0C 00 00 78 70 77 ta·^···· 3o···xpw
+00000040 15 40 93 48 00 00 00 00 00 00 00 00 00 49 96 02 ·@·H···· ·····I··
+00000050 D2 00 00 00 7B 01 7E 72 00 2A 6E 65 74 2E 6F 70 ····{·~r ·*net.op
+00000060 65 6E 68 66 74 2E 63 68 72 6F 6E 69 63 6C 65 2E enhft.ch ronicle.
+00000070 77 69 72 65 2E 62 65 6E 63 68 6D 61 72 6B 73 2E wire.ben chmarks.
+00000080 53 69 64 65 00 00 00 00 00 00 00 00 12 00 00 78 Side···· ·······x
+00000090 72 00 0E 6A 61 76 61 2E 6C 61 6E 67 2E 45 6E 75 r··java. lang.Enu
+000000a0 6D 00 00 00 00 00 00 00 00 12 00 00 78 70 74 00 m······· ····xpt·
+000000b0 04 53 65 6C 6C 74 00 0C 48 65 6C 6C 6F 20 57 6F ·Sellt·· Hello Wo
+000000c0 72 6C 64 21 78 60 00 00 00 01 70 72 69 63 65 00 rld!x`·· ··price·
+000000d0 00 00 00 00 00 48 93 40 08 66 6C 61 67 00 01 02 ·····H·@ ·flag···
+000000e0 74 65 78 74 00 0D 00 00 00 48 65 6C 6C 6F 20 57 text···· ·Hello W
+000000f0 6F 72 6C 64 21 00 02 73 69 64 65 00 05 00 00 00 orld!··s ide·····
+00000100 53 65 6C 6C 00 10 73 6D 61 6C 6C 49 6E 74 00 7B Sell··sm allInt·{
+00000110 00 00 00 12 6C 6F 6E 67 49 6E 74 00 D2 02 96 49 ····long Int····I
+00000120 00 00 00 00 00 ·····
+----
diff --git a/microbenchmarks/README.md b/microbenchmarks/README.md
deleted file mode 100644
index 76c6ef2b53..0000000000
--- a/microbenchmarks/README.md
+++ /dev/null
@@ -1,336 +0,0 @@
-# Wire Format abstraction library - Benchmarks
-===
-
-# Purpose
-
-Chronicle Wire supports a separation of describing what data you want to store and retrieve
- and how it should be rendered/parsed.
- Wire handles a variety of formatting options for a wide range of formats.
-
-How do these options affect performance?
-
-The tests were run with -Xmx1g -XX:MaxInlineSize=400 on an isolated CPU on an i7-3970X with 32 GB of memory.
-
-# Tests
-
-These are latency test with the [full Results Here](https://github.com/OpenHFT/Chronicle-Wire/tree/master/microbenchmarks/results)
-
-Something I found interesting is that while a typical time might be stable for a given run, you can get different results at different time.
-For this reason I ran the tests with 10 forks. By looking at the high percentiles, we tend to pick up the results of the worst run.
-
-| Wire Format | Text encoding | Fixed width values? | Numeric Fields? | field-less?| Bytes | 99.9 %tile | 99.99 %tile | 99.999 %tile | worst |
-|--------------|:---------------:|:---------------------:|:----------------:|:-----------:|-----:|-----------:|-------------:|---------------:|---------:|
-| YAML (TextWire) | UTF-8 | false | false | false | 91 | 2.81 | 4.94 | 8.62 | 17.2 |
-| YAML (TextWire) | 8-bit | false | false | false | 91 | 2.59 | 4.70 | 8.58 | 16.8 |
-| JSONWire | 8-bit | false | false | false | 100 | 3.11 | 5.56 | 10.62 | 36.9 |
-| BinaryWire | UTF-8 | false | false | false | 70 | 1.57 | 3.42 | 7.14 | 35.1 |
-| BinaryWire | UTF-8 | false | true | false | 44 | 0.67 | 2.44 | 5.93 | 12.1 |
-| BinaryWire | UTF-8 | true | false | false | 84 | 1.51 | 3.32 | 7.22 | 37.4 |
-| BinaryWire | UTF-8 | true | true | false | 57 | 0.57 | 2.26 | 5.09 | 17.5 |
-| BinaryWire | UTF-8 | false | na | true | 32 | 0.65 | 2.42 | 5.53 | 8.6 |
-| RawWire | UTF-8 | true | na | true | 43 | 0.49 | 2.07 | 4.87 | 8.6 |
-| RawWire | 8-bit | true | na | true | 43 | 0.40 | 0.57 | 2.90 | 7.6 |
-| BytesMarshallable | 8-bit | true | na | true | 39 | 0.17 | 0.21 | 2.13 | 6.9 |
-| BytesMarshallable + stop bit encoding | 8-bit | true | na | true | 28 | 0.21 | 0.25 | 2.40 | 6.4 |
-
-All times are in micro-seconds
-
-"8-bit" encoding is ISO-8859-1 where characters 0 to 255 are mapped to bytes 0 to 255. I this case, (bytes) string.charAt(0)
-
-In all cases, a 4 bytes header was used to determine the length of message.
-
-## The code for all Wire formats
-The code to support Wire can be added to the class itself. These marshallers can also be added to another classes, but in general you would only do this if you can't modify the class you wish to serialize.
-```java
-@Override
-public void readMarshallable(WireIn wire) throws IllegalStateException {
- wire.read(DataFields.price).float64(setPrice)
- .read(DataFields.flag).bool(setFlag)
- .read(DataFields.text).text(text)
- .read(DataFields.side).asEnum(Side.class, setSide)
- .read(DataFields.smallInt).int32(setSmallInt)
- .read(DataFields.longInt).int64(setLongInt);
-}
-
-@Override
-public void writeMarshallable(WireOut wire) {
- wire.write(DataFields.price).float64(price)
- .write(DataFields.flag).bool(flag)
- .write(DataFields.text).text(text)
- .write(DataFields.side).asEnum(side)
- .write(DataFields.smallInt).int32(smallInt)
- .write(DataFields.longInt).int64(longInt);
-}
-```
-
-## The code for BytesMarshallable
-The code to support BytesMarshallable can eb added to the class marshalled. While this is faster than using Wire, there is no option to visualise the data without deserializing it, nor does it directly support schema changes.
-
-```yaml
-@Override
-public void readMarshallable(Bytes> bytes) {
- price = bytes.readDouble();
- longInt = bytes.readLong();
- smallInt = bytes.readInt();
- flag = bytes.readBoolean();
-// side = bytes.readEnum(Side.class);
- side = bytes.readBoolean() ? Side.Buy : Side.Sell;
- bytes.read8bit(text);
-}
-
-@Override
-public void writeMarshallable(Bytes> bytes) {
- bytes.writeDouble(price)
- .writeLong(longInt)
- .writeInt(smallInt)
-// .writeEnum(side)
- .writeBoolean(flag)
- .writeBoolean(side == Side.Buy)
- .write8bit(text);
-}
-```
-There was a small advantage in encoding the side as a boolean rather than an Enum as the later writes the name() as a String.
-
-# Comparison with other libraries
-
-| Wire Format | Text encoding | Fixed width values? | Numeric Fields? | field-less?| Bytes | 99.9 %tile | 99.99 %tile | 99.999 %tile | worst |
-|--------------|:---------------:|:----------------------:|:-----------------:|:---------:|-------:|------------:|-------------:|--------------:|-------:|
-| SBE | 8-bit | true | true | true | 43 | 0.31 | 0.44 | 4.11 | 9.2 |
-| Jackson | UTF-8 | false | false | false | 100 | 4.95 | 8.33 | 1,400 | 1,500 |
-| BSON | UTF-8 | true | false | false | 96 | 19.8 | 1,430 | 1,400 | 1,600 |
-| Snake YAML | UTF-8 | false | false | false | 89 | 80.3 | 4,067 | 16,000 | 24,000 |
-| BOON Json | UTF-8 | false | false | false | 100 | 20.7 | 32.5 | 11,000 | 69,000 |
-| Externalizable | UTF-8 | true | false | false | 197 | 25.0 | 29.7 | 85,000 | 120,000 |
-| Externalizable with Chronicle Bytes | UTF-8 | true | false | false | 197 | 24.5 | 29.3 | 85,000 | 118,000 |
-
-All times are in micro-seconds
-
-## Comparison of JSON formats
-
-| Wire Format | Bytes | 99.9 %tile | 99.99 %tile | 99.999 %tile | worst |
-|---------------------:|------:|------------:|------------:|---------------:|--------:|
-| Chronicle-Wire ( JSON) | 100* | 3.11 | 5.56 | 10.62 | 36.9 |
-| Jackson | 100 | 4.95 | 8.3 | 1,400 | 1,500 |
-| Jackson + C-Bytes | 100* | 2.87 | 10.1 | 1,300 | 1,400 |
-| Jackson + C-Bytes Reader/Writer| 100* | 3.06 | 10.3 | 883 | 1,500 |
-| BSON | 96 | 19.8 | 1,430 | 1,400 | 1,600 |
-| BSON + C-Bytes | 96* | 7.47 | 15.1 | 1,400 | 11,600 |
-| BOON Json | 100 | 20.7 | 32.5 | 11,000 | 69,000 |
-
-"C-Bytes" means using a recycled Chronicle Bytes buffer.
-
-Tests with "*" on Bytes mean this has been written to/read from direct memory and won't have a copy overhead when working with NIO such as TCP or Files.
-
-## SBE (Simple Binary Encoding)
-SBE performs as well are BytesMarshallable. Even though it was slower in this test, the difference to too small to draw any conclusions. i.e. in a different use case, a different developer might find the difference reversed.
-
-However, I didn't find SBE simple. Perhaps this is because I didn't use the generation for different languages, but I found it was non-trivial to use and setup.
-For a flat class with just six fields it generated 9 classes, we have three support classes, and I ended up adding methods to the generated class to get it to perform as efficiently as I wanted.
-This is likely to be a lack of understanding on my part, though I might not be alone in this.
-
-## Snake YAML
-Snake YAML is a fully featured YAML 1.1 parser. The library has to do much more work to support all the features of the YAML standard which necessarily takes longer.
-However, it takes a lot longer which means it may not be suitable if you need performance but you don't need a complete YAML parser.
-
-If you need to decode YAML which could come from any sources, Snake YAML is a better choice.
-
-# What does the format look like?
-Here some selected examples. The UTF-8 encoded and 8-bit encoded tests look the same in these cases as there isn't any characters >= 128.
-
-## Text Wire
-The main advantage of YAML based wire format is it is easier to implement with, document and debug.
-
-What you want is the ease of a text wire format but the speed of a binary wire format.
-Being able to switch from one to the other can save you a lot of time in development and support, but still give you the speed you want.
-
-This uses 91 bytes, Note: the "--- !!data" is added by the method to dump the data. This information is encoded in the first 4 bytes which contains the size.
-
-```yaml
---- !!data
-price: 1234
-flag: true
-text: Hello World!
-side: Sell
-smallInt: 123
-longInt: 1234567890
-```
-
-## JSON Wire
-This wire produces a JSON style output. It has some YAML based extensions for typed data.
-
-Test json8bit used 100 bytes.
-```json
---- !!data
-"price":1234,"longInt":1234567890,"smallInt":123,"flag":true,"text":"Hello World!","side":"Sell"
-```
-
-## Binary Wire (default)
-This binary wire has be automatically decoded to text by Wires.fromSizePrefixedBlobs(Bytes)
-
-This uses 70 bytes. Note: the "--- !!data #binary" is added by the method to dump the data. This information is encoded in the first 4 bytes which contains the size.
-```yaml
---- !!data #binary
-price: 1234
-flag: true
-text: Hello World!
-side: Sell
-smallInt: 123
-longInt: 1234567890
-```
-
-## Binary Wire with fixed width fields.
-Fixed width fields support binding to values later and updating them atomically.
-Note: if you want to bind to specific values, there is support for this which will also ensure the values are aligned.
-
-This format uses 84 bytes
-```yaml
---- !!data #binary
-price: 1234
-flag: true
-text: Hello World!
-side: Sell
-smallInt: 123
-longInt: 1234567890
-```
-
-## Binary Wire with field numbers
-Numbered fields are more efficient to write and read, but are not as friendly to work with.
-
-Test bwireFTF used 44 bytes.
-```yaml
---- !!data #binary
-3: 1234
-4: true
-5: Hello World!
-6: Sell
-1: 123
-2: 1234567890
-```
-
-## Binary Wire with field numbers and fixed width values
-
-Test bwireTTF used 58 bytes.
-```yaml
---- !!data #binary
-3: 1234
-4: true
-5: Hello World!
-6: Sell
-1: 123
-2: 1234567890
-```
-
-## Binary Wire with variable width values only.
-
-Test bwireFTT used 32 bytes.
-```yaml
---- !!data #binary
-1234
-true
-Hello World!
-Sell
-123
-1234567890
-```
-
-## RawWire format
-Raw wire format drops all meta data. It must be fixed width as there is no way to use compact types.
-
-Test rwireUTF and rwire8bit used 43 bytes.
-```
-00000000 27 00 00 00 00 00 00 00 00 48 93 40 B1 0C 48 65 '······· ·H·@··He
-00000010 6C 6C 6F 20 57 6F 72 6C 64 21 04 53 65 6C 6C 7B llo Worl d!·Sell{
-00000020 00 00 00 D2 02 96 49 00 00 00 00 ······I· ···
-```
-## BytesMarshallable
-The BytesMarshallable uses fixed width data types.
-
-Test bytesMarshallable used 39 bytes.
-```
-00000000 23 00 00 00 00 00 00 00 00 48 93 40 D2 02 96 49 #······· ·H·@···I
-00000010 00 00 00 00 7B 00 00 00 59 00 0C 48 65 6C 6C 6F ····{··· Y··Hello
-00000020 20 57 6F 72 6C 64 21 World!
-```
-
-## BytesMarshallable with stop bit encoding
-This example used stop bit encoding to reduce the size of the message.
-
-Test bytesMarshallable used 28 bytes.
-```
-00000000 18 00 00 00 A0 A4 69 D2 85 D8 CC 04 7B 59 00 0C ······i· ····{Y··
-00000010 48 65 6C 6C 6F 20 57 6F 72 6C 64 21 Hello Wo rld!
-```
-
-# Comparison outputs
-
-## SnakeYAML
-Snake YAML used the .0 on the end of the price to signify that it was a double.
-This added two characters but is an elegant way of encoding that it should be a double.
-
-```yaml
-flag: true
-longInt: 1234567890
-price: 1234.0
-side: Sell
-smallInt: 123
-text: Hello World!
-```
-
-## Boon
-Test boon used 100 chars.
-```json
-{"smallInt":123,"longInt":1234567890,"price":1234.0,"flag":true,"side":"Sell","text":"Hello World!"}
-```
-
-## Jackson
-Test jackson used 100 chars.
-```
-{"price":1234.0,"flag":true,"text":"Hello World!","side":"Sell","smallInt ":123,"longInt":1234567890}
-```
-## BSON
-Test bson used 96 chars.
-```
-00000000 60 00 00 00 01 70 72 69 63 65 00 00 00 00 00 00 `····pri ce······
-00000010 48 93 40 08 66 6C 61 67 00 01 02 74 65 78 74 00 H·@·flag ···text·
-00000020 0D 00 00 00 48 65 6C 6C 6F 20 57 6F 72 6C 64 21 ····Hell o World!
-00000030 00 02 73 69 64 65 00 05 00 00 00 53 65 6C 6C 00 ··side·· ···Sell·
-00000040 10 73 6D 61 6C 6C 49 6E 74 00 7B 00 00 00 12 6C ·smallIn t·{····l
-00000050 6F 6E 67 49 6E 74 00 D2 02 96 49 00 00 00 00 00 ongInt·· ··I·····
-```
-
-## SBE
-SBE has a method to extract the binary as text. It is likely this data structure could be optimised and made much shorter.
-
-Test sbe used 43 chars.
-```
-00000000 29 00 7B 00 00 00 D2 02 96 49 00 00 00 00 00 00 )·{····· ·I······
-00000010 00 00 00 48 93 40 01 0C 48 65 6C 6C 6F 20 57 6F ···H·@·· Hello Wo
-00000020 72 6C 64 21 00 00 00 00 01 00 00 rld!···· ···
-```
-
-## Externalizable
-While Externalizable is more efficient than Serializable, it is still a heavy weight serialization.
-Where Java Serialization does well is in serializing Object Graphs instead of Object Tree, i.e. objects with circular references.
-
-Test externalizable used 293 chars.
-```
-00000000 AC ED 00 05 73 72 00 2A 6E 65 74 2E 6F 70 65 6E ····sr·* net.open
-00000010 68 66 74 2E 63 68 72 6F 6E 69 63 6C 65 2E 77 69 hft.chro nicle.wi
-00000020 72 65 2E 62 65 6E 63 68 6D 61 72 6B 73 2E 44 61 re.bench marks.Da
-00000030 74 61 FB 5E C8 1F BA EB 33 6F 0C 00 00 78 70 77 ta·^···· 3o···xpw
-00000040 15 40 93 48 00 00 00 00 00 00 00 00 00 49 96 02 ·@·H···· ·····I··
-00000050 D2 00 00 00 7B 01 7E 72 00 2A 6E 65 74 2E 6F 70 ····{·~r ·*net.op
-00000060 65 6E 68 66 74 2E 63 68 72 6F 6E 69 63 6C 65 2E enhft.ch ronicle.
-00000070 77 69 72 65 2E 62 65 6E 63 68 6D 61 72 6B 73 2E wire.ben chmarks.
-00000080 53 69 64 65 00 00 00 00 00 00 00 00 12 00 00 78 Side···· ·······x
-00000090 72 00 0E 6A 61 76 61 2E 6C 61 6E 67 2E 45 6E 75 r··java. lang.Enu
-000000a0 6D 00 00 00 00 00 00 00 00 12 00 00 78 70 74 00 m······· ····xpt·
-000000b0 04 53 65 6C 6C 74 00 0C 48 65 6C 6C 6F 20 57 6F ·Sellt·· Hello Wo
-000000c0 72 6C 64 21 78 60 00 00 00 01 70 72 69 63 65 00 rld!x`·· ··price·
-000000d0 00 00 00 00 00 48 93 40 08 66 6C 61 67 00 01 02 ·····H·@ ·flag···
-000000e0 74 65 78 74 00 0D 00 00 00 48 65 6C 6C 6F 20 57 text···· ·Hello W
-000000f0 6F 72 6C 64 21 00 02 73 69 64 65 00 05 00 00 00 orld!··s ide·····
-00000100 53 65 6C 6C 00 10 73 6D 61 6C 6C 49 6E 74 00 7B Sell··sm allInt·{
-00000110 00 00 00 12 6C 6F 6E 67 49 6E 74 00 D2 02 96 49 ····long Int····I
-00000120 00 00 00 00 00 ·····
-```
diff --git a/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/Data.java b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/Data.java
index f0a06fd04f..0fba8f3769 100644
--- a/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/Data.java
+++ b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/Data.java
@@ -14,6 +14,12 @@
import java.nio.ByteBuffer;
+/**
+ * Simple DTO used in Chronicle Wire microbenchmarks.
+ *
+ * Contains an int, long, double, boolean, text and side field and supports Chronicle
+ * {@link Marshallable} and {@link BytesMarshallable} serialisation.
+ */
public class Data implements Marshallable, BytesMarshallable {
int smallInt = 0;
long longInt = 0;
@@ -108,11 +114,20 @@ public void setSide(Side side) {
this.side = side;
}
+ /**
+ * Writes the current text bytes into the provided buffer without resizing it.
+ */
public void copyTextTo(ByteBuffer textBuffer) {
for (int i = 0; i < text.length(); i++)
textBuffer.put((byte) text.charAt(i));
}
+ /**
+ * Intended hook for copying this DTO into the equivalent {@link NativeData} structure.
+ *
+ * Left unimplemented in the benchmark harness because {@link NativeData} lives in a separate
+ * module; the method documents the expected direction for future comparisons.
+ */
public void copyTo(NativeData nd) {
throw new UnsupportedOperationException();
}
diff --git a/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/Data2.java b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/Data2.java
index 6022ca6343..5015753f47 100644
--- a/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/Data2.java
+++ b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/Data2.java
@@ -11,6 +11,11 @@
import net.openhft.chronicle.wire.WireIn;
import net.openhft.chronicle.wire.WireOut;
+/**
+ * Variant of {@link Data} used to compare different serialisation strategies in microbenchmarks.
+ *
+ * Uses a different field ordering and access pattern to highlight layout effects.
+ */
public class Data2 implements Marshallable, BytesMarshallable {
int smallInt = 0;
long longInt = 0;
@@ -19,6 +24,10 @@ public class Data2 implements Marshallable, BytesMarshallable {
transient Bytes> text = Bytes.allocateElasticOnHeap(16).unchecked(true);
Side side;
+ /**
+ * Construct a populated DTO using the provided values and append the given text into the
+ * reusable {@link Bytes} buffer.
+ */
public Data2(int smallInt, long longInt, double price, boolean flag, CharSequence text, Side side) {
this.smallInt = smallInt;
this.longInt = longInt;
@@ -88,11 +97,17 @@ public String getText() {
return text.toString();
}
+ /**
+ * Replace the current text content with the supplied string.
+ */
public void setText(String text) {
this.text.clear();
this.text.appendUtf8(text);
}
+ /**
+ * Direct access to the mutable {@link Bytes} backing the text field for zero-copy use.
+ */
public Bytes> textAsBytes() {
return text;
}
@@ -105,6 +120,10 @@ public void setSide(Side side) {
this.side = side;
}
+ /**
+ * Read the DTO using the manual Bytes-based encoding used in the microbenchmarks.
+ * The side is encoded as a boolean and the text as an 8-bit string for compactness.
+ */
@Override
public void readMarshallable(BytesIn> bytes) {
price = bytes.readDouble();
@@ -116,6 +135,9 @@ public void readMarshallable(BytesIn> bytes) {
bytes.read8bit(text);
}
+ /**
+ * Write the DTO using the manual Bytes-based encoding used in the microbenchmarks.
+ */
@Override
public void writeMarshallable(BytesOut> bytes) {
bytes.writeDouble(price)
diff --git a/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/ExternalizableData.java b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/ExternalizableData.java
index f67080a67b..43a57781d0 100644
--- a/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/ExternalizableData.java
+++ b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/ExternalizableData.java
@@ -20,6 +20,12 @@
import java.io.ObjectOutput;
import java.nio.BufferUnderflowException;
+/**
+ * Plain {@link Externalizable} DTO used as a baseline for Chronicle Wire benchmarks.
+ *
+ * Supports reading and writing via JSON, Chronicle Wire and Java serialisation so that different
+ * approaches can be compared.
+ */
public class ExternalizableData extends SelfDescribingMarshallable implements Externalizable {
int smallInt = 0;
long longInt = 0;
@@ -88,6 +94,9 @@ public void setSide(Side side) {
this.side = side;
}
+ /**
+ * Serialise the DTO into a JSON-smart object for comparison with hand-written JSON handling.
+ */
public void writeTo(JSONObject obj) {
obj.put("price", price);
obj.put("flag", flag);
@@ -97,6 +106,9 @@ public void writeTo(JSONObject obj) {
obj.put("longInt", longInt);
}
+ /**
+ * Populate fields from a JSON-smart object representation.
+ */
public void readFrom(JSONObject obj) {
price = obj.getAsNumber("price").doubleValue();
flag = Boolean.parseBoolean(obj.getAsString("flag"));
@@ -106,6 +118,9 @@ public void readFrom(JSONObject obj) {
longInt = obj.getAsNumber("longInt").longValue();
}
+ /**
+ * Parse the DTO from a Jackson streaming parser.
+ */
public void readFrom(JsonParser parser) throws IOException {
parser.nextToken();
while (parser.nextToken() != JsonToken.END_OBJECT) {
@@ -134,6 +149,9 @@ public void readFrom(JsonParser parser) throws IOException {
}
}
+ /**
+ * Write the DTO using a Jackson streaming generator.
+ */
public void writeTo(JsonGenerator generator) throws IOException {
generator.writeStartObject();
generator.writeNumberField("price", price);
diff --git a/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/Main.java b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/Main.java
index 4c43e9a797..63239052e0 100644
--- a/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/Main.java
+++ b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/Main.java
@@ -22,6 +22,9 @@
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
+/**
+ * Keys shared across benchmark DTOs so wire reads and writes remain consistent.
+ */
enum DataFields implements WireKey {
unknown, smallInt, longInt, price, flag, text, side;
@@ -30,9 +33,19 @@ public int code() {
return ordinal();
}
}
+/**
+ * Marker annotation to flag benchmark methods whose output should be rendered as text when run in
+ * debug mode.
+ */
@Retention(RetentionPolicy.RUNTIME)
@interface PrintAsText {
}
+/**
+ * Entry point for a suite of Chronicle Wire microbenchmarks.
+ *
+ * Benchmarks serialisation and deserialisation of {@link Data}, {@link Data2} and {@link TCData}
+ * across multiple wire formats and configuration combinations using JMH.
+ */
@State(Scope.Thread)
public class Main {
final Bytes> bytes = Bytes.allocateDirect(128).unchecked(true);
diff --git a/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/ObjectPoolMain.java b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/ObjectPoolMain.java
index 6e78a079a8..d1f88d4c4d 100644
--- a/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/ObjectPoolMain.java
+++ b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/ObjectPoolMain.java
@@ -22,6 +22,12 @@
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+
+/**
+ * Microbenchmark exploring the performance characteristics of string interning and allocation
+ * using {@link Bit8StringInterner} and direct string construction from {@link BytesStore}.
+ */
@State(Scope.Thread)
public class ObjectPoolMain {
@@ -35,7 +41,7 @@ public class ObjectPoolMain {
private final Bit8StringInterner si = new Bit8StringInterner(64);
private static BytesStore, Void> BytesStoreFrom(String s) {
- return BytesStore.nativeStoreFrom(s.getBytes(StandardCharsets.ISO_8859_1));
+ return BytesStore.nativeStoreFrom(s.getBytes(ISO_8859_1));
}
public static void main(String... args) throws RunnerException, InvocationTargetException, IllegalAccessException {
diff --git a/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/Side.java b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/Side.java
index d248891223..bc917e59cc 100644
--- a/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/Side.java
+++ b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/Side.java
@@ -3,6 +3,11 @@
*/
package net.openhft.chronicle.wire.benchmarks;
+/**
+ * Trading side used in benchmark DTOs.
+ *
+ * Encoded as a single character or boolean in some native layouts for compactness.
+ */
public enum Side {
Buy, Sell
}
diff --git a/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/TCData.java b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/TCData.java
index 7e9c9fc6f2..e60b9265b4 100644
--- a/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/TCData.java
+++ b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/TCData.java
@@ -11,6 +11,12 @@
import net.openhft.chronicle.wire.LongConversion;
import net.openhft.chronicle.wire.Marshallable;
+/**
+ * Trivially copyable DTO used in Chronicle Wire benchmarks.
+ *
+ * Uses {@link BytesUtil#triviallyCopyableRange(Class)} and base85 text encoding to support very
+ * fast bulk {@link net.openhft.chronicle.bytes.Bytes} operations.
+ */
public class TCData implements Marshallable, BytesMarshallable {
int smallInt = 0;
long longInt = 0;
@@ -43,10 +49,16 @@ public final void writeMarshallable(BytesOut> bytes) {
bytes.unsafeWriteObject(this, DTO_START, DTO_LENGTH);
}
+ /**
+ * Starting byte offset of the trivially copyable range for the provided class.
+ */
public static int start(Class> c) {
return BytesUtil.triviallyCopyableRange(c)[0];
}
+ /**
+ * Length in bytes of the trivially copyable range for the provided class.
+ */
public static int length(Class> c) {
int[] BYTE_RANGE = BytesUtil.triviallyCopyableRange(c);
return BYTE_RANGE[1] - BYTE_RANGE[0];
@@ -95,10 +107,16 @@ public void setText(CharSequence text) {
this.text = Base85LongConverter.INSTANCE.parse(text);
}
- public Side getSide() {
+ /**
+ * Side derived from the compact char representation; 'B' maps to {@link Side#Buy}.
+ */
+ public Side getSide() {
return side == 'B' ? Side.Buy : Side.Sell;
}
+ /**
+ * Store the side as a single character code to keep the struct trivially copyable.
+ */
public void setSide(Side side) {
this.side = side.name().charAt(0);
}
diff --git a/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/bytes/NativeData.java b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/bytes/NativeData.java
index 9919876a9e..3331dc02c7 100644
--- a/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/bytes/NativeData.java
+++ b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/bytes/NativeData.java
@@ -8,6 +8,11 @@
import net.openhft.chronicle.wire.benchmarks.Data;
import net.openhft.chronicle.wire.benchmarks.Side;
+/**
+ * {@link Byteable} view of the {@link Data} structure laid out directly in a {@link BytesStore}.
+ *
+ * Used to benchmark native memory access patterns versus object based DTOs.
+ */
public class NativeData implements Byteable {
static final int PRICE = 0;
static final int LONG_INT = PRICE + 8;
@@ -21,46 +26,83 @@ public class NativeData implements Byteable {
private long offset;
private long length;
+ /**
+ * Read the 32-bit field stored at {@link #SMALL_INT}.
+ */
public int getSmallInt() {
return bytesStore.readInt(offset + SMALL_INT);
}
+ /**
+ * Write the 32-bit {@code smallInt} field into the backing store.
+ */
public void setSmallInt(int smallInt) {
bytesStore.writeInt(offset + SMALL_INT, smallInt);
}
+ /**
+ * Read the 64-bit field stored at {@link #LONG_INT}.
+ */
public long getLongInt() {
return bytesStore.readLong(offset + LONG_INT);
}
+ /**
+ * Write the 64-bit {@code longInt} field into the backing store.
+ */
public void setLongInt(long longInt) {
bytesStore.writeLong(offset + LONG_INT, longInt);
}
+ /**
+ * Read the price value from the backing store.
+ */
public double getPrice() {
return bytesStore.readDouble(offset + PRICE);
}
+ /**
+ * Write the price value into the backing store.
+ */
public void setPrice(double price) {
bytesStore.writeDouble(offset + PRICE, price);
}
+ /**
+ * Read the boolean flag from the backing store.
+ */
public boolean isFlag() {
return bytesStore.readBoolean(offset + FLAG);
}
+ /**
+ * Write the boolean flag into the backing store.
+ */
public void setFlag(boolean flag) {
bytesStore.writeBoolean(offset + FLAG, flag);
}
+ /**
+ * Decode the side flag; true represents {@link Side#Buy}.
+ */
public Side getSide() {
return bytesStore.readBoolean(offset + SIDE) ? Side.Buy : Side.Sell;
}
+ /**
+ * Encode the side flag; {@link Side#Buy} is stored as true.
+ */
public void setSide(Side side) {
bytesStore.writeBoolean(offset + SIDE, side == Side.Buy);
}
+ /**
+ * Point this view at a new {@link BytesStore} region.
+ *
+ * @param bytesStore backing store containing the encoded fields
+ * @param offset starting offset of the record
+ * @param length total length of the region
+ */
@Override
public void bytesStore(BytesStore bytesStore, long offset, long length) {
this.bytesStore = bytesStore;
@@ -68,15 +110,28 @@ public void bytesStore(BytesStore bytesStore, long offset, long length) {
this.length = length;
}
+ /**
+ * Total bytes currently used by this record, including the variable-length text.
+ */
public int encodedLength() {
return TEXT + 1 + bytesStore.readUnsignedByte(offset + TEXT);
}
+ /**
+ * Maximum encoded size supported by this view, assuming the text field uses {@link #MAX_TEXT}
+ * bytes.
+ */
@Override
public long maxSize() {
return TEXT + 1 + MAX_TEXT;
}
+ /**
+ * Copy the native layout into the object-based {@link Data} DTO.
+ *
+ * Not implemented in this benchmark fixture; provided for symmetry with
+ * {@link Data#copyTo(NativeData)}.
+ */
public void copyTo(Data data) {
throw new UnsupportedOperationException();
}
diff --git a/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/bytes/package-info.java b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/bytes/package-info.java
new file mode 100644
index 0000000000..2365d78958
--- /dev/null
+++ b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/bytes/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * Byte-level benchmarks for Chronicle Wire data layouts.
+ *
+ *
Code here models DTOs directly over {@code BytesStore} to measure native
+ * access patterns, allocation behaviour, and serialization performance.
+ */
+package net.openhft.chronicle.wire.benchmarks.bytes;
diff --git a/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/package-info.java b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/package-info.java
new file mode 100644
index 0000000000..730532bccd
--- /dev/null
+++ b/microbenchmarks/src/main/java/net/openhft/chronicle/wire/benchmarks/package-info.java
@@ -0,0 +1,11 @@
+/*
+ * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0
+ */
+/**
+ * Micro-benchmarks for Chronicle Wire.
+ *
+ * This package exercises the Wire APIs and related data structures
+ * under synthetic workloads to characterise performance and allocation
+ * behaviour.
+ */
+package net.openhft.chronicle.wire.benchmarks;
diff --git a/pom.xml b/pom.xml
index a3885fdcfd..d6852f5f9c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -34,7 +34,7 @@
net.openhftthird-party-bom
- 3.27ea5
+ 3.27ea7pomimport
diff --git a/docs/EventsByMethod.adoc b/src/main/docs/EventsByMethod.adoc
similarity index 97%
rename from docs/EventsByMethod.adoc
rename to src/main/docs/EventsByMethod.adoc
index be8fb0d3f8..c889e418d7 100644
--- a/docs/EventsByMethod.adoc
+++ b/src/main/docs/EventsByMethod.adoc
@@ -1,5 +1,9 @@
= Events by Method
Peter Lawrey
+:toc:
+:sectnums:
+:lang: en-GB
+:source-highlighter: rouge
Chronicle favours modelling events as asynchronous method calls.
This document explains the *events by method* pattern used by Chronicle Wire.
@@ -136,9 +140,9 @@ Some advantages of Trivially Copyable Objects
Events received by a component can be handled in two main ways:
-1. *Raw Message Forwarding* - the raw `Bytes` or `DocumentContext` can be forwarded to another queue or network channel without deserialising the message fully.
+. *Raw Message Forwarding* - the raw `Bytes` or `DocumentContext` can be forwarded to another queue or network channel without deserialising the message fully.
This is efficient for routers or filters that only inspect metadata.
-2. *Full Deserialisation and Re-invocation* - the event is deserialised and the corresponding method invoked locally; as part of the processing logic the same (or another) method can then be invoked downstream via a `MethodWriter`.
+. *Full Deserialisation and Re-invocation* - the event is deserialised and the corresponding method invoked locally; as part of the processing logic the same (or another) method can then be invoked downstream via a `MethodWriter`.
== Modelling simple asynchronous method calls
diff --git a/docs/YAML2SpecificationCompliance.adoc b/src/main/docs/YAML2SpecificationCompliance.adoc
similarity index 92%
rename from docs/YAML2SpecificationCompliance.adoc
rename to src/main/docs/YAML2SpecificationCompliance.adoc
index 0c93fe5852..34ab188ef5 100644
--- a/docs/YAML2SpecificationCompliance.adoc
+++ b/src/main/docs/YAML2SpecificationCompliance.adoc
@@ -1,15 +1,10 @@
= Chronicle Wire and YAML 1.2.2 Specification Compliance
-:toc: manual
+:toc:
+:sectnums:
+:lang: en-GB
:css-signature: demo
:toc-placement: preamble
-
-== Overview
-
-Chronicle Wire implements YAML parsing primarily through `YamlWire` and `TextWire`.
-This document outlines the level of compliance with the YAML 1.2.2 specification and highlights any deviations.
-It is intended for developers who require interoperability information.
-
-link:https://yaml.org/spec/1.2.2/[YAML 1.2.2 specification]
+:source-highlighter: rouge
== Overview
diff --git a/src/main/docs/architecture-overview.adoc b/src/main/docs/architecture-overview.adoc
new file mode 100644
index 0000000000..3d8f0c4765
--- /dev/null
+++ b/src/main/docs/architecture-overview.adoc
@@ -0,0 +1,299 @@
+= Chronicle Wire Architecture Overview
+:toc:
+:sectnums:
+:lang: en-GB
+:toclevels: 3
+:source-highlighter: rouge
+
+This document combines and supersedes the earlier `wire-architecture.adoc` and
+`system-architecture.adoc` views for Chronicle Wire.
+It positions Chronicle Wire within the wider OpenHFT stack, describes its core abstractions and layers, and explains how data flows through the system in typical deployments.
+Treat this file as the primary architecture reference and mirror any material changes back into `wire-architecture.adoc` and `system-architecture.adoc` only as summaries.
+
+== Introduction
+
+Chronicle Wire is a high performance, low latency serialisation and deserialisation library that sits near the base of the OpenHFT stack.
+It provides a format agnostic `Wire` API over Chronicle Bytes, allowing the same domain code to read and write YAML, JSON, CSV and several binary formats without changing application logic.
+
+Chronicle Wire is used heavily by Chronicle Queue, Chronicle Map, Chronicle Network and Chronicle Services.
+In these systems it is responsible for turning strongly typed Java objects and service interfaces into bytes that can be stored off heap, persisted to disk, replicated, or sent over the network.
+
+The main architectural goals are:
+
+* Performance - achieve extremely low latency and high throughput for data serialisation and deserialisation while keeping CPU and GC overhead minimal.
+* Flexibility - support multiple text and binary formats behind a unified API so callers can switch representation without large refactors.
+* Extensibility - make it straightforward to add new wire formats, converters and marshalling strategies.
+* Schema evolution - allow data structures to evolve over time without breaking consumers, especially when text and binary formats are mixed.
+
+== System Context and Component Map
+
+At a high level Chronicle Wire sits between business logic and raw bytes.
+
+----
+Application Services -> Wire API -> WireType Implementations -> Chronicle Bytes -> Storage / Network
+ |-> Method Writer/Reader -> Event Consumers
+ |-> Converters / Marshallers -> Domain Objects
+----
+
+* Application services use Wire to read and write domain objects without being tied to a particular serialisation format.
+* The Wire API layer provides `Wire`, `WireIn`, `WireOut`, `DocumentContext`,
+`ValueIn` and `ValueOut` plus interfaces such as `Marshallable` and
+`BytesMarshallable`.
+* WireType implementations (for example text, YAML, JSON, binary) turn API calls into a sequence of bytes in a specific format and back again.
+* Chronicle Bytes offers the underlying on heap and off heap byte stores and the cursor based `Bytes` views used by all Wire implementations.
+* Storage or network layers such as Chronicle Queue and Chronicle Network move those bytes between processes, files and machines.
+
+Within the broader OpenHFT ecosystem the relationships can be viewed as:
+
+ifdef::env-github[[source,mermaid]]
+ifndef::env-github[[mermaid]]
+----
+graph TD
+ subgraph "OpenHFT Ecosystem"
+ A[Chronicle Wire] --> B[Chronicle Queue]
+ A --> C[Chronicle Map]
+ A --> D[Chronicle Network]
+ A --> E[Chronicle Services]
+
+ B -->|"Serialises messages MethodWriter/Reader"| F[Queue Excerpts]
+ C -->|"Serialises keys and values"| G[Off heap Map]
+ D -->|"Marshals data"| H[Network Communication]
+ E -->|"Defines and serialises events"| I[Event Driven Architecture]
+ end
+----
+
+Chronicle Wire is therefore both a standalone library and a shared dependency that strongly influences the performance and behaviour of the higher layers.
+
+== Design Principles
+
+Several core principles guide the implementation of Chronicle Wire.
+
+=== Low Garbage and Direct Memory
+
+* Off heap and direct memory access via Chronicle Bytes is preferred for hot paths to minimise pressure on the JVM garbage collector.
+* Objects that participate in serialisation are designed for reuse.
+Many
+`Marshallable` types expose `reset` or similar methods so instances can be recycled between messages.
+* Where appropriate Chronicle Wire uses Unsafe and low level memory operations (through Chronicle Bytes) to reduce bounds checking and copying overhead, subject to the mitigations described in `security-review.adoc`.
+
+=== Format Agnostic API
+
+* Application code interacts with a single `Wire` API plus `WireIn` and
+`WireOut` interfaces.
+* The `WireType` enumeration selects the concrete implementation to use for a given `Bytes` instance.
+Changing the format is normally a matter of picking a different `WireType` without touching domain logic.
+* Both self describing formats (with field names or identifiers) and compact non self describing formats are supported to allow different trade offs between debuggability and size.
+
+=== Streaming and Framed Documents
+
+* Reading and writing typically happen in a streaming fashion rather than by materialising whole documents up front.
+* `DocumentContext` provides an explicit envelope for a single message or document, which supports replay, skipping and rollback when reading a stream of messages.
+* The same abstractions are used whether data is coming from a queue file, a memory mapped region, a socket, or an in memory buffer.
+
+=== Schema Evolution Friendly
+
+* Self describing textual and binary formats can carry field names and type metadata so that new fields can be added without breaking older readers.
+* Numeric field identifiers (via annotations such as `@FieldNumber`) allow binary schemas to evolve while keeping a stable numeric tag.
+* Converters (for example `LongConverter` based ones) can present compact internal representations while still emitting readable forms in text.
+
+== Layered Architecture
+
+Chronicle Wire's internal architecture can be understood as a set of layers.
+
+ifdef::env-github[[source,mermaid]
+]
+ifndef::env-github[[mermaid]
+]
+
+----
+graph TD
+ A[Application Code] -->|Interacts via| B[Wire API Layer]
+ B -->|Selects and dispatches to| C[Wire Format Implementations]
+ C -->|Operates on and uses| D[Chronicle Bytes Layer]
+ D -->|Reads from and writes to| E[Underlying I/O or Storage Layer]
+
+ classDef appLayer fill:#e6ffe6,stroke:#333,stroke-width:2px,color:#000
+ classDef apiLayer fill:#e6f3ff,stroke:#333,stroke-width:2px,color:#000
+ classDef formatLayer fill:#fff0e6,stroke:#333,stroke-width:2px,color:#000
+ classDef bytesLayer fill:#f9e6ff,stroke:#333,stroke-width:2px,color:#000
+ classDef ioLayer fill:#f2f2f2,stroke:#333,stroke-width:2px,color:#000
+
+ class A appLayer;
+ class B apiLayer;
+ class C formatLayer;
+ class D bytesLayer;
+ class E ioLayer;
+----
+
+=== Application and Domain Layer
+
+* Contains the caller's business logic and domain objects.
+* Domain objects are often Plain Old Java Objects that implement the
+`Marshallable` interface or extend `SelfDescribingMarshallable`.
+* Service interfaces can be exposed to Wire via the method writer and method reader infrastructure.
+
+=== Wire API Layer
+
+The main abstractions are:
+
+* `Wire` - the central interface that combines `WireIn` and `WireOut`.
+It provides access to `ValueIn` and `ValueOut` for reading and writing fields and nested documents.
+* `WireIn` and `WireOut` - lower level interfaces for reading and writing primitive types, strings, sequences and maps in a format neutral way.
+* `ValueIn` and `ValueOut` - fluent entry points used by `Marshallable` objects to pull or push values, including nested marshallable structures.
+* `DocumentContext` - frames a single document or message in a stream so that a sequence of messages can be processed safely and independently.
+* `Marshallable` and `SelfDescribingMarshallable` - higher level interfaces and base classes used by DTOs that want Wire to serialise and deserialise their fields automatically.
+* `BytesMarshallable` - a lower level interface for types that want to control their exact byte layout by reading and writing directly against `Bytes`.
+* `WireType` - an enumeration that chooses the concrete `Wire` implementation for a given `Bytes` instance.
+It also captures format specific configuration.
+
+=== Wire Format Implementation Layer
+
+Each supported `WireType` has a corresponding implementation that knows how to encode and decode the API operations into bytes.
+
+* Textual formats such as YAML, JSON, CSV and plain text are used for human readable configuration, debugging, and integration with other systems.
+* Binary formats such as `BINARY`, `BINARY_LIGHT` and `FIELDLESS_BINARY` provide compact, high performance encodings for latency sensitive use cases.
+* `RAW` formats target bytes level marshalling for `BytesMarshallable` types and other specialised scenarios.
+* The special `READ_ANY` type attempts to detect and read any supported format, which is useful for tools and generic consumers.
+
+These implementations share common conventions about field naming, ordering and defaulting so that `Marshallable` objects can be round tripped between formats without changing semantics.
+
+=== Chronicle Bytes Layer
+
+Chronicle Bytes supplies the general purpose `Bytes` and `BytesStore`
+abstractions that Wire builds upon.
+
+* `BytesStore` represents the underlying storage region, which may be on heap, native off heap or memory mapped file.
+* `Bytes` exposes cursor based reading and writing operations over a
+`BytesStore`.
+Wire implementations treat `Bytes` as their primary input and output surface.
+* Reference counting and explicit `close` semantics are used to control the lifecycle of off heap resources and mappings.
+
+Wire relies on Chronicle Bytes for efficient primitive access, elastic buffer growth, and zero copy views over backing storage.
+
+=== Storage and Transport Layer
+
+This layer is usually provided by other OpenHFT components:
+
+* Chronicle Queue uses Wire to serialise messages into queue excerpts stored in memory mapped files.
+* Chronicle Map uses Wire to serialise keys and values that live in its off heap data structures.
+* Chronicle Network can use Wire to marshal payloads over TCP or other network transports.
+* Chronicle Services use Wire as the event serialisation mechanism for service to service protocols.
+
+Wire itself does not open sockets or files; it simply operates on the `Bytes`
+given to it by these higher layers.
+
+== Message Lifecycle and Data Flow
+
+The typical lifecycle for a message written with Chronicle Wire is:
+
+. The caller acquires a `DocumentContext` for writing, usually via a method such as `wire.acquireWritingDocument`.
+. Within the `DocumentContext`, the caller writes fields using `ValueOut` calls or by delegating to a `Marshallable` object.
+. The `DocumentContext` is closed, which publishes the document and advances the underlying `Bytes` write position.
+. A consumer obtains a view of the same bytes, wraps it in a `Wire` of the appropriate `WireType`, and acquires a `DocumentContext` for reading.
+. The consumer reads fields using `ValueIn` or calls into a `Marshallable` to reconstruct the DTO or event.
+
+Method writers and readers provide a higher level variant of this flow:
+
+* A method writer proxies a service interface and turns method calls into wire messages.
+* A method reader reads messages from a `Wire` and invokes the corresponding methods on a target implementation.
+
+This pattern allows application code to remain interface based while relying on Wire for the underlying serialisation work.
+
+== Schema Evolution Overview
+
+Chronicle Wire supports a range of approaches to schema evolution.
+
+* Adding fields - new fields added to a `Marshallable` class are written by new writers.
+Older readers simply ignore unknown fields in self describing formats.
+* Removing fields - when fields are removed they are no longer written by new code.
+Older readers expecting those fields see default or null values when reading data written by newer code.
+* Reordering fields - in text formats and binary formats with field names the order of fields is generally not significant.
+* Numeric field identifiers - `@FieldNumber` can be used to assign stable numeric identifiers in binary formats so that fields can be renamed in code without changing the on wire representation.
+
+Fieldless binary formats are more sensitive to schema changes, because both ends must agree on the exact order and type of fields.
+They are typically reserved for internal, tightly controlled schemas.
+
+For detailed rules and examples see `wire-schema-evolution.adoc`.
+
+== Performance Considerations
+
+Several aspects of the design contribute to Chronicle Wire's performance:
+
+* Chronicle Bytes minimises copying and garbage creation by using off heap storage and direct memory access where appropriate.
+* Specialised `Wire` implementations are tuned for each format, for example using stop bit encoding for integers in binary formats to reduce size.
+* Generated method writers avoid runtime reflection in hot loops by using bytecode generation.
+* Object reuse is encouraged for `DocumentContext`, marshallable DTOs and other helper objects to avoid repeated allocation.
+* Abstraction layers are kept shallow; the public API is clean but the hot path between a method call and bytes on the wire is short.
+
+When integrating Chronicle Wire into an application, performance should be evaluated end to end, including queue or network behaviour, JVM tuning and GC configuration.
+
+== Cross Cutting and Operational Concerns
+
+Chronicle Wire's architecture interacts with several cross cutting concerns that are important for production deployments.
+
+=== Threading and Concurrency
+
+* The single writer principle applies to many usage patterns: a given
+`DocumentContext` should only be mutated by one thread at a time.
+* Shared `Bytes` and `BytesStore` instances rely on Chronicle Bytes sequencing and compare and swap operations for correctness.
+* Thread local caches may be used to reduce allocation in hot paths; care must be taken to avoid leaking sensitive data between tenants when threads are pooled.
+
+=== Error Handling and Diagnostics
+
+* Error handling patterns and expected exception shapes are documented in
+`wire-error-handling.adoc`.
+* Operational responses to failure scenarios are covered in
+`ops-scenarios.adoc` and the runtime health runbook.
+* Exceptions should include as much context as is practical, such as field name and offset, while keeping logging disabled by default in latency sensitive environments.
+
+=== Security and Validation
+
+Chronicle Wire deliberately keeps many hot paths lean to minimise latency, so input validation is often expected to happen at system boundaries.
+
+* `security-review.adoc` documents known trade offs around validation, Unsafe usage, dynamic typing and configuration expansion.
+* Callers are encouraged to enforce maximum message sizes, validate inputs at network or API boundaries, and treat dynamic type tags carefully.
+* Logging controls such as `YamlLogging` should be used sparingly in production to avoid leaking sensitive data.
+
+=== Documentation and Traceability
+
+* Requirements are captured in `project-requirements.adoc`,
+`functional-requirements.adoc`, `data-requirements.adoc` and
+`operational-requirements.adoc`.
+* Architectural and process decisions are recorded in `decision-log.adoc` with traceability to requirements and tests.
+* Real time documentation practices are encouraged so that architecture, requirements, code and tests evolve together.
+
+== Trade-offs and Alternatives
+
+Chronicle Wire makes a number of explicit trade offs to meet its latency and throughput goals.
+
+Minimal validation on hot paths ::
+many low level operations assume that inputs have already been validated at the perimeter.
+This keeps the inner loops simple and fast, but pushes more responsibility onto callers and higher level modules to enforce size limits and reject malformed data.
+Off heap and Unsafe usage ::
+Wire relies on Chronicle Bytes for off heap storage and, where necessary, Unsafe based access.
+This unlocks predictable latency and large data sets but requires careful review and disciplined resource management, as described in `security-review.adoc`.
+Dynamic typing and self describing data ::
+support for type tags and polymorphic DTOs makes schema evolution and debugging easier, but increases the risk of gadget style deserialisation issues if inputs are not constrained to trusted packages.
+Fieldless binary formats ::
+formats such as `FIELDLESS_BINARY` maximise compactness and speed by omitting field names, at the cost of being very sensitive to schema drift.
+They are best reserved for tightly controlled, internal schemas where both ends evolve together.
+Logging defaults ::
+by default, verbose logging and payload dumps are disabled so that hot paths are not polluted with logging overhead.
+This makes initial debugging slightly harder, but is essential for latency sensitive deployments.
+
+Alternative designs include always validating message sizes and structures inside Wire itself, using only heap based buffers and standard Java serialisation APIs, or avoiding dynamic typing and binary formats entirely.
+These approaches are suitable for less latency sensitive systems, but would not meet the performance targets expected of the Chronicle stack.
+The chosen design is documented so that embedding applications can apply compensating controls where needed, for example strict type whitelists, perimeter validation and careful logging policies.
+
+== Related Documents
+
+For deeper detail on specific aspects of Chronicle Wire see:
+
+* `wire-cookbook.adoc` - practical recipes and examples.
+* `wire-annotations.adoc` - annotation based configuration and converters.
+* `wire-schema-evolution.adoc` - detailed schema evolution patterns.
+* `wire-glossary.adoc` - glossary of terminology used across the Wire docs.
+* `wire-error-handling.adoc` - error handling guidance and exception patterns.
+* `security-review.adoc` - security considerations and mitigations.
+* `ops-scenarios.adoc` and `runbooks/wire-runtime-health.adoc` - operational scenarios and runbook entries.
+* `index.adoc` - entry point for the Chronicle Wire documentation set.
diff --git a/src/main/docs/background/openhft-knowledge-pack.adoc b/src/main/docs/background/openhft-knowledge-pack.adoc
index 8dbe35badb..a4b5375688 100644
--- a/src/main/docs/background/openhft-knowledge-pack.adoc
+++ b/src/main/docs/background/openhft-knowledge-pack.adoc
@@ -1,5 +1,4 @@
= OpenHFT Knowledge Pack for Chronicle Wire
-Chronicle Software
:toc:
:sectnums:
:lang: en-GB
@@ -7,12 +6,12 @@ Chronicle Software
== Purpose
-This background note captures institutional knowledge about the OpenHFT ecosystem that Chronicle Wire
-depends on. It informs performance tuning, dependency management, and support policies.
+This background note captures institutional knowledge about the OpenHFT ecosystem that Chronicle Wire depends on.
+It informs performance tuning, dependency management, and support policies.
== Dependency Baseline
-[cols="1,2,2", options="header"]
+[cols="1,2,2",options="header"]
|===
|Library |Notes |Tracking
@@ -39,16 +38,13 @@ release from the `ea` stream but keeps compatibility with the most recent GA.
== Performance Notes
* Chronicle Wire prefers G1 or ZGC for production when running on Java 17+.
-* Allocate direct memory via `-XX:MaxDirectMemorySize` to match Chronicle Queue retention;
- undersizing this flag leads to forced recycling of buffers under load.
-* Use `-Djvm.compile.threshold=1000` or JIT profiles when benchmarking `MethodWriter` to reach
- steady-state quickly.
+* Allocate direct memory via `-XX:MaxDirectMemorySize` to match Chronicle Queue retention; undersizing this flag leads to forced recycling of buffers under load.
+* Use `-Djvm.compile.threshold=1000` or JIT profiles when benchmarking `MethodWriter` to reach steady-state quickly.
== Observability
* Enable `-Dchronicle.wire.dumpOnError=true` during incident triage to print problematic documents.
-* Chronicle Services deployments typically send structured error events to Chronicle Telemetry;
- Wire emits markers that this pipeline consumes.
+* Chronicle Services deployments typically send structured error events to Chronicle Telemetry; Wire emits markers that this pipeline consumes.
== References
diff --git a/src/main/docs/data-requirements.adoc b/src/main/docs/data-requirements.adoc
index 8e3ffa8f7f..16d079d595 100644
--- a/src/main/docs/data-requirements.adoc
+++ b/src/main/docs/data-requirements.adoc
@@ -1,5 +1,4 @@
= Chronicle Wire Data Requirements
-Chronicle Software
:toc:
:sectnums:
:lang: en-GB
@@ -8,12 +7,11 @@ Chronicle Software
== Purpose
This document captures the structural expectations for Chronicle Wire payloads.
-It complements `functional-requirements.adoc` by focusing on envelopes, metadata,
-and schema-evolution guidance shared by all `WireType` implementations.
+It complements `functional-requirements.adoc` by focusing on envelopes, metadata, and schema-evolution guidance shared by all `WireType` implementations.
== Message Envelope
-[cols="1,3", options="header"]
+[cols="1,3",options="header"]
|===
|ID |Requirement
@@ -23,8 +21,8 @@ The writer must emit the document length (for binary wires) or delimiter (for te
so downstream consumers can skip, replay, or rewind without parsing the payload itself.
|FN-102
-|Field names shall be emitted verbatim for textual wires and mapped to 32-bit field identifiers
-(`WireKey`) for binary wires. Field identifiers must stay stable across releases to preserve backwards compatibility.
+|Field names shall be emitted verbatim for textual wires and mapped to 32-bit field identifiers (`WireKey`) for binary wires.
+Field identifiers must stay stable across releases to preserve backwards compatibility.
|FN-103
|When class metadata is present (`@type` in YAML/JSON or numeric type IDs in BinaryWire),
@@ -34,26 +32,26 @@ it must reference the fully-qualified Java class or an alias registered via `Cla
== Scalar and Collection Semantics
* Numeric types are encoded using the narrowest width that preserves the caller's precision.
- `long` timestamps must stay in epoch nanoseconds to align with down-stream `Pauser` and engine components.
+`long` timestamps must stay in epoch nanoseconds to align with down-stream `Pauser` and engine components.
* Text values default to UTF-8 bytes on the wire while remaining ISO-8859-1 inside documentation.
-* Collections are written as nested documents where each entry uses either an implicit numeric key
- (arrays) or explicit field names (maps). Ordered collections retain insertion order.
+* Collections are written as nested documents where each entry uses either an implicit numeric key (arrays) or explicit field names (maps).
+Ordered collections retain insertion order.
== Schema Evolution Policy
-1. Prefer additive changes (new optional fields, new message types).
-2. Deprecations must keep the existing field identifier reserved even if unused.
-3. When renaming a field, register the former name via `FieldNumberLookup`
- and keep a test in `WireSchemaEvolutionTest.java` or an equivalent suite.
-4. Use explicit defaults in readers to avoid `NullPointerException` when older payloads omit the new field.
+. Prefer additive changes (new optional fields, new message types).
+. Deprecations must keep the existing field identifier reserved even if unused.
+. When renaming a field, register the former name via `FieldNumberLookup`
+and keep a test in `WireSchemaEvolutionTest.java` or an equivalent suite.
+. Use explicit defaults in readers to avoid `NullPointerException` when older payloads omit the new field.
== Metadata and Retention
* Every document that leaves the JVM must carry a monotonically increasing `messageId`
- or sequence supplied by the caller; Chronicle Wire does not synthesise one automatically.
+or sequence supplied by the caller; Chronicle Wire does not synthesise one automatically.
* Timestamps inherit the caller timezone; the library never rewrites them.
* Payloads stored on disk or transmitted over the network must keep their native endianness.
- Mixing `WireType#binary` and `WireType#binary_little_endian` within the same queue is unsupported.
+Mixing `WireType#binary` and `WireType#binary_little_endian` within the same queue is unsupported.
== References
diff --git a/src/main/docs/decision-log.adoc b/src/main/docs/decision-log.adoc
index 492c542832..2ccb7f4056 100644
--- a/src/main/docs/decision-log.adoc
+++ b/src/main/docs/decision-log.adoc
@@ -1,5 +1,4 @@
= Chronicle Wire Decision Log
-Chronicle Software
:toc:
:sectnums:
:lang: en-GB
@@ -8,7 +7,7 @@ Chronicle Software
This log records architectural and process choices that affect Chronicle Wire.
Entries follow the Chronicle-wide template and use Nine-Box identifiers.
-=== [DOC-001] Real-time Documentation Loop
+== [DOC-001] Real-time Documentation Loop
Date :: 2024-05-01
Context ::
@@ -16,12 +15,12 @@ Context ::
* Chronicle introduced the expectation that docs, tests, and code move together.
Decision Statement :: Adopt a real-time documentation workflow where any behavioural change updates the related `.adoc` file before merging.
Alternatives Considered ::
-* Do nothing: Accept drift and rely on periodic clean-up. ::
- ** Pros: No immediate effort.
- ** Cons: Reviewers cannot trust docs; regressions slip through.
-* Batch documentation pushes during release hardening. ::
- ** Pros: Potentially fewer doc merges.
- ** Cons: High risk of missing knowledge; difficult cherry-picks.
+* Do nothing: Accept drift and rely on periodic clean-up.
+** Pros: No immediate effort.
+** Cons: Reviewers cannot trust docs; regressions slip through.
+* Batch documentation pushes during release hardening.
+** Pros: Potentially fewer doc merges.
+** Cons: High risk of missing knowledge; difficult cherry-picks.
Rationale for Decision ::
* Keeps requirements and runbooks trustworthy for both humans and AI agents.
* Reduces rework because inconsistencies are caught early.
@@ -29,10 +28,10 @@ Impact & Consequences ::
* Slightly longer individual PRs, but faster acceptance.
* Enables tooling (`scripts/check-doc-includes.py`) to enforce completeness.
Notes/Links ::
-** `project-requirements.adoc`
-** `ops-scenarios.adoc`
+* `project-requirements.adoc`
+* `ops-scenarios.adoc`
-=== [NF-O-002] Multi-JDK Verification Gates
+== [NF-O-002] Multi-JDK Verification Gates
Date :: 2024-05-10
Context ::
@@ -40,12 +39,14 @@ Context ::
* CI already mirrors branches such as `develop-java8-ok`.
Decision Statement :: Make `mvn -q clean verify` on JDK 8, 11, 17, and 21 a release gate.
Alternatives Considered ::
-* Support only the latest two LTS releases. ::
- ** Pros: Less CI cost.
- ** Cons: Breaks downstream platforms still on Java 8.
-* Allow per-feature overrides. ::
- ** Pros: Faster experimentation.
- ** Cons: High risk of shipping regressions unnoticed.
+* Support only the latest two LTS releases.
+::
+** Pros: Less CI cost.
+** Cons: Breaks downstream platforms still on Java 8.
+* Allow per-feature overrides.
+::
+** Pros: Faster experimentation.
+** Cons: High risk of shipping regressions unnoticed.
Rationale for Decision ::
* Chronicles' clients adopt new JVMs at different speeds; regression risk outweighs CI cost.
* Early detection prevents subtle `Unsafe` or module-related bugs.
@@ -53,5 +54,101 @@ Impact & Consequences ::
* Developers must reproduce failures locally or via container images.
* The release checklist now includes CI links for every JVM build.
Notes/Links ::
-** `operational-requirements.adoc`
-** `functional-requirements.adoc`
+* `operational-requirements.adoc`
+* `functional-requirements.adoc`
+
+== [FN-001] WireType Matrix and Marshallable Compatibility
+
+Date :: 2024-11-14
+Context ::
+* Chronicle Wire must serialise and deserialise `Marshallable` and `SelfDescribingMarshallable` objects consistently across all supported `WireType` implementations (`TextWire`, `YamlWire`, `JSONWire`, `BinaryWire`, and related variants).
+* Downstream components such as Chronicle Queue, Chronicle Map, and Chronicle Services rely on being able to switch wire formats for debugging, configuration, or transport without changing application-level code.
+Decision Statement :: Treat `Marshallable` and `SelfDescribingMarshallable` as the canonical programming model and require each `WireType` implementation to preserve field names, ordering rules, and defaulting semantics when round-tripping data.
+Alternatives Considered ::
+* Per-format APIs (for example YAML-specific and binary-specific marshalling code).
+** Pros: Could be tuned for each format.
+** Cons: Fragments the API, increases maintenance, and makes cross-format testing difficult.
+* Restricting Chronicle Wire to a single preferred format (for example binary only).
+** Pros: Simpler surface area and fewer corner cases.
+** Cons: Reduces debuggability and flexibility; breaks existing YAML and JSON use cases.
+Rationale for Decision ::
+* A single `Wire` API keeps application code independent of the representation while still allowing formats to evolve.
+* Using `Marshallable` as the canonical contract ensures testability and provides a clear place to enforce compatibility.
+Impact & Consequences ::
+* All new formats and optimisations must be validated against the regression suites listed under `FN-001` in `functional-requirements.adoc`.
+* Documentation and examples should demonstrate swapping `WireType` without changing business logic.
+Notes/Links ::
+* `functional-requirements.adoc` (requirement `FN-001`)
+* `wire-architecture.adoc`
+
+== [FN-002] DocumentContext Boundaries and Streaming
+
+Date :: 2024-11-14
+Context ::
+* Chronicle Wire is used to stream sequences of messages over files, queues, and network transports.
+* Consumers must be able to replay, skip, or roll back individual documents without corrupting surrounding state, and enforce single-writer and single-reader semantics.
+Decision Statement :: Treat `DocumentContext` as the standard envelope for multi-message streams, enforcing clear start and end boundaries and associating metadata with each document.
+Alternatives Considered ::
+* Implicit message boundaries based solely on `Bytes` positions.
+** Pros: Slightly simpler API for trivial use cases.
+** Cons: Error prone, makes replay and partial reads harder, and complicates integration with Chronicle Queue.
+* Per-format framing rules without a common abstraction.
+** Pros: Allows fine tuned formats.
+** Cons: Pushes complexity into user code and reduces portability between transports.
+Rationale for Decision ::
+* `DocumentContext` provides a uniform way to demarcate messages while still allowing underlying `Bytes` to be shared and reused.
+* Explicit boundaries make error handling and back-pressure strategies easier to document and test.
+Impact & Consequences ::
+* Application code should wrap read and write operations in `try (DocumentContext dc = wire.writingDocument())` or `readingDocument()` blocks.
+* Tests listed under `FN-002` validate nested documents and ensure context metadata survives round trips.
+Notes/Links ::
+* `functional-requirements.adoc` (requirement `FN-002`)
+* `system-architecture.adoc`
+
+== [NF-P-001] Bytecode-backed Method Writers
+
+Date :: 2024-11-14
+Context ::
+* Many Chronicle Wire users expose service APIs as Java interfaces and expect these abstractions to be turned into wire traffic with minimal allocation and overhead.
+* Reflection heavy proxies introduce garbage and can become a bottleneck in hot loops.
+Decision Statement :: Use bytecode generated method writers and readers as the primary mechanism for turning interfaces into wire messages, avoiding runtime reflection in steady state hot paths.
+Alternatives Considered ::
+* Pure reflection based proxies for method dispatch.
+** Pros: Simpler implementation with no explicit code generation step.
+** Cons: Higher allocation rate and slower dispatch under load.
+* Manually written adapters for each service interface.
+** Pros: Maximum control over encoding and performance.
+** Cons: High maintenance cost and increased chance of subtle bugs.
+Rationale for Decision ::
+* Bytecode backed proxies strike a balance between performance and maintainability and are supported by Chronicle code generation tooling.
+* Generated writers make it easier to attach interceptors and adapters without duplicating boilerplate.
+Impact & Consequences ::
+* Interface design should favour simple, streaming friendly signatures that map cleanly to wire operations.
+* Performance regressions in method writer code paths should be treated as violations of `FN-004` in `functional-requirements.adoc`.
+Notes/Links ::
+* `functional-requirements.adoc` (requirement `FN-004`)
+* `system-architecture.adoc`
+
+== [NF-O-001] Serialisation Error Diagnostics and Logging Defaults
+
+Date :: 2024-11-14
+Context ::
+* Users require actionable diagnostics when serialisation fails, but Chronicle Wire is commonly used in low latency environments where logging noise must be minimised.
+* The operational requirement `NF-O-001` mandates including the field name, type, and offset in error messages where possible.
+Decision Statement :: Provide rich exception messages and structured diagnostics for serialisation failures while keeping logging disabled by default and delegating logging policy to calling applications.
+Alternatives Considered ::
+* Enable verbose logging within Chronicle Wire by default.
+** Pros: Easier initial debugging.
+** Cons: Unacceptable overhead and log volume in production, especially in inner loops.
+* Provide only minimal error detail to avoid overhead.
+** Pros: Saves some CPU and reduces message size.
+** Cons: Makes issues difficult to diagnose, particularly with binary formats.
+Rationale for Decision ::
+* Exception construction is outside the hottest paths; including field names and offsets provides significant debugging value.
+* Allowing callers to decide when to enable logging keeps Chronicle Wire suitable for latency sensitive workloads.
+Impact & Consequences ::
+* Developers should follow the patterns described in `wire-error-handling.adoc` when adding new exceptions or validation logic.
+* Regression tests for malformed input should assert on exception text where feasible, not just on the exception type.
+Notes/Links ::
+* `operational-requirements.adoc` (requirement `NF-O-001`)
+* `wire-error-handling.adoc`
diff --git a/src/main/docs/functional-requirements.adoc b/src/main/docs/functional-requirements.adoc
index 867e507cdf..db7418838b 100644
--- a/src/main/docs/functional-requirements.adoc
+++ b/src/main/docs/functional-requirements.adoc
@@ -1,5 +1,4 @@
= Chronicle Wire Functional Requirements
-Chronicle Software
:toc:
:sectnums:
:lang: en-GB
@@ -8,12 +7,11 @@ Chronicle Software
== Purpose
This catalogue lists the functional behaviours that Chronicle Wire must keep stable across releases.
-It references representative regression tests and the build command (`mvn -q clean verify`) that must
-pass before shipping any change.
+It references representative regression tests and the build command (`mvn -q clean verify`) that must pass before shipping any change.
== Requirement Table
-[cols="1,3,2", options="header"]
+[cols="1,3,2",options="header"]
|===
|ID |Description |Verification
@@ -24,8 +22,8 @@ mapping across all `WireType` implementations, including `TextWire`, `YamlWire`,
`src/test/java/net/openhft/chronicle/wire/*Wire*.java`.
|FN-002
-|Provide explicit `DocumentContext` boundaries so multi-message streams can be replayed, skipped, or
-rolled back without corrupting state. Nested documents must maintain parent context metadata.
+|Provide explicit `DocumentContext` boundaries so multi-message streams can be replayed, skipped, or rolled back without corrupting state.
+Nested documents must maintain parent context metadata.
|Lifecycle tests at `src/test/java/net/openhft/chronicle/wire/DocumentContextLifecycleTest.java`,
`ReadDocumentContextTest.java`, and `WriteDocumentContextTest.java`.
@@ -48,8 +46,8 @@ hooks so downstream engines keep nanosecond precision without intermediate alloc
`src/test/java/net/openhft/chronicle/wire/LongConversionTest.java`.
|FN-006
-|Reference counting for shared `Bytes` instances must stay consistent so wire readers and writers can
-handover buffers without leaks. Leaked owners shall trigger `warnAndReleaseIfNotReleased()` to keep queues
+|Reference counting for shared `Bytes` instances must stay consistent so wire readers and writers can handover buffers without leaks.
+Leaked owners shall trigger `warnAndReleaseIfNotReleased()` to keep queues
stable, as outlined in xref:system-architecture.adoc#component_map[System Architecture – Component Map].
|`src/test/java/net/openhft/chronicle/wire/BytesReferenceCountingTest.java`,
`src/test/java/net/openhft/chronicle/wire/WireResourcesTest.java`.
@@ -65,7 +63,5 @@ xref:system-architecture.adoc#cross_cutting_concerns[System Architecture – Cro
== Traceability and Updates
* Link new requirements back to `project-requirements.adoc` and the ADR in `decision-log.adoc`.
-* When new behaviours are introduced, expand this file, add the corresponding tests, and keep the IDs
-stable so release notes can track regressions precisely.
-* Always update the `Verification` column with the canonical test path to help reviewers jump straight
-to the relevant coverage.
+* When new behaviours are introduced, expand this file, add the corresponding tests, and keep the IDs stable so release notes can track regressions precisely.
+* Always update the `Verification` column with the canonical test path to help reviewers jump straight to the relevant coverage.
diff --git a/src/main/docs/index.adoc b/src/main/docs/index.adoc
index 3491f5ceab..2121e04cfe 100644
--- a/src/main/docs/index.adoc
+++ b/src/main/docs/index.adoc
@@ -1,15 +1,20 @@
= Chronicle Wire Documentation
-:toc: left
+:toc:
+:sectnums:
+:lang: en-GB
:toclevels: 2
:source-highlighter: rouge
-:sectnums:
-Chronicle Wire is a high-performance, low-latency serialisation library that forms part of the OpenHFT stack. This index links to the documentation set.
+Chronicle Wire is a high performance, low latency serialisation library that forms part of the OpenHFT stack.
+This index links to the documentation set.
== Documentation Index
-link:wire-architecture.adoc[Chronicle Wire: Architectural Overview] ::
- Summarises the internal architecture, components and design principles.
+link:architecture-overview.adoc[Chronicle Wire Architecture Overview] ::
+ Positions Chronicle Wire within the OpenHFT stack and summarises the layered architecture, components and data flows.
+
+link:wire-architecture.adoc[Internal Architecture Details] ::
+ Expands on internal layers, `WireType` implementations, and design principles.
link:system-architecture.adoc[System Architecture Summary] ::
Shows how Chronicle Wire links application services, wire formats, and Chronicle Bytes.
@@ -23,6 +28,9 @@ link:data-requirements.adoc[Data Requirements] ::
link:operational-requirements.adoc[Operational Requirements] ::
Captures build gates, diagnostics policy, and documentation expectations.
+link:testing-strategy.adoc[Testing Strategy] ::
+ Describes the unit, integration and performance testing approach for Chronicle Wire.
+
link:interface-control.adoc[Interface Control Document] ::
Documents the contracts exposed to applications (`Wire`, `DocumentContext`, writers/readers).
@@ -62,11 +70,11 @@ link:decision-log.adoc[Decision Log] ::
link:background/openhft-knowledge-pack.adoc[OpenHFT Knowledge Pack] ::
Records version support, JVM targets, and tuning notes.
-link:../../EventsByMethod.adoc[Events by Method Guide] ::
+link:EventsByMethod.adoc[Events by Method Guide] ::
Explains the event-driven approach via asynchronous method calls.
-link:../../YAML2SpecificationCompliance.adoc[YAML 1.2 Compliance Notes] ::
+link:YAML2SpecificationCompliance.adoc[YAML 1.2 Compliance Notes] ::
Details how Chronicle Wire aligns with the YAML 1.2 specification.
-link:../../systemProperties.adoc[System Properties Guide] ::
+link:system-properties.adoc[System Properties Guide] ::
Lists Java system properties influencing Chronicle components.
diff --git a/src/main/docs/interface-control.adoc b/src/main/docs/interface-control.adoc
index 30b32715b9..9b92348597 100644
--- a/src/main/docs/interface-control.adoc
+++ b/src/main/docs/interface-control.adoc
@@ -1,5 +1,4 @@
= Chronicle Wire Interface Control Document
-Chronicle Software
:toc:
:sectnums:
:lang: en-GB
@@ -36,11 +35,11 @@ applications.
== Document Lifecycle
-1. Allocate a document context (`Wire.acquireWritingDocument`). The context carries metadata such as
+. Allocate a document context (`Wire.acquireWritingDocument`). The context carries metadata such as
source ID and thread ID.
-2. Write fields via `ValueOut`. Each call translates to an entry in the current document.
-3. Close the context to publish the bytes downstream.
-4. Readers obtain a matching `DocumentContext` from `Wire.readingDocument()` and consume the fields.
+. Write fields via `ValueOut`. Each call translates to an entry in the current document.
+. Close the context to publish the bytes downstream.
+. Readers obtain a matching `DocumentContext` from `Wire.readingDocument()` and consume the fields.
All code paths must honour this lifecycle; skipping the closing step can leak buffers or block queue tailers.
diff --git a/src/main/docs/operational-requirements.adoc b/src/main/docs/operational-requirements.adoc
index 25e0b18965..b442411030 100644
--- a/src/main/docs/operational-requirements.adoc
+++ b/src/main/docs/operational-requirements.adoc
@@ -1,5 +1,4 @@
= Chronicle Wire Operational Requirements
-Chronicle Software
:toc:
:sectnums:
:lang: en-GB
@@ -7,13 +6,12 @@ Chronicle Software
== Overview
-Chronicle Wire is a library, yet it still has operational expectations for release engineering,
-compatibility, and observability. This document anchors those expectations with `OPS` and `NF-O`
-tags from the Nine-Box taxonomy.
+Chronicle Wire is a library, yet it still has operational expectations for release engineering, compatibility, and observability.
+This document anchors those expectations with `OPS` and `NF-O` tags from the Nine-Box taxonomy.
== Operational Targets
-[cols="1,3,2", options="header"]
+[cols="1,3,2",options="header"]
|===
|ID |Requirement |Notes
@@ -23,13 +21,13 @@ tags from the Nine-Box taxonomy.
|Run the command locally prior to opening a PR and after each rebase.
|OPS-002
-|Release builds must be reproducible. Dependencies are pinned via the Chronicle BOM and validated by
-`project-requirements.adoc`. Enforced by the build scan that fails when SNAPSHOT dependencies leak in.
+|Release builds must be reproducible. Dependencies are pinned via the Chronicle BOM and validated by `project-requirements.adoc`.
+Enforced by the build scan that fails when SNAPSHOT dependencies leak in.
|Check the output of `mvn -q -Dchronicletag=release verify` if a release candidate is prepared.
|NF-O-001
-|Provide actionable diagnostics when serialisation fails. Exceptions must include the field name, type,
-and offset where possible. Logging must stay off by default to avoid polluting low-latency workloads.
+|Provide actionable diagnostics when serialisation fails. Exceptions must include the field name, type, and offset where possible.
+Logging must stay off by default to avoid polluting low-latency workloads.
|`wire-error-handling.adoc` captures the message templates; parser suites such as
`InvalidYamWithCommonMistakesTest.java` and `TextWireTest.java` guard regressions.
@@ -47,8 +45,7 @@ to `functional-requirements.adoc`, the relevant runbook, and at least one regres
== Maintenance Windows
* Patch releases follow Chronicle's standard Tuesday cadence.
-* API-breaking changes are bundled into LTS drops and called out under `decision-log.adoc`
- together with mitigation steps.
+* API-breaking changes are bundled into LTS drops and called out under `decision-log.adoc` together with mitigation steps.
== Runbook Links
diff --git a/src/main/docs/ops-scenarios.adoc b/src/main/docs/ops-scenarios.adoc
index 150295b9ca..e7a5a4181c 100644
--- a/src/main/docs/ops-scenarios.adoc
+++ b/src/main/docs/ops-scenarios.adoc
@@ -1,5 +1,4 @@
= Chronicle Wire Operational Scenarios
-Chronicle Software
:toc:
:sectnums:
:lang: en-GB
@@ -9,27 +8,26 @@ Chronicle Software
OPS-SC-001 :: Build Fails on `mvn -q clean verify`
* Trigger: CI or local build exits non-zero.
- ** Runbook: <>
- ** Requirement: OPS-001
+** Runbook: <>
+** Requirement: OPS-001
* Signals: Maven error logs, missing tests, or format violations.
- ** Tools: `mvn -q -e verify`, `git status`, `scripts/check-doc-includes.py`
+** Tools: `mvn -q -e verify`, `git status`, `scripts/check-doc-includes.py`
OPS-SC-002 :: DocumentContext Leak or Unclosed Writer
* Trigger: Queue tailers stall or Chronicle Queue reports `DocumentContext not closed`.
- ** Runbook: <>
- ** Requirement: FN-002
+** Runbook: <>
+** Requirement: FN-002
* Signals: Thread dumps pointing at `DocumentContext.close`, growing mapped file usage.
- ** Tools: `jcmd Thread.print`, `wire-error-handling.adoc`
+** Tools: `jcmd Thread.print`, `wire-error-handling.adoc`
OPS-SC-003 :: Schema Drift Between Producers and Consumers
* Trigger: Readers throw `UnknownFieldException` or skip fields unexpectedly.
- ** Runbook: <>
- ** Requirement: FN-101 through FN-103
+** Runbook: <>
+** Requirement: FN-101 through FN-103
* Signals: Divergent git SHAs, new fields missing defaults, converter mismatches.
- ** Tools: `wire-schema-evolution.adoc`, `functional-requirements.adoc`, `git bisect`
+** Tools: `wire-schema-evolution.adoc`, `functional-requirements.adoc`, `git bisect`
== Usage
* Each scenario ties back to a requirement ID so reviewers can confirm coverage.
-* Update this file whenever new operational runbooks are added or when incident reviews
- uncover a missing scenario.
+* Update this file whenever new operational runbooks are added or when incident reviews uncover a missing scenario.
diff --git a/src/main/docs/project-requirements.adoc b/src/main/docs/project-requirements.adoc
index 8a98efd681..32e76878d3 100644
--- a/src/main/docs/project-requirements.adoc
+++ b/src/main/docs/project-requirements.adoc
@@ -1,13 +1,18 @@
= Project Requirements: Chronicle Wire Documentation Enhancement
:toc:
:sectnums:
+:lang: en-GB
:source-highlighter: rouge
To outline the detailed requirements for creating comprehensive and technically rich documentation for the Chronicle Wire library, aimed at improving user understanding, adoption, and effective utilization.
== Introduction
-This document specifies the detailed requirements for a significant enhancement of the documentation for the Chronicle Wire library. Chronicle Wire is a foundational component within the OpenHFT (Open High-Frequency Trading) ecosystem, designed for high-performance, low-latency data serialisation and deserialisation. The current initiative aims to produce documentation that is technically deep, practically useful, and addresses the needs of a diverse developer audience. This enhancement will be based on an exhaustive technical review of Chronicle Wire, covering its architecture, features, diverse use cases within OpenHFT (including inter-process communication (IPC), object serialisation, low-latency systems design, and data persistence strategies), and a thorough comparative analysis against other prominent serialisation libraries. The ultimate goal is to establish this documentation as the authoritative resource for Chronicle Wire.
+This document specifies the detailed requirements for a significant enhancement of the documentation for the Chronicle Wire library.
+Chronicle Wire is a foundational component within the OpenHFT (Open High-Frequency Trading) ecosystem, designed for high-performance, low-latency data serialisation and deserialisation.
+The current initiative aims to produce documentation that is technically deep, practically useful, and addresses the needs of a diverse developer audience.
+This enhancement will be based on an exhaustive technical review of Chronicle Wire, covering its architecture, features, diverse use cases within OpenHFT (including inter-process communication (IPC), object serialisation, low-latency systems design, and data persistence strategies), and a thorough comparative analysis against other prominent serialisation libraries.
+The ultimate goal is to establish this documentation as the authoritative resource for Chronicle Wire.
== Goals
@@ -44,106 +49,161 @@ The documentation shall comprehensively cover the following key areas:
=== Core Chronicle Wire Concepts
Comprehensive Overview ::
-* **Introduction:** What Chronicle Wire is, its origin within OpenHFT, and the core problems it solves (e.g., performance bottlenecks of standard Java serialisation, need for format flexibility).
-* **Design Philosophy:** In-depth discussion of low latency, minimal garbage creation, off-heap memory utilization, format agnosticism, and schema flexibility as primary design tenets.
-* **Key Abstractions:** Detailed explanation of `Bytes`, `Wire`, `WireIn`, `WireOut`, `DocumentContext`, `Marshallable`, `SelfDescribingMarshallable`, and `BytesMarshallable`.
+Introduction ::
+What Chronicle Wire is, its origin within OpenHFT, and the core problems it solves (e.g., performance bottlenecks of standard Java serialisation, need for format flexibility).
+Design Philosophy ::
+In-depth discussion of low latency, minimal garbage creation, off-heap memory utilization, format agnosticism, and schema flexibility as primary design tenets.
+Key Abstractions ::
+Detailed explanation of `Bytes`, `Wire`, `WireIn`, `WireOut`, `DocumentContext`, `Marshallable`, `SelfDescribingMarshallable`, and `BytesMarshallable`.
Supported Serialisation Formats (`WireType`) ::
* For each `WireType` (YAML, JSON, JSON_ONLY, BINARY, BINARY_LIGHT, FIELDLESS_BINARY, TEXT, RAW, CSV, READ_ANY):
-** **Detailed Explanation:** Underlying structure, specific features (e.g., human readability, self-description, compactness). For binary formats, discuss aspects like stop-bit encoding for integers.
-** **Instantiation and Usage:** How to create and use each `Wire` type with `Bytes`.
-** **Use Cases:** Recommended scenarios for each format (e.g., YAML for configuration/debugging, BINARY_LIGHT for performance-critical IPC, FIELDLESS_BINARY for extreme compactness when schema is shared).
-** **Performance Implications:** Relative speed, serialized size, and CPU overhead.
-** **Limitations and Caveats:** Any specific constraints or things to be aware of (e.g., FIELDLESS_BINARY requires identical schema on both ends).
-** **Interoperability:** How different wire types can be used together (e.g., reading a binary message and logging it as YAML).
+** *Detailed Explanation:* Underlying structure, specific features (e.g., human readability, self-description, compactness).
+For binary formats, discuss aspects like stop-bit encoding for integers.
+** *Instantiation and Usage:* How to create and use each `Wire` type with `Bytes`.
+** *Use Cases:* Recommended scenarios for each format (e.g., YAML for configuration/debugging, BINARY_LIGHT for performance-critical IPC, FIELDLESS_BINARY for extreme compactness when schema is shared).
+** *Performance Implications:* Relative speed, serialized size, and CPU overhead.
+** *Limitations and Caveats:* Any specific constraints or things to be aware of (e.g., FIELDLESS_BINARY requires identical schema on both ends).
+** *Interoperability:* How different wire types can be used together (e.g., reading a binary message and logging it as YAML).
The `Marshallable` Ecosystem ::
-* **`Marshallable` Interface:** Deep dive into how to implement it, the role of `readMarshallable` and `writeMarshallable` methods (both explicit and default-generated).
-* **`SelfDescribingMarshallable`:** Benefits of extending this class (automatic `toString()`, `equals()`, `hashCode()`, schema information in text formats), and how these methods are generated from the serialized form.
-* **`BytesMarshallable`:** When and how to use it for finer-grained control over serialisation, direct `Bytes` manipulation, and potential performance gains/trade-offs compared to `Marshallable`. Examples of manual field writing/reading.
-* **Automatic Serialisation:** Explanation of the mechanisms used (reflection, runtime code generation via `WireMarshaller`) and their performance characteristics.
-* **Object Graph Serialisation:** How Chronicle Wire handles nested `Marshallable` objects, collections of `Marshallable` objects, and object references (if applicable, or limitations thereof).
+`Marshallable` Interface ::
+Deep dive into how to implement it, the role of `readMarshallable` and `writeMarshallable` methods (both explicit and default-generated).
+`SelfDescribingMarshallable` ::
+Benefits of extending this class (automatic `toString()`, `equals()`, `hashCode()`, schema information in text formats), and how these methods are generated from the serialized form.
+`BytesMarshallable` ::
+When and how to use it for finer-grained control over serialisation, direct `Bytes` manipulation, and potential performance gains/trade-offs compared to `Marshallable`.
+Examples of manual field writing/reading.
+Automatic Serialisation ::
+Explanation of the mechanisms used (reflection, runtime code generation via `WireMarshaller`) and their performance characteristics.
+Object Graph Serialisation ::
+How Chronicle Wire handles nested `Marshallable` objects, collections of `Marshallable` objects, and object references (if applicable, or limitations thereof).
Schema Evolution and Versioning ::
-* **Detailed Mechanisms:** How Chronicle Wire supports schema changes (adding, removing, reordering fields) in self-describing formats.
-* **Field Identification:** Role of field names in text formats and field numbers/names in binary formats.
-* **Handling Unknown Fields:** How readers skip fields not present in their class definition.
-* **Handling Missing Fields:** How new fields in a class are initialized with default values when reading older data.
-* **Best Practices for Versioning:** Strategies for evolving `Marshallable` classes over time to maintain backward and forward compatibility.
-* **Limitations:** Any scenarios where schema evolution might be problematic or require manual intervention (e.g., changing field types significantly).
-* **Comparison:** Explicit comparison of Wire's schema evolution capabilities with those of Protobuf and Avro.
+Detailed Mechanisms ::
+How Chronicle Wire supports schema changes (adding, removing, reordering fields) in self-describing formats.
+Field Identification ::
+Role of field names in text formats and field numbers/names in binary formats.
+Handling Unknown Fields ::
+How readers skip fields not present in their class definition.
+Handling Missing Fields ::
+How new fields in a class are initialized with default values when reading older data.
+Best Practices for Versioning ::
+Strategies for evolving `Marshallable` classes over time to maintain backward and forward compatibility.
+Limitations ::
+Any scenarios where schema evolution might be problematic or require manual intervention (e.g., changing field types significantly).
+Comparison ::
+Explicit comparison of Wire's schema evolution capabilities with those of Protobuf and Avro.
Annotations for Fine-Grained Control and Customisation ::
* For each key annotation (e.g., `@LongConversion`, `@NanoTime`, `@Base64`, `@Base85`, `@ShortText`, `@MaxUtf8Len`, `@Comment`, `@FieldNumber`):
-** **Purpose and Functionality:** Clear explanation of what the annotation does.
-** **Parameters:** Description of any parameters the annotation takes.
-** **Impact:** How it affects serialisation in different `WireType`s (e.g., text vs. binary representation).
-** **Use Cases:** Practical examples illustrating when and how to use the annotation.
-** **Example Code:** Snippets demonstrating its application.
-* **Custom Converters:** Detailed guide on creating and using custom `LongConverter` implementations or other relevant converters.
+** *Purpose and Functionality:* Clear explanation of what the annotation does.
+** *Parameters:* Description of any parameters the annotation takes.
+** *Impact:* How it affects serialisation in different `WireType`s (e.g., text vs. binary representation).
+** *Use Cases:* Practical examples illustrating when and how to use the annotation.
+** *Example Code:* Snippets demonstrating its application.
+Custom Converters ::
+Detailed guide on creating and using custom `LongConverter` implementations or other relevant converters.
Fluent API (`WireIn`/`WireOut` and `ValueIn`/`ValueOut`) ::
-* **Detailed Usage:** Comprehensive examples of using `writeEventName()`, `writeValue()`, `readEventName()`, `readValue()`, and various type-specific methods (`text()`, `int32()`, `bool()`, `marshallable()`, `sequence()`, etc.).
-* **`DocumentContext`:** In-depth explanation of its role in demarcating messages/documents, especially in the context of Chronicle Queue. Managing document boundaries, metadata within documents (`isData()`, `isNotComplete()`, `isPresent()`).
-* **Use Cases:** Scenarios where the fluent API is preferred over `Marshallable` objects (e.g., dynamic data structures, integrating with non-`Marshallable` types, writing raw byte sequences).
-* **Performance Considerations:** Potential impact on performance and GC compared to `Marshallable` usage.
-* **Error Handling:** How to detect and handle issues like malformed data or type mismatches when using the fluent API.
+Detailed Usage ::
+Comprehensive examples of using `writeEventName()`, `writeValue()`, `readEventName()`, `readValue()`, and various type-specific methods (`text()`, `int32()`, `bool()`, `marshallable()`, `sequence()`, etc.).
+`DocumentContext` ::
+In-depth explanation of its role in demarcating messages/documents, especially in the context of Chronicle Queue.
+Managing document boundaries, metadata within documents (`isData()`, `isNotComplete()`, `isPresent()`).
+Use Cases ::
+Scenarios where the fluent API is preferred over `Marshallable` objects (e.g., dynamic data structures, integrating with non-`Marshallable` types, writing raw byte sequences).
+Performance Considerations ::
+Potential impact on performance and GC compared to `Marshallable` usage.
+Error Handling ::
+How to detect and handle issues like malformed data or type mismatches when using the fluent API.
Low-Latency and High-Performance Features ::
-* **`Chronicle Bytes` Integration:** Detailed explanation of how Chronicle Wire leverages `Bytes` for direct memory operations (on-heap and off-heap).
-* **Off-Heap Memory:** Techniques for serializing directly to/from off-heap `BytesStore` instances to minimize GC impact. Examples using `Bytes.allocateElasticDirect()`.
-* **Zero-Copy Principles:** How Chronicle Wire facilitates zero-copy data exchange in conjunction with components like Chronicle Queue and Network.
-* **Object Reuse:** Advanced patterns for object pooling and reuse with `Marshallable.reset()` or similar techniques to reduce allocations in critical loops.
-* **Flyweights and `Chronicle-Values`:** If applicable, how Chronicle Wire can interact with or support `Chronicle-Values` for ultra-low-latency access to off-heap data structures.
-* **`SingleThreadedChecked`:** Explanation of its role and how to ensure thread safety when using Wire and related components.
-* **Trivially Copyable Objects:** Explanation and use cases for this optimisation.
+`Chronicle Bytes` Integration ::
+Detailed explanation of how Chronicle Wire leverages `Bytes` for direct memory operations (on-heap and off-heap).
+Off-Heap Memory ::
+Techniques for serializing directly to/from off-heap `BytesStore` instances to minimize GC impact.
+Examples using `Bytes.allocateElasticDirect()`.
+Zero-Copy Principles ::
+How Chronicle Wire facilitates zero-copy data exchange in conjunction with components like Chronicle Queue and Network.
+Object Reuse ::
+Advanced patterns for object pooling and reuse with `Marshallable.reset()` or similar techniques to reduce allocations in critical loops.
+Flyweights and `Chronicle-Values` ::
+If applicable, how Chronicle Wire can interact with or support `Chronicle-Values` for ultra-low-latency access to off-heap data structures.
+`SingleThreadedChecked` ::
+Explanation of its role and how to ensure thread safety when using Wire and related components.
+Trivially Copyable Objects ::
+Explanation and use cases for this optimisation.
=== Chronicle Wire Usage in OpenHFT Ecosystem Components
*Chronicle Queue (v5.x and relevant versions) ::
-* **Internal Data Format:** Detailed explanation of how Chronicle Wire (typically `BINARY_LIGHT` or `FIELDLESS_BINARY`) is used to serialize each message/document within queue excerpts.
-* **`ExcerptAppender` and `ExcerptTailer`:** How `Wire` instances are obtained and used for writing and reading queue entries.
-* **`MethodWriter` and `MethodReader` Deep Dive:**
-** **Mechanism:** How interfaces are proxied, method calls are intercepted, method names/IDs and arguments are serialized to the queue.
-** **Method ID Generation:** How method identifiers are derived and used.
-** **Argument/Return Type Handling:** Supported types, serialisation of complex `Marshallable` arguments.
-** **Exception Handling:** How exceptions on the writer or reader side are propagated or handled.
-** **Use Cases:** Building high-performance event-driven systems, microservices communication, task distribution.
-** **Code Examples:** Comprehensive examples of defining service interfaces, `Marshallable` DTOs, and implementing writers and readers.
-* **Persistence and Durability:** Role of Wire in ensuring data written to the queue is durable and can be replayed.
-* **Inspection and Debugging:** How tools (like queue dumpers) use Chronicle Wire's flexibility to read binary queue data and display it in human-readable formats (e.g., YAML).
+Internal Data Format ::
+Detailed explanation of how Chronicle Wire (typically `BINARY_LIGHT` or `FIELDLESS_BINARY`) is used to serialize each message/document within queue excerpts.
+`ExcerptAppender` and `ExcerptTailer` ::
+How `Wire` instances are obtained and used for writing and reading queue entries.
+`MethodWriter` and `MethodReader` Deep Dive ::
+* *Mechanism:* How interfaces are proxied, method calls are intercepted, method names/IDs and arguments are serialized to the queue.
+* *Method ID Generation:* How method identifiers are derived and used.
+* *Argument/Return Type Handling:* Supported types, serialisation of complex `Marshallable` arguments.
+* *Exception Handling:* How exceptions on the writer or reader side are propagated or handled.
+* *Use Cases:* Building high-performance event-driven systems, microservices communication, task distribution.
+* *Code Examples:* Comprehensive examples of defining service interfaces, `Marshallable` DTOs, and implementing writers and readers.
+Persistence and Durability ::
+Role of Wire in ensuring data written to the queue is durable and can be replayed.
+Inspection and Debugging ::
+How tools (like queue dumpers) use Chronicle Wire's flexibility to read binary queue data and display it in human-readable formats (e.g., YAML).
Chronicle Map (v3.x and relevant versions) ::
-* **Key/Value Serialisation:** How Chronicle Wire is used for serializing custom Java objects used as keys or values when storing them off-heap.
-* **Integration with `ChronicleMapBuilder`:** Specifying `Marshallable` types for keys/values.
-* **`BytesMarshallable` vs. `Marshallable`:**
-** **Detailed Comparison:** Performance characteristics, storage efficiency, ease of use, schema evolution capabilities for each in the context of Chronicle Map.
-** **Average Message Size:** How this impacts map performance and memory footprint.
-* **Variable-Sized vs. Fixed-Sized Entries:** How Chronicle Wire handles data of varying lengths and its implications for map segment allocation and performance.
-* **Code Examples:** Storing and retrieving complex `Marshallable` objects in a Chronicle Map.
+Key/Value Serialisation ::
+How Chronicle Wire is used for serializing custom Java objects used as keys or values when storing them off-heap.
+Integration with `ChronicleMapBuilder` ::
+Specifying `Marshallable` types for keys/values.
+`BytesMarshallable` vs. `Marshallable` ::
+* *Detailed Comparison:* Performance characteristics, storage efficiency, ease of use, schema evolution capabilities for each in the context of Chronicle Map.
+* *Average Message Size:* How this impacts map performance and memory footprint.
+Variable-Sized vs. Fixed-Sized Entries ::
+How Chronicle Wire handles data of varying lengths and its implications for map segment allocation and performance.
+Code Examples ::
+Storing and retrieving complex `Marshallable` objects in a Chronicle Map.
Chronicle Network (and related TCP/UDP libraries) ::
-* **Data Marshalling for Network Transport:** How Chronicle Wire is used to serialize data sent over TCP/IP or UDP.
-* **`MethodWriter`/`MethodReader` over Network:** Extending the IPC pattern to distributed systems.
-* **Wire Format Negotiation/Selection:** If applicable, how wire formats are chosen or negotiated for network communication.
-* **Low-Latency Network Messaging:** Achieving high throughput and low latency in networked applications using Chronicle Wire.
+Data Marshalling for Network Transport ::
+How Chronicle Wire is used to serialize data sent over TCP/IP or UDP.
+`MethodWriter`/`MethodReader` over Network ::
+Extending the IPC pattern to distributed systems.
+Wire Format Negotiation/Selection ::
+If applicable, how wire formats are chosen or negotiated for network communication.
+Low-Latency Network Messaging ::
+Achieving high throughput and low latency in networked applications using Chronicle Wire.
Chronicle Services ::
-* **Event Serialisation:** How `Marshallable` objects are used to define and serialize domain events in event sourcing architectures.
-* **Event Storage:** Leveraging Chronicle Queue (and thus Wire) for persisting event streams.
-* **State Aggregation and Replay:** How services deserialize events using Wire to reconstruct state or replay business logic.
-* **Conceptual Example:** A detailed walkthrough of a simple event-sourced service (e.g., an "Order Management" service with `OrderCreated`, `OrderUpdated` events defined as `Marshallable` objects), showing event definition, publishing to a queue, and a handler processing these events.
+Event Serialisation ::
+How `Marshallable` objects are used to define and serialize domain events in event sourcing architectures.
+Event Storage ::
+Leveraging Chronicle Queue (and thus Wire) for persisting event streams.
+State Aggregation and Replay ::
+How services deserialize events using Wire to reconstruct state or replay business logic.
+Conceptual Example ::
+A detailed walkthrough of a simple event-sourced service (e.g., an "Order Management" service with `OrderCreated`, `OrderUpdated` events defined as `Marshallable` objects), showing event definition, publishing to a queue, and a handler processing these events.
=== Rich Code Examples and Tutorials
Variety and Scope ::
-* **Basic Serialisation:** Simple POJOs with various `WireType`s (YAML, JSON, Binary).
-* **Complex Objects:** Serialisation of objects with nested `Marshallable` instances, collections (lists, maps) of primitives and `Marshallable` types.
-* **`MethodWriter`/`Reader`:** End-to-end examples for IPC with Chronicle Queue.
-* **Custom Converters and Annotations:** Demonstrating practical use of `@LongConversion`, `@NanoTime`, etc.
-* **Schema Evolution:** Examples showing how to add, remove, or reorder fields in a `Marshallable` class and still read old data or allow new clients to read old data.
-* **Off-Heap Serialisation:** Examples of writing/reading `Marshallable` objects directly to/from off-heap `Bytes`.
-* **Error Handling:** Demonstrating how to handle common serialisation/deserialisation exceptions.
+Basic Serialisation ::
+Simple POJOs with various `WireType`s (YAML, JSON, Binary).
+Complex Objects ::
+Serialisation of objects with nested `Marshallable` instances, collections (lists, maps) of primitives and `Marshallable` types.
+`MethodWriter`/`Reader` ::
+End-to-end examples for IPC with Chronicle Queue.
+Custom Converters and Annotations ::
+Demonstrating practical use of `@LongConversion`, `@NanoTime`, etc.
+Schema Evolution ::
+Examples showing how to add, remove, or reorder fields in a `Marshallable` class and still read old data or allow new clients to read old data.
+Off-Heap Serialisation ::
+Examples of writing/reading `Marshallable` objects directly to/from off-heap `Bytes`.
+Error Handling ::
+Demonstrating how to handle common serialisation/deserialisation exceptions.
Clarity and Readability :: All examples must be well-commented, self-contained where possible, and focused on illustrating specific concepts.
@@ -151,51 +211,58 @@ Completeness :: Provide both the serialisation (writing) and deserialisation (re
Best Practices Integration :: Code examples should subtly (or explicitly) demonstrate recommended patterns and best practices.
-Runnable Format :: Provide examples as complete, runnable Java files or easily copy-pasteable snippets that can be integrated into a user's project. Accompanying `pom.xml` dependencies for OpenHFT components should be noted.
+Runnable Format :: Provide examples as complete, runnable Java files or easily copy-pasteable snippets that can be integrated into a user's project.
+Accompanying `pom.xml` dependencies for OpenHFT components should be noted.
=== Comprehensive Comparison with Other Serialization Libraries
Detailed Comparison Aspects (for each library vs. Chronicle Wire) ::
-* **Data Format & Flexibility:**
-** Supported native formats (binary, text, etc.).
-** Human readability of the serialized form.
-** Cross-language interoperability and support.
-** Ease of switching between different representations (e.g., binary for speed, text for debug).
-* **Performance & Efficiency (Quantitative):**
-** **Serialisation Speed:** Time taken to serialize objects (e.g., ns/op, msgs/sec). Specify object complexity (simple POJO, complex graph).
-** **Deserialisation Speed:** Time taken to deserialize objects.
-** **Serialized Output Size:** Compactness of the serialized form in bytes for typical objects.
-** **CPU Usage:** Relative CPU cycles consumed during serialisation/deserialisation.
-** **GC Impact:** Allocation rates, frequency and duration of GC pauses attributable to serialisation activity.
-_Data should be sourced from existing reputable benchmarks (e.g., Sumit Mundra blog, Micronaut SerDe, InfoQ, Alibaba Cloud) with clear attribution and discussion of test conditions and object models used. Acknowledge that a single definitive benchmark for all aspects across all libraries may not exist._
-* **Schema Definition & Evolution:**
-** **Schema Definition:** How the data structure is defined (e.g., Java class, .proto IDL, JSON Schema).
-** **Code Generation:** Whether code generation is required and its impact on the development workflow.
-** **Backward Compatibility:** Ability of new code to read old data.
-** **Forward Compatibility:** Ability of old code to read new data (or ignore new fields).
-** **Ease of Evolving Schemas:** Process and complexity of adding, removing, renaming, or retyping fields.
-** **Handling of Unknown/Missing Fields:** Default behaviour.
-* **Ease of Use & Developer Experience:**
-** **API Intuitiveness and Verbosity:** How straightforward the API is for common tasks.
-** **Learning Curve:** Time and effort required for a developer to become proficient.
-** **Setup and Configuration:** Complexity of integrating the library into a project (dependencies, initial setup).
-** **Boilerplate Code:** Amount of repetitive code required.
-** **IDE Support:** Quality of IDE integration (e.g., for generated code, debugging).
-* **Documentation & Community Support:**
-** **Quality and Completeness of Official Documentation:** Availability of tutorials, guides, API references.
-** **Community Activity:** Presence on forums (Stack Overflow, mailing lists), GitHub issue responsiveness, availability of third-party articles and tutorials.
-* **Integration & Ecosystem:**
-** **Compatibility with Popular Java Frameworks:** Ease of integration with frameworks like Spring, Guice, etc.
-** **Ecosystem Tools:** Availability of supporting tools for schema management, debugging, etc.
-* **Debugging and Diagnostics:**
-** **Ease of Troubleshooting:** How easy it is to diagnose serialisation errors (e.g., malformed data, version mismatches).
-** **Exception Clarity:** Informativeness of exceptions thrown.
-* **Specific Strengths and Weaknesses:** Summary of unique advantages and disadvantages.
-* **Best Use Cases/Niches:** Typical scenarios where each library excels.
+Data Format & Flexibility ::
+* Supported native formats (binary, text, etc.).
+* Human readability of the serialized form.
+* Cross-language interoperability and support.
+* Ease of switching between different representations (e.g., binary for speed, text for debug).
+Performance & Efficiency (Quantitative) ::
+* *Serialisation Speed:* Time taken to serialize objects (e.g., ns/op, msgs/sec).
+Specify object complexity (simple POJO, complex graph).
+* *Deserialisation Speed:* Time taken to deserialize objects.
+* *Serialized Output Size:* Compactness of the serialized form in bytes for typical objects.
+* *CPU Usage:* Relative CPU cycles consumed during serialisation/deserialisation.
+* *GC Impact:* Allocation rates, frequency and duration of GC pauses attributable to serialisation activity.
+_Data should be sourced from existing reputable benchmarks (e.g., Sumit Mundra blog, Micronaut SerDe, InfoQ, Alibaba Cloud) with clear attribution and discussion of test conditions and object models used.
+Acknowledge that a single definitive benchmark for all aspects across all libraries may not exist._
+Schema Definition & Evolution ::
+* *Schema Definition:* How the data structure is defined (e.g., Java class, .proto IDL, JSON Schema).
+* *Code Generation:* Whether code generation is required and its impact on the development workflow.
+* *Backward Compatibility:* Ability of new code to read old data.
+* *Forward Compatibility:* Ability of old code to read new data (or ignore new fields).
+* *Ease of Evolving Schemas:* Process and complexity of adding, removing, renaming, or retyping fields.
+* *Handling of Unknown/Missing Fields:* Default behaviour.
+Ease of Use & Developer Experience ::
+* *API Intuitiveness and Verbosity:* How straightforward the API is for common tasks.
+* *Learning Curve:* Time and effort required for a developer to become proficient.
+* *Setup and Configuration:* Complexity of integrating the library into a project (dependencies, initial setup).
+* *Boilerplate Code:* Amount of repetitive code required.
+* *IDE Support:* Quality of IDE integration (e.g., for generated code, debugging).
+Documentation & Community Support ::
+* *Quality and Completeness of Official Documentation:* Availability of tutorials, guides, API references.
+* *Community Activity:* Presence on forums (Stack Overflow, mailing lists), GitHub issue responsiveness, availability of third-party articles and tutorials.
+Integration & Ecosystem ::
+* *Compatibility with Popular Java Frameworks:* Ease of integration with frameworks like Spring, Guice, etc.
+* *Ecosystem Tools:* Availability of supporting tools for schema management, debugging, etc.
+Debugging and Diagnostics ::
+* *Ease of Troubleshooting:* How easy it is to diagnose serialisation errors (e.g., malformed data, version mismatches).
+* *Exception Clarity:* Informativeness of exceptions thrown.
+Specific Strengths and Weaknesses ::
+Summary of unique advantages and disadvantages.
+Best Use Cases/Niches ::
+Typical scenarios where each library excels.
Presentation Format ::
-* **Structured Tables:** Use detailed comparison tables for a clear, side-by-side view of features, performance metrics, and qualitative aspects.
-* **Narrative Summaries:** Accompany tables with narrative explanations highlighting key differences and trade-offs.
+Structured Tables ::
+Use detailed comparison tables for a clear, side-by-side view of features, performance metrics, and qualitative aspects.
+Narrative Summaries ::
+Accompany tables with narrative explanations highlighting key differences and trade-offs.
== Non-Functional Requirements
@@ -204,7 +271,8 @@ Accuracy and Currency ::
* Documentation should be versioned alongside the library releases, with clear indications of which library version the documentation pertains to.
Clarity and Precision ::
-* Language must be precise, unambiguous, and grammatically correct. Avoid colloquialisms that may not translate well.
+* Language must be precise, unambiguous, and grammatically correct.
+Avoid colloquialisms that may not translate well.
* Explain complex concepts from first principles before building upon them.
* Utilize diagrams, flowcharts, and sequence diagrams where they aid in understanding complex interactions or architectures.
@@ -231,7 +299,8 @@ Primary AsciiDoc Document(s) ::
* Potentially separate AsciiDoc files for major sections or chapters, included by the main file, to improve modularity and maintainability.
Runnable Code Examples ::
-* A collection of self-contained Java source files for all significant code examples, organized logically. These might be included directly in the AsciiDoc or linked from a separate examples directory within the project.
+* A collection of self-contained Java source files for all significant code examples, organized logically.
+These might be included directly in the AsciiDoc or linked from a separate examples directory within the project.
* Accompanying `pom.xml` snippets or a sample project demonstrating dependencies.
Diagrams and Illustrations ::
@@ -245,27 +314,46 @@ Comparison Data ::
The documentation should cater to a diverse technical audience, including:
Java Developers New to OpenHFT ::
-* **Goal:** Understand Chronicle Wire's purpose, basic usage for serialisation, and how it compares to libraries they already know (like Jackson or Java Serializable).
+Goal ::
+Understand Chronicle Wire's purpose, basic usage for serialisation, and how it compares to libraries they already know (like Jackson or Java Serializable).
Experienced OpenHFT Users (Chronicle Queue/Map Developers) ::
-* **Goal:** Gain deeper insights into the underlying serialisation mechanisms (Wire) they are implicitly using, learn advanced customisation techniques, and optimise Wire usage for performance.
+Goal ::
+Gain deeper insights into the underlying serialisation mechanisms (Wire) they are implicitly using, learn advanced customisation techniques, and optimise Wire usage for performance.
System Architects and Technical Leads ::
-* **Goal:** Evaluate Chronicle Wire for new projects, understand its performance characteristics, schema evolution capabilities, and suitability for low-latency, high-throughput distributed systems.
+Goal ::
+Evaluate Chronicle Wire for new projects, understand its performance characteristics, schema evolution capabilities, and suitability for low-latency, high-throughput distributed systems.
Performance Engineers ::
-* **Goal:** Understand low-level details of Wire's performance features, GC implications, and how to use it for extreme optimisation.
+Goal ::
+Understand low-level details of Wire's performance features, GC implications, and how to use it for extreme optimisation.
Developers Evaluating Serialisation Libraries ::
-* **Goal:** Obtain a balanced, technically sound comparison to make an informed choice for their specific project needs.
+Goal ::
+Obtain a balanced, technically sound comparison to make an informed choice for their specific project needs.
== Assumptions
-Reader's Background :: The documentation will assume readers have a solid understanding of Java programming concepts. Familiarity with general serialisation concepts is helpful but not strictly required for introductory sections.
+Reader's Background :: The documentation will assume readers have a solid understanding of Java programming concepts.
+Familiarity with general serialisation concepts is helpful but not strictly required for introductory sections.
Access to Resources :: Development of this documentation will have access to the Chronicle Wire source code, existing (even if sparse) documentation, community forums, and potentially core OpenHFT developers for clarification.
-Benchmark Data :: Performance comparisons will rely on publicly available benchmark results, with appropriate attribution and caveats. No new primary benchmarking activities are within the scope of this documentation project itself.
+Benchmark Data :: Performance comparisons will rely on publicly available benchmark results, with appropriate attribution and caveats.
+No new primary benchmarking activities are within the scope of this documentation project itself.
Source Document :: The initial technical review document that prompted this requirements specification serves as a foundational research base.
+== Related documentation
+
+The following companion documents provide deeper detail for specific areas:
+
+* link:index.adoc[Chronicle Wire Documentation Index]
+* link:wire-architecture.adoc[Chronicle Wire: Architectural Overview]
+* link:functional-requirements.adoc[Chronicle Wire Functional Requirements]
+* link:data-requirements.adoc[Chronicle Wire Data Requirements]
+* link:operational-requirements.adoc[Chronicle Wire Operational Requirements]
+* link:security-review.adoc[Chronicle Wire Security Review]
+* link:ops-scenarios.adoc[Chronicle Wire Operational Scenarios]
+* link:runbooks/wire-runtime-health.adoc[Chronicle Wire Runtime Health Runbook]
diff --git a/src/main/docs/runbooks/wire-runtime-health.adoc b/src/main/docs/runbooks/wire-runtime-health.adoc
index 6888a7af32..f97fd72096 100644
--- a/src/main/docs/runbooks/wire-runtime-health.adoc
+++ b/src/main/docs/runbooks/wire-runtime-health.adoc
@@ -1,5 +1,4 @@
= Chronicle Wire Runtime Health Runbook
-Chronicle Software
:toc:
:sectnums:
:lang: en-GB
@@ -13,32 +12,34 @@ build failures, leaked `DocumentContext` instances, and schema drift.
[[build-recovery]]
== Build Recovery (`mvn -q clean verify`)
-1. Confirm the failing JVM version. Run `java -version` and compare it with the CI lane.
-2. Execute `mvn -q -e clean verify` locally. Capture the first stack trace.
-3. If the failure stems from missing documentation, run `scripts/check-doc-includes.py`
- and update the relevant `.adoc` files (see `functional-requirements.adoc`).
-4. For test regressions, bisect with `git bisect run mvn -q -DskipTests=false test`
- to isolate the offending commit.
-5. After applying the fix, rerun `mvn -q clean verify` and attach the log to the PR.
+. Confirm the failing JVM version.
+Run `java -version` and compare it with the CI lane.
+. Execute `mvn -q -e clean verify` locally.
+Capture the first stack trace.
+. If the failure stems from missing documentation, run `scripts/check-doc-includes.py`
+and update the relevant `.adoc` files (see `functional-requirements.adoc`).
+. For test regressions, bisect with `git bisect run mvn -q -DskipTests=false test`
+to isolate the offending commit.
+. After applying the fix, rerun `mvn -q clean verify` and attach the log to the PR.
[[document-context-leak]]
== DocumentContext Leak Response
-1. Capture a thread dump: `jcmd Thread.print | tee /tmp/wire-thread-dump.txt`.
-2. Search for `DocumentContext.close` or `AbstractMethodReader.readOne` stack traces.
-3. If the writer side is stuck, enable debug logging for `net.openhft.chronicle.wire` temporarily
- and reproduce the issue in a lower environment.
-4. Inspect user code for missing try-with-resources blocks around `DocumentContext`.
-5. Add coverage or assertions (`DocumentContextLifecycleTest`) and rerun the full build.
+. Capture a thread dump: `jcmd Thread.print | tee /tmp/wire-thread-dump.txt`.
+. Search for `DocumentContext.close` or `AbstractMethodReader.readOne` stack traces.
+. If the writer side is stuck, enable debug logging for `net.openhft.chronicle.wire` temporarily and reproduce the issue in a lower environment.
+. Inspect user code for missing try-with-resources blocks around `DocumentContext`.
+. Add coverage or assertions (`DocumentContextLifecycleTest`) and rerun the full build.
[[schema-drift]]
== Schema Drift Investigation
-1. Compare producer and consumer SHAs. If they differ, check whether new fields were added without defaults.
-2. Dump a problematic message with `WireDumper` (see `wire-cookbook.adoc`) and inspect field names.
-3. Validate converters by running `mvn -q -Dtest=LongConversionTest test`.
-4. Update `data-requirements.adoc` and `wire-schema-evolution.adoc` with the new field rules.
-5. Add regression tests before redeploying.
+. Compare producer and consumer SHAs.
+If they differ, check whether new fields were added without defaults.
+. Dump a problematic message with `WireDumper` (see `wire-cookbook.adoc`) and inspect field names.
+. Validate converters by running `mvn -q -Dtest=LongConversionTest test`.
+. Update `data-requirements.adoc` and `wire-schema-evolution.adoc` with the new field rules.
+. Add regression tests before redeploying.
== Verification
diff --git a/src/main/docs/security-review.adoc b/src/main/docs/security-review.adoc
index 7fdf3bb806..2134a1c35c 100644
--- a/src/main/docs/security-review.adoc
+++ b/src/main/docs/security-review.adoc
@@ -1,10 +1,28 @@
= Chronicle Wire: Security Review & Known Trade-offs
:toc:
:sectnums:
+:lang: en-GB
+:source-highlighter: rouge
+
+This document is aligned with the shared security and architectural standards in `Chronicle-Quality-Rules/src/main/docs/security-review.adoc` and `Chronicle-Quality-Rules/src/main/docs/architectural-standards.adoc`.
+
+== Trust Zone and Responsibilities
+
+Chronicle Wire can sit at either the *Edge (Zone A)* or in the *Core (Zone B)* of a system, as defined in `Chronicle-Quality-Rules/src/main/docs/architectural-standards.adoc`:
+
+* At the Edge, Wire parses untrusted input (for example YAML/JSON configuration, network payloads or files) and must be treated as handling potentially hostile data.
+* In the Core, Wire serialises and deserialises objects that have already passed authentication and higher-level validation.
+
+This security review focuses on:
+
+* the risks that arise when Wire is used on untrusted data paths;
+* the controls and coding patterns that reduce those risks (for example bounds checking, maximum message sizes, deny-lists and fuzzing);
+* the trade-offs inherent in keeping hot paths fast for both Edge and Core usage.
== Introduction
-This document provides an overview of known security considerations and deliberate trade-offs made within the Chronicle Wire library. Chronicle libraries prioritize very low-latency and high-throughput performance, which sometimes necessitates design choices that diverge from typical enterprise software where safety and security checks might take precedence over raw speed.
+This document provides an overview of known security considerations and deliberate trade-offs made within the Chronicle Wire library.
+Chronicle libraries prioritize very low-latency and high-throughput performance, which sometimes necessitates design choices that diverge from typical enterprise software where safety and security checks might take precedence over raw speed.
The purpose of this document is to:
@@ -129,7 +147,8 @@ Why ::
Useful for debugging and tracing configuration issues.
Risks ::
-* `AbstractMarshallableCfg.unexpectedField` logs ignored values via `valueIn.objectBestEffort()`. Malicious inputs could appear in logs.
+* `AbstractMarshallableCfg.unexpectedField` logs ignored values via `valueIn.objectBestEffort()`.
+Malicious inputs could appear in logs.
* `VanillaMethodReader.logMessage0` prints message payloads when `DEBUG_ENABLED` is true.
* `YamlLogging` flags may expose sensitive data if enabled in production.
* Unchecked input that is then logged compounds the issue.
diff --git a/src/main/docs/system-architecture.adoc b/src/main/docs/system-architecture.adoc
index 88d22b0e4d..7d33faf678 100644
--- a/src/main/docs/system-architecture.adoc
+++ b/src/main/docs/system-architecture.adoc
@@ -1,5 +1,4 @@
= Chronicle Wire System Architecture
-Chronicle Software
:toc:
:sectnums:
:lang: en-GB
@@ -10,11 +9,15 @@ Chronicle Software
This document summarises how Chronicle Wire's modules collaborate with the wider OpenHFT stack.
Use it as an orientation map before diving into the detailed views in `wire-architecture.adoc`,
`wire-schema-evolution.adoc`, and the component notes.
+For the primary, combined architecture view, refer to `architecture-overview.adoc`, which supersedes
+earlier summaries in this file.
+Update the canonical view first and mirror only condensed highlights here to keep descriptions aligned.
== Context
Chronicle Wire provides the serialisation substrate for components such as Chronicle Queue,
-Chronicle Services, and higher-level trading stacks. It sits between business code and
+Chronicle Services, and higher-level trading stacks.
+It sits between business code and
`chronicle-bytes`, exposing a format-neutral API that maps directly to heap or off-heap buffers.
== Component Map
@@ -25,35 +28,40 @@ Application Services -> Wire API -> WireType Implementations -> Chronicle Bytes
|-> Converters / Marshallers -> Domain Objects
----
-* **Application Services** use Wire to read and write domain objects without worrying about the
+* *Application Services* use Wire to read and write domain objects without worrying about the
transport format.
-* **Wire API** includes `Wire`, `WireIn`, `WireOut`, `DocumentContext`, `ValueIn`, and `ValueOut`.
-* **WireType Implementations** (Text, YAML, JSON, Binary) convert API calls into bytes.
-* **Chronicle Bytes** supplies direct-memory primitives and pooling.
-* **Storage / Network** refers to Chronicle Queue, replication, or user-defined transports.
+* *Wire API* includes `Wire`, `WireIn`, `WireOut`, `DocumentContext`, `ValueIn`, and `ValueOut`.
+* *WireType Implementations* (Text, YAML, JSON, Binary) convert API calls into bytes.
+* *Chronicle Bytes* supplies direct-memory primitives and pooling.
+* *Storage / Network* refers to Chronicle Queue, replication, or user-defined transports.
== Data Flow
-1. The caller requests a document via `Wire.acquireWritingDocument`.
-2. Fields are written using fluent `ValueOut` calls (or generated via `MethodWriter`).
-3. The document is published, transferring ownership of the buffer slice.
-4. Consumers wrap the slice in a `Wire` via the appropriate `WireType` and replay the fields.
-5. Optional converters (`LongConverter`, `Base32LongConverter`, etc.) translate textual encodings
+. The caller requests a document via `Wire.acquireWritingDocument`.
+. Fields are written using fluent `ValueOut` calls (or generated via `MethodWriter`).
+. The document is published, transferring ownership of the buffer slice.
+. Consumers wrap the slice in a `Wire` via the appropriate `WireType` and replay the fields.
+. Optional converters (`LongConverter`, `Base32LongConverter`, etc.) translate textual encodings
into numeric forms without allocations.
== Cross-Cutting Concerns
-* **Threading:** `DocumentContext` enforces single-writer, single-reader semantics per instance.
+Threading ::
+`DocumentContext` enforces single-writer, single-reader semantics per instance.
Shared buffers are protected via Chronicle Bytes' CAS-based locking and sequencing.
-* **Performance:** Hot loops avoid reflection; method writers generate bytecode-backed proxies.
-* **Resilience:** Error handling is centralised in `wire-error-handling.adoc`; operational
+Performance ::
+Hot loops avoid reflection; method writers generate bytecode-backed proxies.
+Resilience ::
+Error handling is centralised in `wire-error-handling.adoc`; operational
responses live in `ops-scenarios.adoc`.
-* **Documentation Sync:** Any change to the architecture must update this file as well as the
+Documentation Sync ::
+Any change to the architecture must update this file as well as the
detailed component documentation.
== Future Work
-Chronicle Wire continues to adopt decisions recorded in `decision-log.adoc`. Upcoming investigations
+Chronicle Wire continues to adopt decisions recorded in `decision-log.adoc`.
+Upcoming investigations
include:
* Expanding support for pluggable `ClassLookup` strategies for sandboxed environments.
diff --git a/docs/systemProperties.adoc b/src/main/docs/system-properties.adoc
similarity index 99%
rename from docs/systemProperties.adoc
rename to src/main/docs/system-properties.adoc
index 16ebb7f995..799789582a 100644
--- a/docs/systemProperties.adoc
+++ b/src/main/docs/system-properties.adoc
@@ -1,7 +1,8 @@
= Chronicle System Properties Guide
-:toc: preamble
-:icons: font
+:toc:
:sectnums:
+:icons: font
+:lang: en-GB
:source-highlighter: rouge
This document lists Java system properties that influence Chronicle libraries such as Chronicle Wire and Chronicle Core.
diff --git a/src/main/docs/testing-strategy.adoc b/src/main/docs/testing-strategy.adoc
new file mode 100644
index 0000000000..ff9fdeb1db
--- /dev/null
+++ b/src/main/docs/testing-strategy.adoc
@@ -0,0 +1,99 @@
+= Chronicle Wire Testing Strategy
+:toc:
+:sectnums:
+:lang: en-GB
+:toclevels: 2
+:doctype: book
+:source-highlighter: rouge
+
+This document outlines the testing approach for Chronicle Wire and links tests to the requirements catalogues defined in `project-requirements.adoc` and `functional-requirements.adoc`.
+It supports the ISO 9001 design verification checklist and helps reviewers assess coverage for key behaviours.
+
+== Test Layers
+
+Chronicle Wire uses several complementary test layers:
+
+* unit tests in `src/test/java/net/openhft/chronicle/wire` for core API contracts, `WireType` behaviour, `DocumentContext` lifecycles and method writer or reader patterns;
+* integration style tests that exercise multiple WireTypes over shared `Bytes`
+instances and interactions with other Chronicle modules where appropriate;
+* micro benchmarks and JLBH based harnesses in the `microbenchmarks` and
+`marshallingperf` modules for performance related requirements;
+* exploratory and regression tests that capture previously reported bugs and edge cases, especially around schema evolution, malformed input and dynamic typing.
+
+Where practical, test classes reference requirement identifiers from
+`functional-requirements.adoc` (for example `FN-001`, `FN-002`) in comments or Javadoc to support traceability.
+
+== Unit Testing Approach
+
+Unit tests focus on:
+
+* functional behaviour of `Wire`, `WireIn` and `WireOut` across supported
+`WireType` values, ensuring that `Marshallable` and
+`SelfDescribingMarshallable` round trip correctly;
+* correct use of `DocumentContext` for framing messages, including nested documents and failure or rollback scenarios;
+* dynamic typing and annotation handling, such as `@FieldNumber`,
+`@LongConversion` and type alias resolution;
+* converters and low level helpers in `net.openhft.chronicle.wire` that are used by higher level modules (for example long and time converters, class lookup strategies).
+
+Tests are written to avoid non deterministic timing assumptions and to keep allocations low, reflecting the performance sensitive nature of the library.
+
+== Integration and Compatibility Tests
+
+Integration style tests cover:
+
+* combined usage of Wire with Chronicle Bytes where realistic `Bytes` and
+`BytesStore` implementations are involved (on heap, native and mapped);
+* scenarios where messages are written using one `WireType` and read using another, to exercise the format independence guarantees described in the architecture and requirements documentation;
+* behaviour across JVM versions and platforms as part of the multi JDK verification policy captured in `operational-requirements.adoc` and the decision log.
+
+Where possible, integration tests reuse production configuration defaults so that changes in settings (for example system properties and logging flags) are exercised in continuous integration.
+
+== Performance and Benchmarking Strategy
+
+Performance related expectations are verified using:
+
+* JLBH style harnesses and JMH micro benchmarks under the `microbenchmarks`
+directory, targeting serialisation or deserialisation latency for typical DTOs, method writer or reader throughput and converter overhead;
+* scenario benchmarks in `marshallingperf` and the `demo` module that simulate realistic usage patterns, such as queue based message flows or configuration loading.
+
+Benchmark configurations, such as JVM flags, thread pinning and payload sizes, are documented alongside the benchmark source where relevant so that results are reproducible and comparable across versions.
+
+While not all benchmarks run on every CI executor, they are treated as gating signals before major releases or significant architectural changes that could affect latency or allocation characteristics.
+
+== Code Review and Regression Handling
+
+Design verification requires evidence that:
+
+* new features and bug fixes come with corresponding tests or benchmarks;
+* regressions are captured by durable tests where feasible;
+* test names or comments reference the relevant requirement identifiers or issue references.
+
+During code review:
+
+* reviewers confirm that changes which touch method writers or readers,
+`WireType` behaviour, Unsafe usage or schema evolution paths include targeted tests and, where appropriate, updated documentation;
+* reviewers consider whether additional negative tests (for example malformed inputs, incompatible schema changes, concurrent access) are needed to cover the intended behaviour.
+
+== Running the Test Suite
+
+From the repository root, run:
+
+[source,bash]
+----
+mvn -q clean verify
+----
+
+This command builds all modules, executes unit and integration tests and runs static analysis tools configured in the Maven build.
+Module specific test runs can be scoped using Maven's `-pl` flag when iterating, but the full
+`verify` goal should be executed before releases or pull requests.
+
+== Known Skipped Tests (latest runs)
+
+Recent `mvn -q clean verify` runs on JDK 8 and JDK 21 (`mvn-java8.log` and `mvn-java21.log` in the repository root) passed but reported several intentional skips:
+
+* `BinaryWirePerfTest` (6 tests) - performance heavy, kept skipped to avoid long CI runs; re-run on dedicated hardware when assessing latency.
+* `WireCollectionTest` (7 tests) - currently skipped; review and re-enable to regain coverage for collection handling.
+* `JSON222Test` (224 of 448 tests skipped) - specification suite remains partially disabled; investigate feasibility of widening coverage.
+* `BinaryWire2Test` (10 of 78 tests) and `WireTests` (5 of 60 tests) - small subsets skipped; confirm whether platform or flakiness constraints remain.
+
+The combined skip totals were 292 (JDK 8) and 296 (JDK 21). Each skipped group should carry an explicit rationale in the test class and a TODO to re-enable where possible.
diff --git a/src/main/docs/wire-annotations.adoc b/src/main/docs/wire-annotations.adoc
index 41d6a6c340..b4a83fa472 100644
--- a/src/main/docs/wire-annotations.adoc
+++ b/src/main/docs/wire-annotations.adoc
@@ -1,15 +1,18 @@
= Chronicle Wire Annotations: A Comprehensive Guide
:toc:
:sectnums:
+:lang: en-GB
:source-highlighter: rouge
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.
== Introduction
-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.
+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:
+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).
@@ -17,15 +20,19 @@ This document serves as a comprehensive guide to the standard annotations provid
* 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.
+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.
== Core Annotation Categories
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 `transient` keyword or the inherent behaviour of `Marshallable`, some annotations might subtly influence what or how data is marshalled.
+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 `transient` keyword or the inherent behaviour of `Marshallable`, some annotations might subtly influence what or how data is marshalled.
This guide will explore annotations primarily from the first two categories.
@@ -36,7 +43,8 @@ These annotations are crucial for controlling the on-wire representation of your
=== `@LongConversion` and Derivative Converters
Purpose ::
-The `@LongConversion` annotation is a powerful meta-annotation used to specify that a `long` field in Java should be converted to and from a different representation (typically a String) when serialised to text-based wire formats, while remaining a `long` in binary formats. This is extremely useful for compactly storing short textual identifiers or codes within an 8-byte long.
+The `@LongConversion` annotation is a powerful meta-annotation used to specify that a `long` field in Java should be converted to and from a different representation (typically a String) when serialised to text-based wire formats, while remaining a `long` in binary formats.
+This is extremely useful for compactly storing short textual identifiers or codes within an 8-byte long.
Target :: Field (of type `long`)
@@ -44,8 +52,12 @@ Attributes ::
`value` (Class extends LongConverter>):: Specifies the `LongConverter` implementation 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 a `long`.
-* **Binary Formats:** The field is serialised directly as a standard `long` (typically 8 bytes). The conversion logic is not applied.
+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 a `long`.
+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 `long` for efficient storage and processing, but need to be human-readable in configurations or logs.
@@ -57,9 +69,12 @@ While `@LongConversion` is the base, Chronicle Wire provides several convenient
Annotations :: `@Base32`, `@Base64`, `@Base85` (these are meta-annotated with `@LongConversion` pointing to respective `BaseNLongConverter` implementations).
Purpose :: To store short strings (composed of characters from the respective BaseN alphabet) within a `int`, up to 5 characters, or `long` upt o 10 characters.
-* `@Base32`: Uses a 32-character alphabet. Can store up to 12 characters in a `long`.
-* `@Base64`: Uses a 64-character alphabet (A-Z, a-z, 0-9, +, /). Can store up to 10 characters in a `long`.
-* `@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.
+* `@Base32`: Uses a 32-character alphabet.
+Can store up to 12 characters in a `long`.
+* `@Base64`: Uses a 64-character alphabet (A-Z, a-z, 0-9, +, /).
+Can store up to 10 characters in a `long`.
+* `@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.
.Example (`@Base64`)
[source,java]
@@ -97,20 +112,23 @@ public class StockInfo extends SelfDescribingMarshallable {
Status :: Stable
-Purpose :: Provides a concise way to convert short strings (up to ten
-characters) to and from a `int` up to 5 characters, or `long` up to 10 characters. using the `ShortTextLongConverter`.
+Purpose :: Provides a concise way to convert short strings (up to ten characters) to and from a `int` up to 5 characters, or `long` up to 10 characters.
+using the `ShortTextLongConverter`.
It is a specialised form of `@LongConversion` and 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".
+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.
+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
+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)`.
.Example (`@ShortText`)
@@ -133,8 +151,10 @@ Purpose :: To format `long` fields representing timestamps (nanoseconds or milli
Target :: Field (of type `long`)
Behaviour ::
-* **Text Formats (YAML, JSON):** Converts the `long` timestamp to an ISO 8601 string (e.g., `2023-10-27T10:15:30.123456789Z`).
-* **Binary Formats:** Stores the `long` value directly.
+Text Formats (YAML, JSON) ::
+Converts the `long` timestamp to an ISO 8601 string (e.g., `2023-10-27T10:15:30.123456789Z`).
+Binary Formats ::
+Stores the `long` value directly.
Use Case :: Storing precise timestamps efficiently while allowing easy human inspection in logs or configuration files.
@@ -173,7 +193,8 @@ These annotations provide additional information about fields or types, primaril
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.
+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
@@ -181,12 +202,16 @@ 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 `@FieldNumber` remains the same.
-* **Text Formats:** Generally has no direct effect on the output (field names are used).
+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 `@FieldNumber` remains 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 `Marshallable` classes when using number-based binary field identification.
Example ::
+
[source,java]
----
import net.openhft.chronicle.wire.FieldNumber;
@@ -215,12 +240,15 @@ 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.
+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 ::
+
[source,java]
----
import net.openhft.chronicle.wire.Comment;
@@ -248,12 +276,19 @@ AppConfig {
== Best Practices for Using Annotations
-* **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`).
-* **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 `Marshallable` classes for predictable behaviour.
-* **Test Thoroughly:** When using annotations that affect data representation or schema (like `@LongConversion` or `@FieldNumber`), 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 `SelfDescribingMarshallable` is often sufficient for many use cases.
+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`).
+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 `Marshallable` classes for predictable behaviour.
+Test Thoroughly ::
+When using annotations that affect data representation or schema (like `@LongConversion` or `@FieldNumber`), 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 `SelfDescribingMarshallable` is 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.
diff --git a/src/main/docs/wire-architecture.adoc b/src/main/docs/wire-architecture.adoc
index d2e65be5f2..ffcb700e59 100644
--- a/src/main/docs/wire-architecture.adoc
+++ b/src/main/docs/wire-architecture.adoc
@@ -1,37 +1,56 @@
= Chronicle Wire: Architectural Overview
:toc:
:sectnums:
+:lang: en-GB
:source-highlighter: rouge
Purpose: To provide a comprehensive understanding of the internal architecture of the Chronicle Wire library, its components, and design principles.
+For the primary, up-to-date architecture entry point that combines system and internal views, see
+`architecture-overview.adoc`.
+Keep any supplementary detail in this file consistent with the canonical view to avoid drift.
== Introduction
-Chronicle Wire is a high-performance, low-latency serialisation and deserialisation library, forming a foundational part of the OpenHFT (Open High-Frequency Trading) ecosystem. Its architecture is meticulously designed to support demanding applications that require minimal garbage collection, high throughput, and flexible data representation. This document outlines the key architectural components, design principles, and interactions within Chronicle Wire.
+Chronicle Wire is a high-performance, low-latency serialisation and deserialisation library, forming a foundational part of the OpenHFT (Open High-Frequency Trading) ecosystem.
+Its architecture is meticulously designed to support demanding applications that require minimal garbage collection, high throughput, and flexible data representation.
+This document outlines the key architectural components, design principles, and interactions within Chronicle Wire.
The primary architectural goals of Chronicle Wire are:
-* **Performance:** Achieve extremely low latency and high throughput for data serialisation and deserialisation, minimizing CPU overhead and GC pauses.
-* **Flexibility:** Support multiple data formats (e.g., YAML, JSON, Binary) through a unified API, allowing developers to switch formats without code changes.
-* **Extensibility:** Provide mechanisms for custom data type handling and new wire format implementations.
-* **Schema Evolution:** Offer robust support for evolving data schemas over time without breaking compatibility.
+Performance ::
+Achieve extremely low latency and high throughput for data serialisation and deserialisation, minimizing CPU overhead and GC pauses.
+Flexibility ::
+Support multiple data formats (e.g., YAML, JSON, Binary) through a unified API, allowing developers to switch formats without code changes.
+Extensibility ::
+Provide mechanisms for custom data type handling and new wire format implementations.
+Schema Evolution ::
+Offer robust support for evolving data schemas over time without breaking compatibility.
== Core Design Principles
The architecture of Chronicle Wire is guided by several core design principles:
-* **Zero/Minimal Garbage Creation:** Extensive use of off-heap memory (`Chronicle Bytes`) and object pooling/reuse techniques to avoid generating garbage during critical serialisation/deserialisation paths.
-* **Direct Memory Access:** Leverage `sun.misc.Unsafe` (where available and appropriate) for direct memory operations, bypassing Java heap overhead for raw data handling.
-* **Format Agnosticism:** Abstract the serialisation logic from the specific data format. The application interacts with a common `Wire` API, while the underlying implementation handles the format-specific encoding/decoding.
-* **Self-Describing Data (Optional):** Support for both self-describing formats (which include field names or identifiers, aiding schema evolution and debugging) and more compact, non-self-describing formats (for maximum performance where schemas are implicitly shared).
-* **Streaming API:** Provide a streaming approach to reading and writing data, allowing for efficient processing of large data structures or sequences of messages.
+Zero/Minimal Garbage Creation ::
+Extensive use of off-heap memory (`Chronicle Bytes`) and object pooling/reuse techniques to avoid generating garbage during critical serialisation/deserialisation paths.
+Direct Memory Access ::
+Leverage `sun.misc.Unsafe` (where available and appropriate) for direct memory operations, bypassing Java heap overhead for raw data handling.
+Format Agnosticism ::
+Abstract the serialisation logic from the specific data format.
+The application interacts with a common `Wire` API, while the underlying implementation handles the format-specific encoding/decoding.
+Self-Describing Data (Optional) ::
+Support for both self-describing formats (which include field names or identifiers, aiding schema evolution and debugging) and more compact, non-self-describing formats (for maximum performance where schemas are implicitly shared).
+Streaming API ::
+Provide a streaming approach to reading and writing data, allowing for efficient processing of large data structures or sequences of messages.
== Architectural Layers and Components
Chronicle Wire's architecture can be conceptualized in several layers, with well-defined components interacting across these layers.
-ifdef::env-github[[source,mermaid]]
-ifndef::env-github[[mermaid]]
+ifdef::env-github[[source,mermaid]
+]
+ifndef::env-github[[mermaid]
+]
+
----
graph TD
A[Application Code] -->|Interacts via| B[Chronicle Wire API Layer]
@@ -62,11 +81,13 @@ Chronicle Wire API Layer ::
* Key components:
** `Marshallable`: An interface (or its base class `SelfDescribingMarshallable`) that domain objects implement to enable automatic serialisation of their fields.
** `BytesMarshallable`: A lower-level interface for objects that manage their own serialisation directly to/from `Bytes`.
-** `Wire`: The central interface for reading and writing structured data. It provides methods to obtain `ValueIn` (for reading) and `ValueOut` (for writing).
+** `Wire`: The central interface for reading and writing structured data.
+It provides methods to obtain `ValueIn` (for reading) and `ValueOut` (for writing).
** `WireIn` / `WireOut`: Interfaces defining methods for reading/writing various data types and structures (e.g., `read("fieldName")`, `write("fieldName")`).
** `ValueIn` / `ValueOut`: Fluent APIs for reading/writing individual values or nested structures.
** `DocumentContext`: Manages the boundaries of a "document" or "message" on the wire, crucial for streaming multiple messages.
-** `WireType`: An enum that specifies the desired serialisation format (e.g., `YAML`, `BINARY`, `JSON`). This determines which concrete `Wire` implementation is used.
+** `WireType`: An enum that specifies the desired serialisation format (e.g., `YAML`, `BINARY`, `JSON`).
+This determines which concrete `Wire` implementation is used.
Wire Format Implementation Layer ::
* This layer contains concrete implementations of the `Wire` interface for each supported data format.
@@ -80,8 +101,10 @@ Chronicle Bytes Layer ::
* Chronicle Wire relies heavily on `chronicle-bytes`, another OpenHFT library, for all low-level byte manipulation.
* Key components:
** `BytesStore`: An abstraction for a region of memory (can be on-heap byte array, off-heap direct memory, or memory-mapped file).
-** `Bytes`: The primary interface for reading and writing raw bytes to a `BytesStore`. It provides methods for reading/writing primitives, strings, and byte arrays directly.
-* This layer enables Chronicle Wire to operate on off-heap memory, significantly reducing GC pressure. All `Wire` implementations operate on a `Bytes` instance.
+** `Bytes`: The primary interface for reading and writing raw bytes to a `BytesStore`.
+It provides methods for reading/writing primitives, strings, and byte arrays directly.
+* This layer enables Chronicle Wire to operate on off-heap memory, significantly reducing GC pressure.
+All `Wire` implementations operate on a `Bytes` instance.
Underlying I/O or Storage Layer ::
* This layer is typically provided by the application or other Chronicle libraries (like Chronicle Queue or Chronicle Network).
@@ -94,14 +117,21 @@ Underlying I/O or Storage Layer ::
=== `Bytes` and `BytesStore`
-The `Bytes` abstraction is fundamental. It provides a mutable, resizable view over a `BytesStore`. `Wire` implementations use `Bytes` to read from and write to the underlying byte sequence without needing to know if it's on-heap, off-heap, or file-backed. This decoupling is crucial for performance and flexibility.
+The `Bytes` abstraction is fundamental.
+It provides a mutable, resizable view over a `BytesStore`.
+`Wire` implementations use `Bytes` to read from and write to the underlying byte sequence without needing to know if it's on-heap, off-heap, or file-backed.
+This decoupling is crucial for performance and flexibility.
=== `Wire` and `WireType`
-The `Wire` interface abstracts the process of serializing and deserializing structured data. An application obtains a `Wire` instance, typically specifying a `WireType` and providing a `Bytes` buffer.
+The `Wire` interface abstracts the process of serializing and deserializing structured data.
+An application obtains a `Wire` instance, typically specifying a `WireType` and providing a `Bytes` buffer.
+
+ifdef::env-github[[source,mermaid]
+]
+ifndef::env-github[[mermaid]
+]
-ifdef::env-github[[source,mermaid]]
-ifndef::env-github[[mermaid]]
----
classDiagram
class Wire {
@@ -165,14 +195,17 @@ Wire yamlWire = WireType.YAML_RETAIN_TYPE.apply(bytes);
Wire binaryWire = WireType.BINARY_LIGHT.apply(bytes);
----
-The `WireType` enum acts as a factory and configuration point for different wire formats. It allows the application to easily switch between, for example, human-readable YAML for debugging and compact Binary for production performance, using the same serialisation logic.
+The `WireType` enum acts as a factory and configuration point for different wire formats.
+It allows the application to easily switch between, for example, human-readable YAML for debugging and compact Binary for production performance, using the same serialisation logic.
=== `Marshallable`
The `Marshallable` interface is a marker interface that, when implemented by a POJO, allows Chronicle Wire to automatically serialize its fields.
-* **`readMarshallable(WireIn wire)`:** Method to read the object's state from the wire.
-* **`writeMarshallable(WireOut wire)`:** Method to write the object's state to the wire.
+`readMarshallable(WireIn wire)` ::
+Method to read the object's state from the wire.
+`writeMarshallable(WireOut wire)` ::
+Method to write the object's state to the wire.
Often, developers extend `SelfDescribingMarshallable`, which provides default implementations for these methods (using reflection or generated code) and also includes helpful `toString()`, `equals()`, and `hashCode()` methods based on the object's serialized form.
@@ -188,9 +221,12 @@ Chronicle Wire supports two main ways to marshal data:
Object Marshalling (via `Marshallable`) ::
* When an object implementing `Marshallable` is passed to `wire.getValueOut().object(obj)` or similar, Chronicle Wire needs to determine how to write its fields.
-* It uses an internal `WireMarshaller` for the class. This marshaller can be:
-** **Reflection-based:** Dynamically inspects fields at runtime. Slower, but requires no code generation.
-** **Code-generated:** At class-load time (or ahead-of-time in some scenarios), Chronicle Wire can generate specialized bytecode to read/write the fields of a `Marshallable` class directly. This is significantly faster.
+* It uses an internal `WireMarshaller` for the class.
+This marshaller can be:
+** *Reflection-based:* Dynamically inspects fields at runtime.
+Slower, but requires no code generation.
+** *Code-generated:* At class-load time (or ahead-of-time in some scenarios), Chronicle Wire can generate specialized bytecode to read/write the fields of a `Marshallable` class directly.
+This is significantly faster.
* Annotations like `@LongConversion`, `@NanoTime`, `@FieldNumber` can influence how fields are written and read by the `WireMarshaller`.
Fluent API Marshalling (Manual Wiring) ::
@@ -200,6 +236,7 @@ Only use this where there is no DTO available or when you need to write data tha
* This approach is more verbose but allows for dynamic schemas or when the data structure does not map cleanly to a Java class.
* Example of using the fluent API to write a trade message:
+
[source,java]
----
wire.write("trade")
@@ -207,12 +244,16 @@ wire.write("trade")
.write("price").float64(150.0)
.write("quantity").int32(100));
----
+
* This provides fine-grained control and is useful for dynamic schemas or when not using `Marshallable` POJOs.
== Serialization Formats (`WireType`) and Flexibility
-ifdef::env-github[[source,mermaid]]
-ifndef::env-github[[mermaid]]
+ifdef::env-github[[source,mermaid]
+]
+ifndef::env-github[[mermaid]
+]
+
----
graph LR
subgraph "Wire Format Comparison"
@@ -237,23 +278,35 @@ graph LR
end
----
-The power of Chronicle Wire's architecture lies in its ability to switch `WireType` implementations transparently. The same `Marshallable` object or the same sequence of fluent API calls will produce different byte outputs (YAML, JSON, Binary) depending on the `Wire` instance used.
-
-* **Text Formats (YAML, JSON, TEXT):** Human-readable, self-describing. Excellent for debugging, configuration, and interoperability where performance is less critical. `YAML_RETAIN_TYPE` and `JSON_RETAIN_TYPE` are configurations of YAML and JSON that include type information (e.g., `!Car {}`) allowing for polymorphic deserialisation.
-* **Binary Formats (`BINARY`, `BINARY_LIGHT`, `FIELDLESS_BINARY`, `RAW`):**
-** `BINARY_LIGHT` (and `BINARY`): Compact, efficient, self-describing to a degree (field numbers or names can be included). Good balance of performance and schema flexibility.
-** `FIELDLESS_BINARY`: Extremely compact as it omits field names/numbers, relying on the reader and writer agreeing on the field order. Highest performance for stable, internal schemas.
-** `RAW`: Essentially a "pass-through" for raw byte sequences, often used with `BytesMarshallable`.
-* `READ_ANY`: A special `WireType` that can attempt to detect and read data from any of the known formats, useful for flexible consumers.
+The power of Chronicle Wire's architecture lies in its ability to switch `WireType` implementations transparently.
+The same `Marshallable` object or the same sequence of fluent API calls will produce different byte outputs (YAML, JSON, Binary) depending on the `Wire` instance used.
+
+Text Formats (YAML, JSON, TEXT) ::
+Human-readable, self-describing.
+Excellent for debugging, configuration, and interoperability where performance is less critical.
+`YAML_RETAIN_TYPE` and `JSON_RETAIN_TYPE` are configurations of YAML and JSON that include type information (e.g., `!Car {}`) allowing for polymorphic deserialisation.
+Binary Formats (`BINARY`, `BINARY_LIGHT`, `FIELDLESS_BINARY`, `RAW`) ::
+* `BINARY_LIGHT` (and `BINARY`): Compact, efficient, self-describing to a degree (field numbers or names can be included).
+Good balance of performance and schema flexibility.
+* `FIELDLESS_BINARY`: Extremely compact as it omits field names/numbers, relying on the reader and writer agreeing on the field order.
+Highest performance for stable, internal schemas.
+* `RAW`: Essentially a "pass-through" for raw byte sequences, often used with `BytesMarshallable`.
+** `READ_ANY`: A special `WireType` that can attempt to detect and read data from any of the known formats, useful for flexible consumers.
== Schema Evolution
Chronicle Wire's architecture supports schema evolution primarily through its self-describing formats:
-* **Adding Fields:** New fields added to a `Marshallable` class will be written by new writers. Older readers will ignore these new fields if they are not present in their class definition.
-* **Removing Fields:** Fields removed from a `Marshallable` class will not be written by new writers. Older readers expecting these fields will typically see them as `null` or default values if the data was written by a newer writer.
-* **Reordering Fields:** In text formats (YAML, JSON) and binary formats that use field names, the order of fields generally does not matter for deserialisation.
-* **Field Numbers (`@FieldNumber`):** For binary formats, annotating fields with stable `@FieldNumber` allows renaming fields in the Java class without breaking wire compatibility, as the numeric tag remains the same.
+Adding Fields ::
+New fields added to a `Marshallable` class will be written by new writers.
+Older readers will ignore these new fields if they are not present in their class definition.
+Removing Fields ::
+Fields removed from a `Marshallable` class will not be written by new writers.
+Older readers expecting these fields will typically see them as `null` or default values if the data was written by a newer writer.
+Reordering Fields ::
+In text formats (YAML, JSON) and binary formats that use field names, the order of fields generally does not matter for deserialisation.
+Field Numbers (`@FieldNumber`) ::
+For binary formats, annotating fields with stable `@FieldNumber` allows renaming fields in the Java class without breaking wire compatibility, as the numeric tag remains the same.
`FIELDLESS_BINARY` is an exception; it is very sensitive to schema changes (field order, type, and count must match).
@@ -261,16 +314,26 @@ Chronicle Wire's architecture supports schema evolution primarily through its se
Several architectural choices contribute to Chronicle Wire's high performance:
-* **`Chronicle Bytes`:** Off-heap storage and direct memory access via `Bytes` minimizes GC overhead.
-* **Specialized `Wire` Implementations:** Each format has an optimised encoder/decoder. Binary formats, in particular, use techniques like stop-bit encoding for integers to reduce data size without CPU-intensive compression.
-* **Code Generation for `Marshallable`:** Avoids reflection overhead in critical paths.
-* **Object Reuse:** `DocumentContext` and other internal components are often pooled or designed for reuse. `Marshallable` objects can implement `reset()` methods for pooling.
-* **Minimal Abstraction Overhead:** While providing a clean API, the internal paths are optimised to reduce layers of indirection during actual data processing.
+`Chronicle Bytes` ::
+Off-heap storage and direct memory access via `Bytes` minimizes GC overhead.
+Specialized `Wire` Implementations ::
+Each format has an optimised encoder/decoder.
+Binary formats, in particular, use techniques like stop-bit encoding for integers to reduce data size without CPU-intensive compression.
+Code Generation for `Marshallable` ::
+Avoids reflection overhead in critical paths.
+Object Reuse ::
+`DocumentContext` and other internal components are often pooled or designed for reuse.
+`Marshallable` objects can implement `reset()` methods for pooling.
+Minimal Abstraction Overhead ::
+While providing a clean API, the internal paths are optimised to reduce layers of indirection during actual data processing.
== Integration with OpenHFT Ecosystem
-ifdef::env-github[[source,mermaid]]
-ifndef::env-github[[mermaid]]
+ifdef::env-github[[source,mermaid]
+]
+ifndef::env-github[[mermaid]
+]
+
----
graph TD
subgraph "OpenHFT Ecosystem"
@@ -288,16 +351,24 @@ graph TD
Chronicle Wire is the serialisation backbone for many other OpenHFT libraries:
-* **Chronicle Queue:** Uses Wire to serialize messages into queue excerpts. The `MethodWriter` and `MethodReader` patterns in Chronicle Queue are built on top of Wire's ability to serialize method calls and their arguments.
-* **Chronicle Map:** Uses Wire to serialize keys and values for storage in its off-heap hash map.
-* **Chronicle Network:** Can use Wire to marshal data for transmission over TCP/IP, enabling low-latency network communication.
-* **Chronicle Services:** Leverages Wire for defining and serializing events in event-driven architectures.
+Chronicle Queue ::
+Uses Wire to serialize messages into queue excerpts.
+The `MethodWriter` and `MethodReader` patterns in Chronicle Queue are built on top of Wire's ability to serialize method calls and their arguments.
+Chronicle Map ::
+Uses Wire to serialize keys and values for storage in its off-heap hash map.
+Chronicle Network ::
+Can use Wire to marshal data for transmission over TCP/IP, enabling low-latency network communication.
+Chronicle Services ::
+Leverages Wire for defining and serializing events in event-driven architectures.
This tight integration ensures that the performance benefits of Wire are propagated throughout the OpenHFT stack.
== Conclusion
-Chronicle Wire's architecture is a sophisticated blend of flexibility and high-performance engineering. By abstracting data formats behind a unified `Wire` API, leveraging `Chronicle Bytes` for efficient memory management, and providing robust marshalling capabilities for POJOs, it serves as a critical enabling technology for low-latency Java applications. Its design prioritizes minimizing garbage collection and CPU overhead, making it suitable for the most demanding use cases in financial systems and other real-time data processing environments. Understanding its layered architecture and core abstractions is key to effectively utilizing its power.
+Chronicle Wire's architecture is a sophisticated blend of flexibility and high-performance engineering.
+By abstracting data formats behind a unified `Wire` API, leveraging `Chronicle Bytes` for efficient memory management, and providing robust marshalling capabilities for POJOs, it serves as a critical enabling technology for low-latency Java applications.
+Its design prioritizes minimizing garbage collection and CPU overhead, making it suitable for the most demanding use cases in financial systems and other real-time data processing environments.
+Understanding its layered architecture and core abstractions is key to effectively utilizing its power.
== Related Topics
diff --git a/src/main/docs/wire-cookbook.adoc b/src/main/docs/wire-cookbook.adoc
index 772d5c4d13..1f42c41b5f 100644
--- a/src/main/docs/wire-cookbook.adoc
+++ b/src/main/docs/wire-cookbook.adoc
@@ -1,6 +1,7 @@
= Chronicle Wire Cookbook: Practical Recipes
:toc:
:sectnums:
+:lang: en-GB
:source-highlighter: rouge
Purpose :: To provide a collection of practical recipes for common tasks and advanced techniques when using the Chronicle Wire library.
@@ -8,7 +9,9 @@ Purpose :: To provide a collection of practical recipes for common tasks and adv
== Introduction
-This cookbook offers a series of focused, problem-solution style recipes to help you effectively use Chronicle Wire. Each recipe addresses a specific task or challenge, providing code examples and explanations. Whether you're new to Chronicle Wire or looking for advanced techniques, these recipes aim to provide quick and actionable guidance.
+This cookbook offers a series of focused, problem-solution style recipes to help you effectively use Chronicle Wire.
+Each recipe addresses a specific task or challenge, providing code examples and explanations.
+Whether you're new to Chronicle Wire or looking for advanced techniques, these recipes aim to provide quick and actionable guidance.
ifdef::env-github[[source,mermaid]]
ifndef::env-github[[mermaid]]
@@ -29,7 +32,10 @@ graph TD
end
----
-The diagram above illustrates the basic serialisation and deserialisation process in Chronicle Wire. Objects implementing the `Marshallable` interface can be written to a `Wire` instance, which uses a specific `WireType` to determine the format (YAML, JSON, Binary, etc.). The data is then stored in a `Bytes` buffer, which can be persisted or transmitted. The deserialisation process reverses these steps.
+The diagram above illustrates the basic serialisation and deserialisation process in Chronicle Wire.
+Objects implementing the `Marshallable` interface can be written to a `Wire` instance, which uses a specific `WireType` to determine the format (YAML, JSON, Binary, etc.).
+The data is then stored in a `Bytes` buffer, which can be persisted or transmitted.
+The deserialisation process reverses these steps.
TIP: For a foundational understanding of Chronicle Wire's architecture and core concepts, please refer to the main Chronicle Wire documentation and architectural overview.
@@ -41,9 +47,11 @@ TIP: For a foundational understanding of Chronicle Wire's architecture and core
You have a simple Plain Old Java Object (POJO) and you want to serialize it into different formats like YAML, JSON, and Binary using Chronicle Wire.
*Solution:*
-First, make your POJO implement `net.openhft.chronicle.wire.SelfDescribingMarshallable`. Then, use different `WireType` instances to serialize it.
+First, make your POJO implement `net.openhft.chronicle.wire.SelfDescribingMarshallable`.
+Then, use different `WireType` instances to serialize it.
-NOTE: Chronicle favours fluent property accessors (like `message()`, `number()`, `value()`) over traditional getters/setters. This is not strictly required but is a common practice in Chronicle Wire to enhance readability, maintainability, and reduce token count.
+NOTE: Chronicle favours fluent property accessors (like `message()`, `number()`, `value()`) over traditional getters/setters.
+This is not strictly required but is a common practice in Chronicle Wire to enhance readability, maintainability, and reduce token count.
. Define your `Marshallable` POJO:
+
@@ -114,7 +122,9 @@ public class BasicSerialisationDemo {
----
Discussion ::
-`SelfDescribingMarshallable` automatically handles the serialisation of fields. By simply changing the `WireType` (e.g., `YAML_ONLY`, `JSON_ONLY`, `BINARY_LIGHT`), you can control the output format without altering the `MyData` class or the core serialisation call (`getValueOut().object(data)`). `*_ONLY` variants like `YAML_ONLY` or `JSON_ONLY` are often preferred for cleaner output when not needing to retain full type information for dynamic deserialisation into differing types (though `YAML` and `JSON` wire types can be configured to include type information if needed).
+`SelfDescribingMarshallable` automatically handles the serialisation of fields.
+By simply changing the `WireType` (e.g., `YAML_ONLY`, `JSON_ONLY`, `BINARY_LIGHT`), you can control the output format without altering the `MyData` class or the core serialisation call (`getValueOut().object(data)`).
+`*_ONLY` variants like `YAML_ONLY` or `JSON_ONLY` are often preferred for cleaner output when not needing to retain full type information for dynamic deserialisation into differing types (though `YAML` and `JSON` wire types can be configured to include type information if needed).
=== Recipe: Deserializing Data into a POJO
@@ -176,7 +186,11 @@ public class BasicDeserialisationDemo {
----
*Discussion:*
-`getValueIn().object(MyData.class)` is the key call for deserialisation. Chronicle Wire reads the data and populates a new instance of `MyData`. For text formats like YAML, the `!MyData` type hint helps in identifying the target class, though providing the class explicitly in `object()` is robust. For binary formats, if type information isn't inherently part of the stream for the specific `WireType` chosen, providing the target class is essential. `SelfDescribingMarshallable` with `BINARY_LIGHT` typically includes type information or field names/numbers allowing for successful deserialisation.
+`getValueIn().object(MyData.class)` is the key call for deserialisation.
+Chronicle Wire reads the data and populates a new instance of `MyData`.
+For text formats like YAML, the `!MyData` type hint helps in identifying the target class, though providing the class explicitly in `object()` is robust.
+For binary formats, if type information isn't inherently part of the stream for the specific `WireType` chosen, providing the target class is essential.
+`SelfDescribingMarshallable` with `BINARY_LIGHT` typically includes type information or field names/numbers allowing for successful deserialisation.
[[working_with_annotations]]
== Working with Annotations
@@ -187,7 +201,8 @@ public class BasicDeserialisationDemo {
You have a short string identifier (e.g., a symbol or ID up to 10-11 characters using a Base85-like alphabet) that you want to represent as a `long` in your Java object for efficiency, but display as a String in human-readable formats (like YAML).
*Solution:*
-Use the `@LongConversion` annotation with a suitable converter, like `Base85LongConverter`. Chronicle Wire provides shorthand annotations like `@Base85`.
+Use the `@LongConversion` annotation with a suitable converter, like `Base85LongConverter`.
+Chronicle Wire provides shorthand annotations like `@Base85`.
. Define your `Marshallable` POJO with an annotated field:
+
@@ -267,7 +282,10 @@ public class LongConversionDemo {
----
Discussion ::
-In the YAML output, `symbol` appears as a string "AAPL". However, in the `CompactIdData` object and in the binary wire format, it's stored as an 8-byte `long`. This technique is excellent for performance-sensitive applications that deal with many short textual identifiers, saving space and potentially speeding up comparisons/hashing if the `long` form is used internally. Chronicle Wire provides several built-in converters (`Base32`, `Base64`, `Base85`, etc.).
+In the YAML output, `symbol` appears as a string "AAPL".
+However, in the `CompactIdData` object and in the binary wire format, it's stored as an 8-byte `long`.
+This technique is excellent for performance-sensitive applications that deal with many short textual identifiers, saving space and potentially speeding up comparisons/hashing if the `long` form is used internally.
+Chronicle Wire provides several built-in converters (`Base32`, `Base64`, `Base85`, etc.).
=== Recipe: Formatting Timestamps with `@NanoTime`
@@ -331,7 +349,8 @@ public class NanoTimeDemo {
----
*Discussion:*
-The `@NanoTime` annotation (and similarly `@MillisTime` for millisecond precision) ensures that the `long` timestamp is converted to/from a standard ISO 8601 string representation in text formats like YAML or JSON, while remaining a `long` in binary formats and in the Java object. This provides both human readability for logs/configs and numerical efficiency for processing.
+The `@NanoTime` annotation (and similarly `@MillisTime` for millisecond precision) ensures that the `long` timestamp is converted to/from a standard ISO 8601 string representation in text formats like YAML or JSON, while remaining a `long` in binary formats and in the Java object.
+This provides both human readability for logs/configs and numerical efficiency for processing.
[[schema_evolution]]
== Schema Evolution
@@ -339,10 +358,12 @@ The `@NanoTime` annotation (and similarly `@MillisTime` for millisecond precisio
=== Recipe: Adding a New Field (Backward Compatibility)
*Problem:*
-You have an existing `Marshallable` class and need to add a new field. You want older versions of your application (that don't know about the new field) to still be able to read data written by the new version, and new versions to read old data.
+You have an existing `Marshallable` class and need to add a new field.
+You want older versions of your application (that don't know about the new field) to still be able to read data written by the new version, and new versions to read old data.
*Solution:*
-Simply add the new field to your class. Chronicle Wire's self-describing formats (like YAML, JSON, and `BINARY_LIGHT`) handle this gracefully.
+Simply add the new field to your class.
+Chronicle Wire's self-describing formats (like YAML, JSON, and `BINARY_LIGHT`) handle this gracefully.
. Original class `VersionedDataV1`:
+
@@ -390,7 +411,8 @@ public class VersionedDataV2 extends SelfDescribingMarshallable {
}
----
-IMPORTANT: For Chronicle Wire to map `com.example.evo.VersionedDataV1` to `com.example.evo.VersionedDataV2` when reading old data, you would typically ensure they have the same class alias if using `WireType.YAML` (which uses type info). If you are deserializing into a specific class `VersionedDataV2.class`, then the type alias in the data is less critical, as Wire will try to map fields by name.
+IMPORTANT: For Chronicle Wire to map `com.example.evo.VersionedDataV1` to `com.example.evo.VersionedDataV2` when reading old data, you would typically ensure they have the same class alias if using `WireType.YAML` (which uses type info).
+If you are deserializing into a specific class `VersionedDataV2.class`, then the type alias in the data is less critical, as Wire will try to map fields by name.
. Demonstration:
+
@@ -444,7 +466,10 @@ public class SchemaEvolutionDemo {
----
*Discussion:*
-When new code reads old data (V1 data into `VersionedDataV2`), the `newField` in `VersionedDataV2` will be initialized to its Java default value (0 for `int`, `null` for objects, `false` for `boolean`). When old code (expecting `VersionedDataV1`) reads data written by new code (V2 data), it will simply ignore the `newField` it doesn't recognize. This works seamlessly for most self-describing `WireType`s. Using consistent class aliasing (e.g., `Wires.CLASS_ALIASES.addAlias(VersionedDataV2.class, "VersionedData")`) can be important if you rely on type information in the stream (like `!VersionedData`) rather than always specifying the concrete class on deserialisation.
+When new code reads old data (V1 data into `VersionedDataV2`), the `newField` in `VersionedDataV2` will be initialized to its Java default value (0 for `int`, `null` for objects, `false` for `boolean`).
+When old code (expecting `VersionedDataV1`) reads data written by new code (V2 data), it will simply ignore the `newField` it doesn't recognize.
+This works seamlessly for most self-describing `WireType`s.
+Using consistent class aliasing (e.g., `Wires.CLASS_ALIASES.addAlias(VersionedDataV2.class, "VersionedData")`) can be important if you rely on type information in the stream (like `!VersionedData`) rather than always specifying the concrete class on deserialisation.
== Working with `DocumentContext`
@@ -454,7 +479,8 @@ When new code reads old data (V1 data into `VersionedDataV2`), the `newField` in
You need to write a sequence of distinct messages or objects to a single `Bytes` buffer or stream, and then read them back one by one.
*Solution:*
-Use `DocumentContext` to demarcate each message. This is fundamental to how Chronicle Queue works.
+Use `DocumentContext` to demarcate each message.
+This is fundamental to how Chronicle Queue works.
. Writing multiple documents:
+
@@ -525,7 +551,10 @@ public class MultiDocumentDemo {
----
*Discussion:*
-The `try-with-resources` block ensures that each `DocumentContext` is properly closed. When `writingDocument()`'s context is closed, metadata (like message length) is written, allowing the reader to correctly identify document boundaries. `readingDocument()` returns a context; `dc.isPresent()` tells you if a document was found. `dc.isData()` or `dc.isMetaData()` can be used to distinguish message types, a pattern heavily used by Chronicle Queue.
+The `try-with-resources` block ensures that each `DocumentContext` is properly closed.
+When `writingDocument()`'s context is closed, metadata (like message length) is written, allowing the reader to correctly identify document boundaries.
+`readingDocument()` returns a context; `dc.isPresent()` tells you if a document was found.
+`dc.isData()` or `dc.isMetaData()` can be used to distinguish message types, a pattern heavily used by Chronicle Queue.
== Advanced & Performance
@@ -617,9 +646,15 @@ public class BytesMarshallableDemo {
----
*Discussion:*
-`BytesMarshallable` gives you direct access to the `BytesIn` and `BytesOut` objects. You are responsible for reading and writing all fields in the correct order and format. This offers maximum performance by bypassing much of Wire's higher-level machinery but requires more manual effort and is more brittle to schema changes if not managed carefully. `WireType.RAW` is often used with `BytesMarshallable` as it does minimal framing. When deserializing, you might pass a pre-allocated instance to `object(instance, class)` to encourage object reuse.
-
-NOTE: This cookbook provides a starting point. Many more recipes can be developed for specific use cases and advanced features of Chronicle Wire. Refer to the main documentation for comprehensive details on each feature.
+`BytesMarshallable` gives you direct access to the `BytesIn` and `BytesOut` objects.
+You are responsible for reading and writing all fields in the correct order and format.
+This offers maximum performance by bypassing much of Wire's higher-level machinery but requires more manual effort and is more brittle to schema changes if not managed carefully.
+`WireType.RAW` is often used with `BytesMarshallable` as it does minimal framing.
+When deserializing, you might pass a pre-allocated instance to `object(instance, class)` to encourage object reuse.
+
+NOTE: This cookbook provides a starting point.
+Many more recipes can be developed for specific use cases and advanced features of Chronicle Wire.
+Refer to the main documentation for comprehensive details on each feature.
== Related Topics
diff --git a/src/main/docs/wire-error-handling.adoc b/src/main/docs/wire-error-handling.adoc
index c7e29db55d..7f4c8708e0 100644
--- a/src/main/docs/wire-error-handling.adoc
+++ b/src/main/docs/wire-error-handling.adoc
@@ -1,6 +1,7 @@
= Chronicle Wire: Error Handling and Diagnostics Guide
:toc:
:sectnums:
+:lang: en-GB
:source-highlighter: rouge
Purpose: To provide a comprehensive guide on handling errors, diagnosing issues, and debugging when using the Chronicle Wire library.
@@ -130,48 +131,57 @@ Deserialisation is often where subtle data or schema issues become apparent.
=== Schema Mismatches
-* **Symptoms:** `InvalidMarshallableException`, unexpected `null` values, incorrect field values, or even `BufferUnderflowException` if field count/size changes drastically with formats like `FIELDLESS_BINARY`.
-* **Diagnosis:**
-1. **Dump to YAML:** If possible, convert the problematic binary data to YAML to visually inspect field names, types, and values.
-2. **Compare Class Definitions:** Manually compare the `Marshallable` class definitions used by the writer and the reader.
+Symptoms ::
+`InvalidMarshallableException`, unexpected `null` values, incorrect field values, or even `BufferUnderflowException` if field count/size changes drastically with formats like `FIELDLESS_BINARY`.
+Diagnosis ::
+. *Dump to YAML:* If possible, convert the problematic binary data to YAML to visually inspect field names, types, and values.
+. *Compare Class Definitions:* Manually compare the `Marshallable` class definitions used by the writer and the reader.
Look for differences in field names, types, order (if using `FIELDLESS_BINARY`), and annotations.
-3. **Check `@FieldNumber`:** If using binary formats and `@FieldNumber`, ensure these are consistent and unique.
-* **Solutions:**
+. *Check `@FieldNumber`:* If using binary formats and `@FieldNumber`, ensure these are consistent and unique.
+Solutions ::
* Align class definitions.
* Implement proper schema evolution strategies (see Chronicle Wire documentation on schema evolution).
* For `FIELDLESS_BINARY`, ensure strict schema identity or implement a versioning/migration path.
=== Corrupted Data or Framing Errors
-* **Symptoms:** `EOFException`, `BufferUnderflowException`, `InvalidMarshallableException` with cryptic messages, or reading garbage data.
-* **Diagnosis:**
-1. **Inspect `DocumentContext`:** When reading in a loop, log the state of `dc.isPresent()`, `dc.isData()`, `dc.isMetaData()`, `dc.isNotComplete()`.
+Symptoms ::
+`EOFException`, `BufferUnderflowException`, `InvalidMarshallableException` with cryptic messages, or reading garbage data.
+Diagnosis ::
+. *Inspect `DocumentContext`:* When reading in a loop, log the state of `dc.isPresent()`, `dc.isData()`, `dc.isMetaData()`, `dc.isNotComplete()`.
An unexpected `isNotComplete()` can indicate a partially written message.
-2. **Hex Dump:** Examine the raw `Bytes` using `bytes.toHexString()` to look for unexpected patterns or premature ends.
-3. **Verify Length Prefixes:** If `DocumentContext` is used, it handles length prefixes.
+. *Hex Dump:* Examine the raw `Bytes` using `bytes.toHexString()` to look for unexpected patterns or premature ends.
+. *Verify Length Prefixes:* If `DocumentContext` is used, it handles length prefixes.
If you have custom framing, ensure it's correct.
-* **Solutions:**
+Solutions ::
* Ensure producers fully write and commit/flush data before consumers try to read it.
* Use `DocumentContext` correctly with `try-with-resources` to ensure proper document finalisation and reading.
* Investigate the source of potential data corruption (network issues, disk errors, bugs in writing logic).
=== Class Aliasing and Polymorphism Issues
-* **Symptoms:** `ClassNotFoundException`, or deserialisation into a base type instead of the expected subtype.
-* **Diagnosis:**
-1. Check YAML/JSON output for type tags (e.g., `!com.example.MySpecificType {}`).
-2. Verify `Wires.CLASS_ALIASES` setup on both sides if aliases are used.
-3. Ensure the `WireType` used supports and is configured for type retention (e.g., `YAML_RETAIN_TYPE` vs `YAML_ONLY`).
-* **Solutions:**
+Symptoms ::
+`ClassNotFoundException`, or deserialisation into a base type instead of the expected subtype.
+Diagnosis ::
+. Check YAML/JSON output for type tags (e.g., `!com.example.MySpecificType {}`).
+. Verify `Wires.CLASS_ALIASES` setup on both sides if aliases are used.
+. Ensure the `WireType` used supports and is configured for type retention (e.g., `YAML_RETAIN_TYPE` vs `YAML_ONLY`).
+Solutions ::
* Configure class aliasing correctly and consistently.
* Use `WireType`s that retain type information when deserialising polymorphic types.
* Explicitly pass the concrete class to `valueIn.object(SpecificType.class)` if type information is not in the stream.
=== Missing No-Argument Constructor
-* **Symptoms:** Exception during object instantiation, often a `NoSuchMethodException` wrapped in a Wire exception.
-* **Diagnosis:** Chronicle Wire (like many serialisation libraries) may require a no-argument constructor to instantiate objects before populating them, especially when using reflection-based or generated marshallers. Generally, it doesn't need a no-argument constructor for `BytesMarshallable` classes. However, this will result in `transient` fields not being set, which can lead to unexpected `null` values or default values in the deserialised object.
-* **Solutions:** Add a public or protected no-argument constructor to your `Marshallable` classes. The access level is ignored, so `private` or package-local can be used.
+Symptoms ::
+Exception during object instantiation, often a `NoSuchMethodException` wrapped in a Wire exception.
+Diagnosis ::
+Chronicle Wire (like many serialisation libraries) may require a no-argument constructor to instantiate objects before populating them, especially when using reflection-based or generated marshallers.
+Generally, it doesn't need a no-argument constructor for `BytesMarshallable` classes.
+However, this will result in `transient` fields not being set, which can lead to unexpected `null` values or default values in the deserialised object.
+Solutions ::
+Add a public or protected no-argument constructor to your `Marshallable` classes.
+The access level is ignored, so `private` or package-local can be used.
== Troubleshooting Serialisation Issues
@@ -179,39 +189,48 @@ Issues during serialisation are often more straightforward but can still occur.
=== Buffer Overflow
-* **Symptoms:** `BufferOverflowException`.
-* **Diagnosis:** The data being written is larger than the `Bytes` buffer's current capacity.
-* **Solutions:**
+Symptoms ::
+`BufferOverflowException`.
+Diagnosis ::
+The data being written is larger than the `Bytes` buffer's current capacity.
+Solutions ::
* Use `Bytes.elasticByteBuffer()` or `Bytes.elasticHeapByteBuffer()` for automatically resizing buffers.
* If using fixed-size buffers, ensure they are pre-allocated with sufficient capacity.
Estimate maximum message size.
=== Invalid Data for Fields/Annotations
-* **Symptoms:** `IllegalArgumentException`, `IllegalStateException`, or exceptions from annotation converters (e.g., `Base85LongConverter` failing to parse an invalid character).
-* **Diagnosis:** An attempt was made to write data that violates constraints.
+Symptoms ::
+`IllegalArgumentException`, `IllegalStateException`, or exceptions from annotation converters (e.g., `Base85LongConverter` failing to parse an invalid character).
+Diagnosis ::
+An attempt was made to write data that violates constraints.
* A string field annotated with `@MaxUtf8Len` receives a string that is too long.
* A `@LongConversion`-annotated field receives a string that cannot be parsed by the converter.
-* **Solutions:**
+Solutions ::
* Validate data before attempting to serialize it.
* Ensure data conforms to the constraints imposed by annotations.
* Handle exceptions from converters gracefully.
=== Custom `Marshallable` Implementation Bugs
-* **Symptoms:** Incorrect data written, `NullPointerException`, or other unexpected exceptions originating from your `writeMarshallable()` method.
-* **Diagnosis:** Step through your custom `writeMarshallable()` logic in a debugger.
+Symptoms ::
+Incorrect data written, `NullPointerException`, or other unexpected exceptions originating from your `writeMarshallable()` method.
+Diagnosis ::
+Step through your custom `writeMarshallable()` logic in a debugger.
Log the values being written.
-* **Solutions:** Carefully review and test your custom marshalling logic, ensuring all fields are written correctly and in the intended order (especially for `BytesMarshallable`).
+Solutions ::
+Carefully review and test your custom marshalling logic, ensuring all fields are written correctly and in the intended order (especially for `BytesMarshallable`).
== Debugging Techniques
=== Dump to YAML/Text
One of the most powerful features of Chronicle Wire for debugging is its ability to switch formats.
-* **Writing:** If you suspect issues with binary serialisation, temporarily change the `WireType` to `YAML_ONLY` or `JSON_ONLY` and print the `Bytes.toString()`.
+Writing ::
+If you suspect issues with binary serialisation, temporarily change the `WireType` to `YAML_ONLY` or `JSON_ONLY` and print the `Bytes.toString()`.
This allows you to see a human-readable representation of what's being written.
-* **Reading:** If you have binary data in a `Bytes` buffer that you suspect is malformed, you can attempt to read it using a `YAML_ONLY` wire (if the binary format is self-describing like `BINARY_LIGHT`):
+Reading ::
+If you have binary data in a `Bytes` buffer that you suspect is malformed, you can attempt to read it using a `YAML_ONLY` wire (if the binary format is self-describing like `BINARY_LIGHT`):
[source,java]
----
@@ -254,7 +273,9 @@ Serialize and deserialize a problematic object in a simple test case to rule out
== Error Handling Best Practices
-* **Use `try-with-resources` for `DocumentContext`:** Ensures proper resource management and finalisation of documents.
+Use `try-with-resources` for `DocumentContext` ::
+Ensures proper resource management and finalisation of documents.
+
[source,java]
----
try (DocumentContext dc = wire.writingDocument()) {
@@ -262,18 +283,25 @@ try (DocumentContext dc = wire.writingDocument()) {
} // dc.close() is called automatically
----
-* **Check `DocumentContext.isPresent()` before reading:** Prevents errors when no more data is available.
-* **Validate Data:** Validate business data before attempting serialisation to catch issues early.
-* **Graceful Degradation:** For non-critical errors, log the issue and continue if possible, rather than crashing the application.
-* **Specific Catch Blocks:** Catch specific exceptions (`BufferUnderflowException`, `InvalidMarshallableException`) rather than generic `Exception` where possible, to handle them more appropriately.
-* **Logging:** Log errors with sufficient context (e.g., the data being processed if it's not too large or sensitive, relevant identifiers, stack traces).
-* **Resource Management:** Always release `Bytes` buffers obtained from `Bytes.elasticByteBuffer()` or `Bytes.allocateDirect()` using `bytes.releaseLast()` when they are no longer needed, especially for direct/off-heap memory, to prevent memory leaks.
+Check `DocumentContext.isPresent()` before reading ::
+Prevents errors when no more data is available.
+Validate Data ::
+Validate business data before attempting serialisation to catch issues early.
+Graceful Degradation ::
+For non-critical errors, log the issue and continue if possible, rather than crashing the application.
+Specific Catch Blocks ::
+Catch specific exceptions (`BufferUnderflowException`, `InvalidMarshallableException`) rather than generic `Exception` where possible, to handle them more appropriately.
+Logging ::
+Log errors with sufficient context (e.g., the data being processed if it's not too large or sensitive, relevant identifiers, stack traces).
+Resource Management ::
+Always release `Bytes` buffers obtained from `Bytes.elasticByteBuffer()` or `Bytes.allocateDirect()` using `bytes.releaseLast()` when they are no longer needed, especially for direct/off-heap memory, to prevent memory leaks.
== Related Errors in Integrated Systems
When Chronicle Wire is used within larger systems like Chronicle Queue or Chronicle Network, errors might originate from those systems but relate to the data being processed by Wire.
-* **Network Errors (`java.net.SocketException`, etc.):** If using Wire over a network, underlying network issues can interrupt data streams, leading to partial messages and subsequent Wire deserialisation errors.
+Network Errors (`java.net.SocketException`, etc.) ::
+If using Wire over a network, underlying network issues can interrupt data streams, leading to partial messages and subsequent Wire deserialisation errors.
== Conclusion
diff --git a/src/main/docs/wire-faq.adoc b/src/main/docs/wire-faq.adoc
index d0d61b6fd7..64b174ed4c 100644
--- a/src/main/docs/wire-faq.adoc
+++ b/src/main/docs/wire-faq.adoc
@@ -1,5 +1,6 @@
= Chronicle Wire FAQ: Common Questions Answered
:toc:
+:lang: en-GB
:source-highlighter: rouge
Purpose: To provide answers to frequently asked questions about the Chronicle Wire library.
@@ -9,7 +10,8 @@ Purpose: To provide answers to frequently asked questions about the Chronicle Wi
== Basics & Core Concepts
What is Chronicle Wire? ::
-Chronicle Wire is an open-source Java library from the OpenHFT ecosystem designed for high-performance, low-latency serialisation and deserialisation. It supports multiple data formats through a unified API.
+Chronicle Wire is an open-source Java library from the OpenHFT ecosystem designed for high-performance, low-latency serialisation and deserialisation.
+It supports multiple data formats through a unified API.
Why should I use Chronicle Wire over standard Java Serialisation? ::
Chronicle Wire offers significantly better performance (lower latency, higher throughput), minimal garbage creation, greater flexibility with multiple data formats, and more robust schema evolution capabilities compared to standard Java Serialisation.
@@ -21,47 +23,64 @@ What does "format-agnostic" mean in the context of Chronicle Wire? ::
It means you can write your serialisation/deserialisation logic once (e.g., using `Marshallable` objects) and then switch the underlying data format (e.g., from YAML to Binary) by simply changing the `WireType` without altering your core application code.
What is `Bytes` in Chronicle Wire? ::
-`Bytes` (from the `chronicle-bytes` library) is a core abstraction representing a sequence of bytes. It can wrap on-heap byte arrays, off-heap direct memory, or memory-mapped files. Chronicle Wire implementations read from and write to `Bytes` instances.
+`Bytes` (from the `chronicle-bytes` library) is a core abstraction representing a sequence of bytes.
+It can wrap on-heap byte arrays, off-heap direct memory, or memory-mapped files.
+Chronicle Wire implementations read from and write to `Bytes` instances.
What is a `Wire` instance? ::
-A `Wire` instance is the primary interface for reading and writing structured data in a specific format (like YAML, JSON, or Binary). You obtain it by applying a `WireType` to a `Bytes` buffer.
+A `Wire` instance is the primary interface for reading and writing structured data in a specific format (like YAML, JSON, or Binary).
+You obtain it by applying a `WireType` to a `Bytes` buffer.
What is `WireType`? ::
-`WireType` is an enum that defines the different serialisation formats supported by Chronicle Wire (e.g., `YAML_ONLY`, `JSON_ONLY`, `BINARY_LIGHT`, `FIELDLESS_BINARY`). It also acts as a factory for creating `Wire` instances.
+`WireType` is an enum that defines the different serialisation formats supported by Chronicle Wire (e.g., `YAML_ONLY`, `JSON_ONLY`, `BINARY_LIGHT`, `FIELDLESS_BINARY`).
+It also acts as a factory for creating `Wire` instances.
What is `DocumentContext`? ::
-`DocumentContext` is used to manage the boundaries of individual messages or "documents" when streaming multiple items to or from a `Wire`. It's crucial for ensuring messages are correctly framed, especially in binary formats or when used with Chronicle Queue.
+`DocumentContext` is used to manage the boundaries of individual messages or "documents" when streaming multiple items to or from a `Wire`.
+It's crucial for ensuring messages are correctly framed, especially in binary formats or when used with Chronicle Queue.
== `Marshallable` Objects
What is the `Marshallable` interface? ::
-It's an interface that your POJOs can implement to indicate they can be serialized and deserialized by Chronicle Wire. It has `readMarshallable(WireIn)` and `writeMarshallable(WireOut)` methods.
+It's an interface that your POJOs can implement to indicate they can be serialized and deserialized by Chronicle Wire.
+It has `readMarshallable(WireIn)` and `writeMarshallable(WireOut)` methods.
What is `SelfDescribingMarshallable`? ::
-It's a convenient abstract base class that implements `Marshallable`. It automatically provides serialisation/deserialisation logic for fields (via reflection or code generation) and also generates `toString()`, `equals()`, and `hashCode()` methods based on the object's fields.
+It's a convenient abstract base class that implements `Marshallable`.
+It automatically provides serialisation/deserialisation logic for fields (via reflection or code generation) and also generates `toString()`, `equals()`, and `hashCode()` methods based on the object's fields.
What is `BytesMarshallable`? ::
-It's a lower-level interface for objects that need complete control over their binary representation. Implementors read/write directly from/to `BytesIn`/`BytesOut`, bypassing some of Wire's higher-level mechanisms for maximum performance or custom formats.
+It's a lower-level interface for objects that need complete control over their binary representation.
+Implementors read/write directly from/to `BytesIn`/`BytesOut`, bypassing some of Wire's higher-level mechanisms for maximum performance or custom formats.
How does Chronicle Wire serialize fields in a `Marshallable` object? ::
By default (especially with `SelfDescribingMarshallable`), it can use reflection or, for better performance, generate bytecode at runtime (`WireMarshaller`) to directly access and serialize/deserialize fields.
Do I need getters and setters for `Marshallable` objects? ::
-Not strictly for serialisation if fields are public or default access within the same package. However, for private fields or to follow JavaBean conventions, getters/setters are good practice. Chronicle Wire's generated marshallers can often access private fields if permissions allow.
+Not strictly for serialisation if fields are public or default access within the same package.
+However, for private fields or to follow JavaBean conventions, getters/setters are good practice.
+Chronicle Wire's generated marshallers can often access private fields if permissions allow.
Can I serialize collections (Lists, Maps) with Chronicle Wire? ::
-Yes. Chronicle Wire can serialize collections containing primitives, strings, or other `Marshallable` objects. It has specific methods on `ValueOut` (e.g., `sequence()`, `marshallableAsMap()`) and `ValueIn` to handle them.
+Yes.
+Chronicle Wire can serialize collections containing primitives, strings, or other `Marshallable` objects.
+It has specific methods on `ValueOut` (e.g., `sequence()`, `marshallableAsMap()`) and `ValueIn` to handle them.
How are null values handled? ::
-Chronicle Wire can represent nulls. In text formats, it might be explicit (e.g., `fieldName: !!null ""`). In binary, it's handled with special markers or by omitting fields. The behaviour can sometimes depend on the `WireType`.
+Chronicle Wire can represent nulls.
+In text formats, it might be explicit (e.g., `fieldName: !!null ""`).
+In binary, it's handled with special markers or by omitting fields.
+The behaviour can sometimes depend on the `WireType`.
== API Usage
What are `WireIn` and `WireOut`? ::
-These are interfaces used by `Marshallable` objects for reading (`WireIn`) and writing (`WireOut`) their state. They provide methods to access `ValueIn` and `ValueOut`.
+These are interfaces used by `Marshallable` objects for reading (`WireIn`) and writing (`WireOut`) their state.
+They provide methods to access `ValueIn` and `ValueOut`.
What are `ValueIn` and `ValueOut`? ::
-These provide a fluent API for reading and writing individual named or indexed values of various types (e.g., `text()`, `int32()`, `object()`, `sequence()`). `Wire` provides access to root `ValueIn` and `ValueOut`.
+These provide a fluent API for reading and writing individual named or indexed values of various types (e.g., `text()`, `int32()`, `object()`, `sequence()`).
+`Wire` provides access to root `ValueIn` and `ValueOut`.
How do I write a single object to a Wire? ::
Typically, you get a `ValueOut` from the `Wire` and call `vo.object(myMarshallableObject);`.
@@ -70,10 +89,13 @@ How do I read a single object from a Wire? ::
Get a `ValueIn` from the `Wire` and call `vi.object(MyClass.class);` or `vi.object(myPreallocatedInstance, MyClass.class);`.
What's the purpose of `try-with-resources` with `DocumentContext`? ::
-It ensures that the `DocumentContext` is closed properly. For writing, closing the context finalizes the document (e.g., writes its length prefix). For reading, it releases any resources held by the context.
+It ensures that the `DocumentContext` is closed properly.
+For writing, closing the context finalizes the document (e.g., writes its length prefix).
+For reading, it releases any resources held by the context.
Can Chronicle Wire serialize enums? ::
-Yes, enums can be serialized. They are typically written as their string name in text formats or as an ordinal/name in binary.
+Yes, enums can be serialized.
+They are typically written as their string name in text formats or as an ordinal/name in binary.
== Serialisation Formats
@@ -81,16 +103,24 @@ Which `WireType` should I choose for human-readable output? ::
`YAML_ONLY` or `JSON_ONLY` are good choices for pure YAML or JSON output respectively.
Which `WireType` is best for performance? ::
-`BINARY_LIGHT` offers a good balance of performance and self-description (for schema evolution). `FIELDLESS_BINARY` is extremely compact and fast but requires the reader and writer to have identical, fixed schemas. `RAW` is for `BytesMarshallable` or direct byte manipulation.
+`BINARY_LIGHT` offers a good balance of performance and self-description (for schema evolution).
+`FIELDLESS_BINARY` is extremely compact and fast but requires the reader and writer to have identical, fixed schemas.
+`RAW` is for `BytesMarshallable` or direct byte manipulation.
What is the difference between `BINARY` and `BINARY_LIGHT`? ::
-`BINARY_LIGHT` is generally preferred and more modern. It aims to be more compact and efficient. `BINARY` might have slightly different header information or conventions.
+`BINARY_LIGHT` is generally preferred and more modern.
+It aims to be more compact and efficient.
+`BINARY` might have slightly different header information or conventions.
Can I read data written in one `WireType` with another? ::
-Sometimes, yes. For example, binary data written with `BINARY_LIGHT` can often be "dumped" or inspected using `YAML_ONLY` because `BINARY_LIGHT` can be self-describing. `READ_ANY` wire type attempts to auto-detect the format. However, you cannot reliably read `FIELDLESS_BINARY` as YAML, for instance.
+Sometimes, yes.
+For example, binary data written with `BINARY_LIGHT` can often be "dumped" or inspected using `YAML_ONLY` because `BINARY_LIGHT` can be self-describing.
+`READ_ANY` wire type attempts to auto-detect the format.
+However, you cannot reliably read `FIELDLESS_BINARY` as YAML, for instance.
How does `YAML_RETAIN_TYPE` or `JSON_RETAIN_TYPE` work? ::
-These wire types include explicit type information (e.g., `!com.example.MyClass {}` in YAML) in the output. This allows for deserialisation of polymorphic types or when the concrete class is not known by the reader beforehand.
+These wire types include explicit type information (e.g., `!com.example.MyClass {}` in YAML) in the output.
+This allows for deserialisation of polymorphic types or when the concrete class is not known by the reader beforehand.
== Annotations
@@ -98,13 +128,15 @@ What is the purpose of annotations in Chronicle Wire? ::
Annotations provide a declarative way to customise serialisation behaviour, such as data conversion, formatting, or providing metadata for schema evolution, without writing extensive custom marshalling code.
How does `@LongConversion` (e.g., `@Base64`, `@Base85`) work? ::
-It allows you to store a short string (packed into a `long`) efficiently in binary while representing it as a human-readable string in text formats. For example, `@ShortText long myId;` will store up to 10 characters in an 8-byte long.
+It allows you to store a short string (packed into a `long`) efficiently in binary while representing it as a human-readable string in text formats.
+For example, `@ShortText long myId;` will store up to 10 characters in an 8-byte long.
What does `@NanoTime` or `@MillisTime` do? ::
They instruct Chronicle Wire to store a `long` timestamp as a numeric value in binary but format it as a human-readable ISO 8601 date-time string in text formats (YAML, JSON).
What is `@FieldNumber` used for? ::
-In binary formats, `@FieldNumber` allows you to assign a stable numeric identifier to a field. This means you can rename the Java field later without breaking binary compatibility, as long as the field number remains the same.
+In binary formats, `@FieldNumber` allows you to assign a stable numeric identifier to a field.
+This means you can rename the Java field later without breaking binary compatibility, as long as the field number remains the same.
Can I add comments to YAML output? ::
Yes, the `@Comment` annotation can be used on fields in your `Marshallable` class to add comments that will appear in YAML output.
@@ -114,32 +146,42 @@ Yes, the `@Comment` annotation can be used on fields in your `Marshallable` clas
How does Chronicle Wire support schema evolution? ::
For self-describing formats (most text formats, `BINARY_LIGHT`), fields are typically identified by name or a tag.
-* **Adding fields:** New code writes new fields; old code ignores them.
-* **Removing fields:** New code omits fields; old code treats them as null/default.
-* **Reordering fields:** Usually not an issue for named fields.
+Adding fields ::
+New code writes new fields; old code ignores them.
+Removing fields ::
+New code omits fields; old code treats them as null/default.
+Reordering fields ::
+Usually not an issue for named fields.
Can I add a new field to a `Marshallable` class without breaking old clients? ::
-Yes, if using a self-describing format. Old clients (readers) will simply ignore the new field they don't recognize in the incoming data.
+Yes, if using a self-describing format.
+Old clients (readers) will simply ignore the new field they don't recognize in the incoming data.
What happens if an old client reads data with a missing field (written by a newer client that removed it)? ::
The field in the old client's object will typically be initialized to its Java default value (0, false, null).
Is `FIELDLESS_BINARY` good for schema evolution? ::
-No. `FIELDLESS_BINARY` is extremely brittle to schema changes. The reader and writer must have an identical understanding of the field order, types, and count.
+No. `FIELDLESS_BINARY` is extremely brittle to schema changes.
+The reader and writer must have an identical understanding of the field order, types, and count.
How can I rename a field while maintaining compatibility? ::
-For binary formats, use `@FieldNumber` to provide a stable numeric ID. For text formats, you might need a transition period where both old and new field names are understood by readers, or use a custom deserializer if the change is complex. `Wires.renameOldFieldToNew()` can sometimes help during transitions for text formats.
+For binary formats, use `@FieldNumber` to provide a stable numeric ID.
+For text formats, you might need a transition period where both old and new field names are understood by readers, or use a custom deserializer if the change is complex.
+`Wires.renameOldFieldToNew()` can sometimes help during transitions for text formats.
== Performance
How does Chronicle Wire achieve low latency? ::
-By minimizing garbage creation (using off-heap `Bytes`, object pooling), using efficient binary encodings, and enabling direct memory access. Code generation for marshallers also avoids reflection overhead.
+By minimizing garbage creation (using off-heap `Bytes`, object pooling), using efficient binary encodings, and enabling direct memory access.
+Code generation for marshallers also avoids reflection overhead.
Does Chronicle Wire create garbage? ::
-It's designed to create minimal or zero garbage in its critical paths, especially when using binary formats, off-heap `Bytes`, and object reuse patterns. Text formats inherently create more garbage (Strings).
+It's designed to create minimal or zero garbage in its critical paths, especially when using binary formats, off-heap `Bytes`, and object reuse patterns.
+Text formats inherently create more garbage (Strings).
What is "off-heap" memory and how does Wire use it? ::
-Off-heap memory is Java direct memory allocated outside the JVM's garbage-collected heap. Chronicle Wire, through `chronicle-bytes`, can serialize directly to and deserialize directly from off-heap `Bytes` buffers, reducing GC pressure.
+Off-heap memory is Java direct memory allocated outside the JVM's garbage-collected heap.
+Chronicle Wire, through `chronicle-bytes`, can serialize directly to and deserialize directly from off-heap `Bytes` buffers, reducing GC pressure.
How can I optimise Chronicle Wire performance? ::
* Choose efficient binary `WireType`s (`BINARY_LIGHT`, `FIELDLESS_BINARY`).
@@ -149,21 +191,28 @@ How can I optimise Chronicle Wire performance? ::
* Be mindful of string creation; use `LongConversion` for short IDs.
Is Chronicle Wire faster than Kryo or Protobuf? ::
-Performance comparisons depend heavily on the specific use case, data structures, and benchmark methodology. Chronicle Wire is generally in the same high-performance league as Kryo and Protobuf, often excelling in scenarios requiring minimal GC and consistent low latency. Each has its strengths.
+Performance comparisons depend heavily on the specific use case, data structures, and benchmark methodology.
+Chronicle Wire is generally in the same high-performance league as Kryo and Protobuf, often excelling in scenarios requiring minimal GC and consistent low latency.
+Each has its strengths.
== Integration
How is Chronicle Wire used in Chronicle Queue? ::
-Chronicle Wire is the serialisation engine for messages stored in Chronicle Queue. It serializes data into queue excerpts (typically in `BINARY_LIGHT` format). The `MethodWriter` and `MethodReader` patterns in Queue use Wire to serialize method calls and arguments.
+Chronicle Wire is the serialisation engine for messages stored in Chronicle Queue.
+It serializes data into queue excerpts (typically in `BINARY_LIGHT` format).
+The `MethodWriter` and `MethodReader` patterns in Queue use Wire to serialize method calls and arguments.
How is Chronicle Wire used in Chronicle Map? ::
-Chronicle Wire is used to serialize keys and values when they are custom Java objects being stored in an off-heap Chronicle Map. Users typically make their keys/values `Marshallable` or `BytesMarshallable`.
+Chronicle Wire is used to serialize keys and values when they are custom Java objects being stored in an off-heap Chronicle Map.
+Users typically make their keys/values `Marshallable` or `BytesMarshallable`.
Can I use Chronicle Wire for network communication? ::
-Yes. While Wire itself is a serialisation library, it's used by `chronicle-network` (and related OpenHFT networking components) to marshal data for sending over TCP/IP or UDP.
+Yes.
+While Wire itself is a serialisation library, it's used by `chronicle-network` (and related OpenHFT networking components) to marshal data for sending over TCP/IP or UDP.
Can I use Chronicle Wire for configuration files? ::
-Yes, `YAML_ONLY` Wire is excellent for creating and parsing human-readable configuration files. Your configuration DTOs can implement `Marshallable`.
+Yes, `YAML_ONLY` Wire is excellent for creating and parsing human-readable configuration files.
+Your configuration DTOs can implement `Marshallable`.
== Troubleshooting & Debugging
@@ -176,7 +225,8 @@ Common causes include:
* No-arg constructor missing for the class being deserialized into (for some paths).
How can I debug binary Chronicle Wire data? ::
-You can often read the binary `Bytes` buffer using a `YAML_ONLY` wire. If the binary format was self-describing enough (like `BINARY_LIGHT`), this will dump the content in a human-readable YAML form.
+You can often read the binary `Bytes` buffer using a `YAML_ONLY` wire.
+If the binary format was self-describing enough (like `BINARY_LIGHT`), this will dump the content in a human-readable YAML form.
`System.out.println(bytes.toHexString());` can also give you a raw view.
What does "Unable to find a marshaller for class..." mean? ::
@@ -196,10 +246,14 @@ Can I create custom `WireType` implementations? ::
Yes, the architecture is extensible, but this is an advanced task requiring a deep understanding of the `Wire` interface and serialisation principles.
How does Chronicle Wire handle circular dependencies in object graphs? ::
-Standard Chronicle Wire object marshalling is primarily designed for tree-like structures or DAGs. Deeply nested circular dependencies can cause issues (like `StackOverflowError`) if not handled carefully. For complex graphs, you might need custom marshalling logic or to break cycles.
+Standard Chronicle Wire object marshalling is primarily designed for tree-like structures or DAGs.
+Deeply nested circular dependencies can cause issues (like `StackOverflowError`) if not handled carefully.
+For complex graphs, you might need custom marshalling logic or to break cycles.
What is `READ_ANY` WireType useful for? ::
-`READ_ANY` attempts to heuristically determine the format of the incoming data (e.g., YAML, JSON, common Binary variants) and deserialize it. It's useful when a consumer needs to be flexible about the format of data it receives.
+`READ_ANY` attempts to heuristically determine the format of the incoming data (e.g., YAML, JSON, common Binary variants) and deserialize it.
+It's useful when a consumer needs to be flexible about the format of data it receives.
How does class aliasing work (e.g., `Wires.CLASS_ALIASES.addAlias(...)`)? ::
-Class aliasing allows you to use short names (aliases) in the serialized output (especially text formats like YAML) instead of fully qualified class names. This makes the output cleaner and can help if you refactor class names or packages, as the alias in the data can remain stable.
\ No newline at end of file
+Class aliasing allows you to use short names (aliases) in the serialized output (especially text formats like YAML) instead of fully qualified class names.
+This makes the output cleaner and can help if you refactor class names or packages, as the alias in the data can remain stable.
diff --git a/src/main/docs/wire-glossary.adoc b/src/main/docs/wire-glossary.adoc
index bbd405b2f8..e8b4a7cb26 100644
--- a/src/main/docs/wire-glossary.adoc
+++ b/src/main/docs/wire-glossary.adoc
@@ -1,11 +1,12 @@
-
= Chronicle Wire Glossary
:toc:
+:lang: en-GB
:toclevels: 2
:source-highlighter: rouge
-:icons: font
:sectnums:
+:lang: en-GB
+
Purpose: To provide clear definitions for common terms and concepts used in Chronicle Wire and its related ecosystem.
[glossary]
@@ -13,11 +14,13 @@ Purpose: To provide clear definitions for common terms and concepts used in Chro
[glossaryentry]
Annotation ::
-In Java, a form of metadata that can be added to code elements (classes, methods, fields). Chronicle Wire uses annotations (e.g., `@LongConversion`, `@NanoTime`, `@FieldNumber`) to declaratively control serialisation behaviour.
+In Java, a form of metadata that can be added to code elements (classes, methods, fields).
+Chronicle Wire uses annotations (e.g., `@LongConversion`, `@NanoTime`, `@FieldNumber`) to declaratively control serialisation behaviour.
[glossaryentry]
ASCII-7 ::
-A 7-bit character encoding standard representing 128 characters, primarily English letters, digits, and common punctuation. Relevant for ensuring text-based wire formats are universally readable.
+A 7-bit character encoding standard representing 128 characters, primarily English letters, digits, and common punctuation.
+Often used as a subset of ISO-8859-1 to keep text-based wire formats universally readable.
[glossaryentry]
AtomicLong ::
@@ -27,19 +30,24 @@ A Java class (`java.util.concurrent.atomic.AtomicLong`) that provides atomic ope
[glossaryentry]
Base64 / Base85 ::
-Encoding schemes that represent binary data in an ASCII string format. In Chronicle Wire, `@Base64` and `@Base85` annotations (via `@LongConversion`) allow short strings to be compactly stored in `long` fields.
+Encoding schemes that represent binary data in an ASCII string format.
+In Chronicle Wire, `@Base64` and `@Base85` annotations (via `@LongConversion`) allow short strings to be compactly stored in `long` fields.
[glossaryentry]
Binary Format ::
-A data representation that stores information as sequences of bytes, not directly human-readable without tools. Chronicle Wire offers several binary formats (e.g., `BINARY_LIGHT`, `FIELDLESS_BINARY`) optimised for performance and compactness.
+A data representation that stores information as sequences of bytes, not directly human-readable without tools.
+Chronicle Wire offers several binary formats (e.g., `BINARY_LIGHT`, `FIELDLESS_BINARY`) optimised for performance and compactness.
[glossaryentry]
`Bytes` ::
-A core abstraction from the `chronicle-bytes` library representing a sequence of bytes. It can wrap on-heap byte arrays, off-heap direct memory, or memory-mapped files. All `Wire` implementations operate on a `Bytes` instance.
+A core abstraction from the `chronicle-bytes` library representing a sequence of bytes.
+It can wrap on-heap byte arrays, off-heap direct memory, or memory-mapped files.
+All `Wire` implementations operate on a `Bytes` instance.
[glossaryentry]
`BytesMarshallable` ::
-An interface in Chronicle Wire that allows objects to have complete control over their serialisation and deserialisation logic directly at the `Bytes` level. This is used for maximum performance or when a very specific binary layout is required.
+An interface in Chronicle Wire that allows objects to have complete control over their serialisation and deserialisation logic directly at the `Bytes` level.
+This is used for maximum performance or when a very specific binary layout is required.
[glossaryentry]
`BytesStore` ::
@@ -49,15 +57,18 @@ An interface from `chronicle-bytes` representing the underlying storage for a `B
[glossaryentry]
Chronicle Bytes ::
-A low-level Java library from OpenHFT providing high-performance, off-heap and on-heap byte buffer manipulation capabilities. It's a foundational component for Chronicle Wire.
+A low-level Java library from OpenHFT providing high-performance, off-heap and on-heap byte buffer manipulation capabilities.
+It's a foundational component for Chronicle Wire.
[glossaryentry]
Chronicle Map ::
-An OpenHFT library providing an off-heap, persisted, and optionally IPC-shared key-value store (a concurrent hash map). Chronicle Wire is often used to serialise keys and values for Chronicle Map.
+An OpenHFT library providing an off-heap, persisted, and optionally IPC-shared key-value store (a concurrent hash map).
+Chronicle Wire is often used to serialise keys and values for Chronicle Map.
[glossaryentry]
Chronicle Queue ::
-An OpenHFT library providing a persisted, low-latency, high-throughput messaging queue. Chronicle Wire is its internal serialisation engine for messages (excerpts).
+An OpenHFT library providing a persisted, low-latency, high-throughput messaging queue.
+Chronicle Wire is its internal serialisation engine for messages (excerpts).
[glossaryentry]
Chronicle Wire ::
@@ -69,7 +80,8 @@ A mechanism in Chronicle Wire (e.g., via `Wires.CLASS_ALIASES`) to use a short,
[glossaryentry]
Compactness ::
-Refers to how little space the serialised data occupies. Binary formats are generally more compact than text formats.
+Refers to how little space the serialised data occupies.
+Binary formats are generally more compact than text formats.
[glossaryentry]
Converter (`LongConverter`, etc.) ::
@@ -83,11 +95,13 @@ The process of converting data from a serialised format (e.g., a byte stream, JS
[glossaryentry]
`DocumentContext` ::
-An interface in Chronicle Wire used to manage the boundaries of individual messages or "documents" when streaming multiple items. It ensures messages are correctly framed and provides metadata about the current document.
+An interface in Chronicle Wire used to manage the boundaries of individual messages or "documents" when streaming multiple items.
+It ensures messages are correctly framed and provides metadata about the current document.
[glossaryentry]
DTO (Data Transfer Object) ::
-A simple object used to pass data between layers or components. `Marshallable` POJOs in Chronicle Wire often serve as DTOs.
+A simple object used to pass data between layers or components.
+`Marshallable` POJOs in Chronicle Wire often serve as DTOs.
== E
@@ -97,17 +111,20 @@ Refers to `Bytes` instances that can automatically resize (expand) as more data
[glossaryentry]
Excerpt ::
-A term used in Chronicle Queue representing a single message or record within the queue. Each excerpt's content is serialised using Chronicle Wire.
+A term used in Chronicle Queue representing a single message or record within the queue.
+Each excerpt's content is serialised using Chronicle Wire.
== F
[glossaryentry]
`FIELDLESS_BINARY` ::
-A `WireType` in Chronicle Wire that produces an extremely compact binary representation by omitting all field names or identifiers. It requires the reader and writer to have an identical, fixed schema.
+A `WireType` in Chronicle Wire that produces an extremely compact binary representation by omitting all field names or identifiers.
+It requires the reader and writer to have an identical, fixed schema.
[glossaryentry]
Fluent API ::
-A style of object-oriented API design where method calls are chained together (e.g., `object.setA(1).setB("text").setC(true)`), often with methods returning the instance itself (`this`). Chronicle Wire's `ValueIn` and `ValueOut` provide a fluent API.
+A style of object-oriented API design where method calls are chained together (e.g., `object.setA(1).setB("text").setC(true)`), often with methods returning the instance itself (`this`).
+Chronicle Wire's `ValueIn` and `ValueOut` provide a fluent API.
[glossaryentry]
Format Agnosticism ::
@@ -117,7 +134,8 @@ A key feature of Chronicle Wire where the application's serialisation logic (e.g
[glossaryentry]
Garbage Collection (GC) ::
-The process by which a Java Virtual Machine (JVM) automatically reclaims memory occupied by objects that are no longer in use. Chronicle Wire is designed to minimise GC overhead.
+The process by which a Java Virtual Machine (JVM) automatically reclaims memory occupied by objects that are no longer in use.
+Chronicle Wire is designed to minimise GC overhead.
== H
@@ -129,7 +147,8 @@ A data format (like YAML or JSON) that can be easily read and understood by huma
[glossaryentry]
Inter-Process Communication (IPC) ::
-Mechanisms that allow different processes, potentially running on the same machine, to exchange data and synchronise. Chronicle Queue (using Wire) is a common tool for high-performance IPC.
+Mechanisms that allow different processes, potentially running on the same machine, to exchange data and synchronise.
+Chronicle Queue (using Wire) is a common tool for high-performance IPC.
[glossaryentry]
ISO 8601 ::
@@ -139,13 +158,16 @@ An international standard for representing dates and times as strings, commonly
[glossaryentry]
JSON (JavaScript Object Notation) ::
-A lightweight, human-readable data-interchange format. Chronicle Wire supports JSON as a `WireType`.
+A lightweight, human-readable data-interchange format.
+Chronicle Wire supports JSON as a `WireType`.
== L
[glossaryentry]
Latency ::
-The time delay between a cause and its effect. In serialisation, it can refer to the time taken to convert an object to bytes or vice-versa. Chronicle Wire aims for very low latency.
+The time delay between a cause and its effect.
+In serialisation, it can refer to the time taken to convert an object to bytes or vice-versa.
+Chronicle Wire aims for very low latency.
[glossaryentry]
`LongConversion` ::
@@ -155,7 +177,8 @@ An annotation in Chronicle Wire used to specify that a `long` field should be co
[glossaryentry]
`Marshallable` ::
-An interface in Chronicle Wire that objects implement to indicate they can be serialised and deserialised. It defines `readMarshallable(WireIn)` and `writeMarshallable(WireOut)` methods.
+An interface in Chronicle Wire that objects implement to indicate they can be serialised and deserialised.
+It defines `readMarshallable(WireIn)` and `writeMarshallable(WireOut)` methods.
[glossaryentry]
Marshalling ::
@@ -163,7 +186,8 @@ Another term for serialisation; the process of transforming an in-memory object
[glossaryentry]
Memory-Mapped File ::
-A segment of virtual memory that has been assigned a direct byte-for-byte correlation with some portion of a file or file-like resource. Used by Chronicle Queue for persistence and efficient I/O.
+A segment of virtual memory that has been assigned a direct byte-for-byte correlation with some portion of a file or file-like resource.
+Used by Chronicle Queue for persistence and efficient I/O.
[glossaryentry]
`MethodReader` ::
@@ -181,13 +205,15 @@ An annotation in Chronicle Wire used to format a `long` timestamp (representing
[glossaryentry]
Null Safety ::
-Handling of null values during serialisation and deserialisation. Chronicle Wire can represent nulls.
+Handling of null values during serialisation and deserialisation.
+Chronicle Wire can represent nulls.
== O
[glossaryentry]
Off-Heap Memory ::
-Memory allocated outside the standard JVM garbage-collected heap, typically using `java.nio.ByteBuffer.allocateDirect()` or similar. Chronicle Wire extensively uses off-heap memory via `chronicle-bytes` to reduce GC pauses.
+Memory allocated outside the standard JVM garbage-collected heap, typically using `java.nio.ByteBuffer.allocateDirect()` or similar.
+Chronicle Wire extensively uses off-heap memory via `chronicle-bytes` to reduce GC pauses.
[glossaryentry]
OpenHFT (Open High-Frequency Trading) ::
@@ -197,11 +223,14 @@ The open-source project and community that develops Chronicle Wire and other rel
[glossaryentry]
POJO (Plain Old Java Object) ::
-A simple Java object not bound by any special restriction or framework other than those of the Java Language Specification itself. `Marshallable` objects are often POJOs.
+A simple Java object not bound by any special restriction or framework other than those of the Java Language Specification itself.
+`Marshallable` objects are often POJOs.
[glossaryentry]
Polymorphism ::
-The ability of an object to take on many forms. In serialisation, this relates to deserialising data into the correct concrete subclass when the exact type is not known beforehand. `YAML_RETAIN_TYPE` or `JSON_RETAIN_TYPE` help with this.
+The ability of an object to take on many forms.
+In serialisation, this relates to deserialising data into the correct concrete subclass when the exact type is not known beforehand.
+`YAML_RETAIN_TYPE` or `JSON_RETAIN_TYPE` help with this.
== R
@@ -215,7 +244,8 @@ A special `WireType` that attempts to heuristically detect and read data from an
[glossaryentry]
Reflection ::
-A Java API that allows a program to inspect and manipulate its own structure (classes, methods, fields) at runtime. Chronicle Wire can use reflection for default marshalling but often prefers code generation for performance.
+A Java API that allows a program to inspect and manipulate its own structure (classes, methods, fields) at runtime.
+Chronicle Wire can use reflection for default marshalling but often prefers code generation for performance.
== S
@@ -233,11 +263,14 @@ The ability to change the schema of data over time (e.g., add or remove fields)
[glossaryentry]
`SelfDescribingMarshallable` ::
-A convenient abstract base class in Chronicle Wire that implements `Marshallable`. It provides automatic field serialisation and default `toString()`, `equals()`, and `hashCode()` methods.
+A convenient abstract base class in Chronicle Wire that implements `Marshallable`.
+It provides automatic field serialisation and default `toString()`, `equals()`, and `hashCode()` methods.
[glossaryentry]
Self-Describing Format ::
-A data format where metadata (like field names or type information) is included alongside the data itself. This aids in schema evolution and human readability. YAML, JSON, and some Chronicle Wire binary formats are self-describing.
+A data format where metadata (like field names or type information) is included alongside the data itself.
+This aids in schema evolution and human readability.
+YAML, JSON, and some Chronicle Wire binary formats are self-describing.
[glossaryentry]
Serialisation ::
@@ -245,11 +278,13 @@ The process of converting an in-memory object into a stream of bytes or a textua
[glossaryentry]
Stop-Bit Encoding (VarInts/VarLongs) ::
-A variable-length encoding scheme for integers where smaller numeric values use fewer bytes. Used in Chronicle Wire binary formats for efficiency.
+A variable-length encoding scheme for integers where smaller numeric values use fewer bytes.
+Used in Chronicle Wire binary formats for efficiency.
[glossaryentry]
Streaming API ::
-An API that processes data as a continuous flow or sequence of items, rather than loading everything into memory at once. Chronicle Wire's `DocumentContext` supports a streaming model for messages.
+An API that processes data as a continuous flow or sequence of items, rather than loading everything into memory at once.
+Chronicle Wire's `DocumentContext` supports a streaming model for messages.
== T
@@ -263,7 +298,8 @@ The rate at which data can be processed, often measured in messages per second o
[glossaryentry]
Trivially Copyable Object ::
-An object whose in-memory representation can be directly copied to its serialised form (and vice-versa) with minimal transformation, typically involving only primitive fields. This is an advanced optimisation.
+An object whose in-memory representation can be directly copied to its serialised form (and vice-versa) with minimal transformation, typically involving only primitive fields.
+This is an advanced optimisation.
== V
@@ -275,7 +311,8 @@ Fluent API interfaces provided by `Wire` for reading (`ValueIn`) and writing (`V
[glossaryentry]
`Wire` ::
-The central interface in Chronicle Wire for reading and writing structured data in a specific format. Concrete implementations include `YamlWire`, `BinaryWire`, etc.
+The central interface in Chronicle Wire for reading and writing structured data in a specific format.
+Concrete implementations include `YamlWire`, `BinaryWire`, etc.
[glossaryentry]
`WireType` ::
@@ -285,14 +322,17 @@ An enum in Chronicle Wire that defines and acts as a factory for different seria
[glossaryentry]
YAML (YAML Ain't Markup Language) ::
-A human-friendly data serialisation standard for all programming languages. Chronicle Wire supports YAML as a `WireType`.
+A human-friendly data serialisation standard for all programming languages.
+Chronicle Wire supports YAML as a `WireType`.
== Z
[glossaryentry]
Zero-Copy ::
-A technique that aims to eliminate memory copying when transferring data between different parts of a system (e.g., from a file to a network socket, or between kernel space and user space). Chronicle Wire's use of off-heap memory and direct buffers facilitates zero-copy principles in conjunction with libraries like Chronicle Queue.
+A technique that aims to eliminate memory copying when transferring data between different parts of a system (e.g., from a file to a network socket, or between kernel space and user space).
+Chronicle Wire's use of off-heap memory and direct buffers facilitates zero-copy principles in conjunction with libraries like Chronicle Queue.
[glossaryentry]
Zero GC / Minimal GC ::
-A design goal to create as little garbage as possible during program execution to minimise the frequency and duration of Garbage Collection pauses, crucial for low-latency applications. Chronicle Wire is designed with this principle in mind.
+A design goal to create as little garbage as possible during program execution to minimise the frequency and duration of Garbage Collection pauses, crucial for low-latency applications.
+Chronicle Wire is designed with this principle in mind.
diff --git a/src/main/docs/wire-schema-evolution.adoc b/src/main/docs/wire-schema-evolution.adoc
index 90b34776eb..8eb7054fe6 100644
--- a/src/main/docs/wire-schema-evolution.adoc
+++ b/src/main/docs/wire-schema-evolution.adoc
@@ -1,9 +1,11 @@
= Chronicle Wire: Schema Evolution Deep Dive
:toc:
+:lang: en-GB
:source-highlighter: rouge
Purpose: To provide an in-depth exploration of schema evolution capabilities and mechanisms within Chronicle Wire, including implementation details and advanced strategies.
:sectnums:
+:lang: en-GB
== Introduction to Schema Evolution in Chronicle Wire
@@ -13,10 +15,12 @@ For systems that store data long-term or communicate across different service ve
Chronicle Wire's approach to schema evolution is rooted in its flexible, format-agnostic design:
-* **Philosophy:** It generally favors flexibility, particularly with its self-describing formats (like YAML, JSON, and `BINARY_LIGHT`).
+Philosophy ::
+It generally favors flexibility, particularly with its self-describing formats (like YAML, JSON, and `BINARY_LIGHT`).
These formats inherently carry metadata (field names or numbers) that allows for a degree of tolerance to schema changes.
Conversely, highly optimised, non-self-describing formats like `FIELDLESS_BINARY` offer minimal to no schema evolution support by design, prioritising raw speed and compactness.
-* **No Central Schema Registry:** Unlike systems like Apache Avro or Google Protocol Buffers, Chronicle Wire does not typically rely on separately defined schema files (e.g., `.avsc` or `.proto`).
+No Central Schema Registry ::
+Unlike systems like Apache Avro or Google Protocol Buffers, Chronicle Wire does not typically rely on separately defined schema files (e.g., `.avsc` or `.proto`).
The Java class definition (often a `Marshallable` object) itself serves as the primary schema definition.
Evolution is managed by how these class definitions change and how the chosen `WireType` interprets those changes against existing serialised data.
@@ -60,9 +64,11 @@ This mapping is generally case-sensitive but can sometimes be influenced by inte
`BINARY_LIGHT` / `BINARY` Formats ::
* These formats can store either the full field name (more verbose, similar to text but in binary) or, more commonly for efficiency, a numeric field identifier.
-* **Field Numbers:** When field numbers are used (often via the `@FieldNumber` annotation), a compact representation of this number (e.g., stop-bit encoded for small numbers) is written to the wire preceding the field's data.
+Field Numbers ::
+When field numbers are used (often via the `@FieldNumber` annotation), a compact representation of this number (e.g., stop-bit encoded for small numbers) is written to the wire preceding the field's data.
This numeric tag uniquely identifies the field.
-* **Field Names:** If full field names are used, they are typically written as length-prefixed UTF-8 strings.
+Field Names ::
+If full field names are used, they are typically written as length-prefixed UTF-8 strings.
* Each field entry generally consists of this identifier (name or number), potentially some type information or length indication for the data itself, followed by the serialised field value.
ifdef::env-github[[source,mermaid]
@@ -91,13 +97,15 @@ graph TD
=== Handling Unknown Fields (Forward Compatibility)
-*Forward compatibility* means that older code (a reader with an older schema version) can process data written by newer code (a writer with a newer schema version that includes additional fields).
+_Forward compatibility_ means that older code (a reader with an older schema version) can process data written by newer code (a writer with a newer schema version that includes additional fields).
Mechanism ::
* When a Chronicle Wire reader encounters a field name or field number in the input stream that does not exist in its current class definition, it will attempt to skip over that field's data.
-* **Skipping Data in Text Formats:** For YAML/JSON, this involves parsing past the unknown key and its entire associated value (which could be a simple scalar, a list, or a nested object).
+Skipping Data in Text Formats ::
+For YAML/JSON, this involves parsing past the unknown key and its entire associated value (which could be a simple scalar, a list, or a nested object).
The parser understands the structure to know where the unknown field ends.
-* **Skipping Data in Binary Formats:** The `Wire` implementation must be able to determine the length of the unknown field's data to skip it.
+Skipping Data in Binary Formats ::
+The `Wire` implementation must be able to determine the length of the unknown field's data to skip it.
This is often achieved because:
** The field's type might be encoded, implying a known fixed length (e.g., `int` is 4 bytes).
** Variable-length data (like strings, nested objects, or sequences) is typically length-prefixed.
@@ -109,7 +117,7 @@ Performance impact of skipping is generally minimal unless there are very many l
=== Handling Missing Fields (Backward Compatibility)
-*Backward compatibility* means that newer code (a reader with a newer schema version that expects more fields) can process data written by older code (a writer with an older schema version that omits some of these fields).
+_Backward compatibility_ means that newer code (a reader with a newer schema version that expects more fields) can process data written by older code (a writer with an older schema version that omits some of these fields).
Primary Mechanism :: A default constructor is used.
* When there is a default constructor for the Java class, a sample instance is created to define the default value for each field.
@@ -137,7 +145,7 @@ if (this.myList == null) {
=== Reordering Fields
-In self-describing formats (text or binary with field names/numbers), the physical order of fields in the serialised data stream generally does *not* need to match the declaration order in the Java class.
+In self-describing formats (text or binary with field names/numbers), the physical order of fields in the serialised data stream generally does _not_ need to match the declaration order in the Java class.
Deserialisation maps fields based on their identified names or numbers.
This provides flexibility in how data is written or how classes are refactored.
@@ -147,30 +155,30 @@ Changing the data type of an existing field is the most complex part of schema e
Chronicle Wire provides limited automatic coercion.
Scenarios and Wire Behaviour ::
-* **Widening Primitives (e.g., `int` in data, `long` in class):**
-** **Text Formats:** Often handled gracefully, as text "123" can be parsed into an `int` or a `long`.
-** **Binary Formats:** If the binary format stores the `int` as, say, 4 bytes, and the class expects a `long`, the `Wire` implementation *might* promote it (e.g., read 4 bytes, convert to long).
+Widening Primitives (e.g., `int` in data, `long` in class) ::
+* *Text Formats:* Often handled gracefully, as text "123" can be parsed into an `int` or a `long`.
+* *Binary Formats:* If the binary format stores the `int` as, say, 4 bytes, and the class expects a `long`, the `Wire` implementation _might_ promote it (e.g., read 4 bytes, convert to long).
However, this depends on the specific `WireType` and its internal logic.
It's safer to assume this needs testing.
-* **Narrowing Primitives (e.g., `long` in data, `int` in class):**
-** **Text Formats:** If the textual representation of the long value fits into an `int`, parsing might succeed.
+Narrowing Primitives (e.g., `long` in data, `int` in class) ::
+* *Text Formats:* If the textual representation of the long value fits into an `int`, parsing might succeed.
If it's out of range for `int`, a `NumberFormatException` or similar parsing error is likely.
-** **Binary Formats:** Reading a `long` (8 bytes) into an `int` (4 bytes) field is problematic.
+* *Binary Formats:* Reading a `long` (8 bytes) into an `int` (4 bytes) field is problematic.
Chronicle Wire will likely throw an error or read incorrect data, as it would attempt to read only 4 bytes for the `int` field, leaving the remaining 4 bytes of the long unread or misinterpreting them as the start of the next field.
Data loss or corruption is highly probable without custom handling.
-* **Changing Numeric Type (e.g., `int` to `double`):**
-** **Text Formats:** "123" can be parsed as an `int` or `double`. `123.45` cannot be parsed as an `int`.
-** **Binary Formats:** `int` and `double` have different binary representations.
+Changing Numeric Type (e.g., `int` to `double`) ::
+* *Text Formats:* "123" can be parsed as an `int` or `double`. `123.45` cannot be parsed as an `int`.
+* *Binary Formats:* `int` and `double` have different binary representations.
Automatic conversion is unlikely; this would typically lead to errors or misinterpretation.
-* **Changing To/From `String` (e.g., `int` in data, `String` in class):**
-** **Text Formats:** Reading a numeric literal like `123` into a `String` field is usually fine (`"123"`).
+Changing To/From `String` (e.g., `int` in data, `String` in class) ::
+* *Text Formats:* Reading a numeric literal like `123` into a `String` field is usually fine (`"123"`).
Reading a string like `"abc"` into an `int` field will fail.
-** **Binary Formats:** No automatic conversion.
+* *Binary Formats:* No automatic conversion.
The wire expects a binary representation of an `int` versus a binary representation of a string (e.g., length-prefixed UTF-8).
-* **Changing Complex Types (e.g., `OldType` to `NewType`, or `List` to `List`):**
-** Chronicle Wire will automatically convert between different custom `Marshallable` types, even if they are structurally different.
+Changing Complex Types (e.g., `OldType` to `NewType`, or `List` to `List`) ::
+* Chronicle Wire will automatically convert between different custom `Marshallable` types, even if they are structurally different.
This can leave all fields as default if there are no matches.
-** Conversion from scalar to marshallable or vise versa is not automatic.
+* Conversion from scalar to marshallable or vise versa is not automatic.
For example, reading a `String` into a `List` field will not work without custom logic.
Strategy :: When a field type must change, the safest approach is often to:
@@ -184,7 +192,8 @@ Strategy :: When a field type must change, the safest approach is often to:
The `FIELDLESS_BINARY` `WireType` is designed for extreme performance and compactness by omitting all field names and numbers.
-* **Mechanism:** Data is written as a direct sequence of field values in the exact order they are declared in the `Marshallable` class.
+Mechanism ::
+Data is written as a direct sequence of field values in the exact order they are declared in the `Marshallable` class.
+
[source,java]
----
@@ -194,12 +203,15 @@ class MyFieldlessData extends SelfDescribingMarshallable {
// Wire output is just: (binary int for fieldA)(binary long for fieldB)
}
----
-* **Brittleness:** This format is *extremely* intolerant of schema changes:
-** **Order Matters:** Changing the order of fields in the class breaks deserialisation.
-** **Type Matters:** Changing a field's type (e.g., `int` to `long`) breaks deserialisation as the number of bytes read/written will mismatch.
-** **Count Matters:** Adding or removing fields breaks deserialisation.
-* **Consequences of Mismatch:** `BufferUnderflowException`, `BufferOverflowException`, reading garbage data, or application-level errors due to incorrect field values.
-* **Strategies for Versioning with `FIELDLESS_BINARY`:**
+
+Brittleness ::
+This format is _extremely_ intolerant of schema changes:
+* *Order Matters:* Changing the order of fields in the class breaks deserialisation.
+* *Type Matters:* Changing a field's type (e.g., `int` to `long`) breaks deserialisation as the number of bytes read/written will mismatch.
+* *Count Matters:* Adding or removing fields breaks deserialisation.
+Consequences of Mismatch ::
+`BufferUnderflowException`, `BufferOverflowException`, reading garbage data, or application-level errors due to incorrect field values.
+Strategies for Versioning with `FIELDLESS_BINARY` ::
Explicit Version Field :: Include a version number as the very first field.
The reader reads this version first and then uses different `Marshallable` class definitions or parsing logic based on this version.
@@ -226,33 +238,42 @@ Annotations provide metadata that Chronicle Wire uses to manage schema evolution
Status :: Road Map
-* **Deep Dive:** When using `BINARY_LIGHT` or `BINARY` wire that supports numbered fields, this annotation assigns a persistent numeric ID to a Java field.
+Deep Dive ::
+When using `BINARY_LIGHT` or `BINARY` wire that supports numbered fields, this annotation assigns a persistent numeric ID to a Java field.
The wire format will store this number instead of (or sometimes alongside) the textual field name.
-* **Mechanism:** During serialisation, the `WireMarshaller` looks for this annotation.
+Mechanism ::
+During serialisation, the `WireMarshaller` looks for this annotation.
If present, it instructs the binary `Wire` implementation to write the specified number as the field tag.
During deserialisation, the binary `Wire` reads the numeric tag and the `WireMarshaller` uses an internal map (numeric tag -> Java Field object) to find the corresponding field to populate.
-* **Benefit:** This decouples the on-wire field identifier from the Java field's textual name, allowing the Java field to be renamed without breaking binary compatibility.
+Benefit ::
+This decouples the on-wire field identifier from the Java field's textual name, allowing the Java field to be renamed without breaking binary compatibility.
The numeric ID remains the contract.
-* **Requirement:** Field numbers must be unique within the scope of the class being serialised.
+Requirement ::
+Field numbers must be unique within the scope of the class being serialised.
=== `@DeprecatedWireKey(String[] oldKeys)` (and alternatives like `Wires.FIELD_RENAME_MAP`)
Status :: Road Map
-* **Deep Dive:** This addresses field renaming primarily for *text-based* formats (YAML, JSON) or binary formats that store textual field names.
-* **Mechanism (Conceptual for `@DeprecatedWireKey`):** During deserialisation, if the `WireMarshaller` encounters a field name in the input stream that matches one of the `oldKeys` specified in an `@DeprecatedWireKey` annotation on a field, it will map the value to that annotated Java field (which now has a new name).
-* **`Wires.FIELD_RENAME_MAP`:** This static map provides a programmatic way to declare renames: `Wires.FIELD_RENAME_MAP.put(OldClassName.class.getName() + ".oldFieldName", "newFieldName");`.
+Deep Dive ::
+This addresses field renaming primarily for _text-based_ formats (YAML, JSON) or binary formats that store textual field names.
+Mechanism (Conceptual for `@DeprecatedWireKey`) ::
+During deserialisation, if the `WireMarshaller` encounters a field name in the input stream that matches one of the `oldKeys` specified in an `@DeprecatedWireKey` annotation on a field, it will map the value to that annotated Java field (which now has a new name).
+`Wires.FIELD_RENAME_MAP` ::
+This static map provides a programmatic way to declare renames: `Wires.FIELD_RENAME_MAP.put(OldClassName.class.getName() + ".oldFieldName", "newFieldName");`.
The marshaller consults this map.
-* **Benefit:** Allows graceful renaming of fields in Java code while still being able to read older data that uses the previous field names.
-* **Note:** When writing, the *current* Java field name is typically used.
+Benefit ::
+Allows graceful renaming of fields in Java code while still being able to read older data that uses the previous field names.
+Note ::
+When writing, the _current_ Java field name is typically used.
== Advanced Strategies and Implementation Considerations
For complex schema migrations beyond simple field additions/removals or renames supported by annotations, more advanced strategies are required.
Custom `readMarshallable` / `writeMarshallable` Implementations::
-** This is the most powerful way to handle complex schema changes.
-** **Reading Old Versions:** Inside `readMarshallable(WireIn wire)` of a newer class version, you can inspect the incoming wire for tell-tale signs of an older version (e.g., presence/absence of certain fields, an explicit version field).
+* This is the most powerful way to handle complex schema changes.
+* *Reading Old Versions:* Inside `readMarshallable(WireIn wire)` of a newer class version, you can inspect the incoming wire for tell-tale signs of an older version (e.g., presence/absence of certain fields, an explicit version field).
Based on this, you can have conditional logic to read fields that existed in the old version and map/transform them to the new structure.
+
[source,java]
@@ -267,42 +288,42 @@ if (wire.read("anotherOldFieldToBeRemoved").isPresent()) {
wire.getValueIn().skipValue(); // Skip it if it's no longer needed
}
----
-** **Writing for Forward/Backward Compatibility:** When writing, you might choose to write data in a way that newer readers can fully utilise but older readers can still partially understand (by gracefully skipping new parts).
-Or, for a transition period, you might write *both* old and new representations of a changed field.
+* *Writing for Forward/Backward Compatibility:* When writing, you might choose to write data in a way that newer readers can fully utilise but older readers can still partially understand (by gracefully skipping new parts).
+Or, for a transition period, you might write _both_ old and new representations of a changed field.
Explicit Version Field ::
-** A common robust strategy is to include an explicit `schemaVersion` integer field as the first field in every `Marshallable` object.
-** **Writing:** Always write the current schema version of the class.
-** **Reading:**
+* A common robust strategy is to include an explicit `schemaVersion` integer field as the first field in every `Marshallable` object.
+* *Writing:* Always write the current schema version of the class.
+* *Reading:*
. Read the `schemaVersion` field first.
. Based on this version, either:
-** Instantiate a specific `V1_Object.class`, `V2_Object.class`, etc. and deserialise into that.
-** Use a single class with conditional logic in `readMarshallable` that adapts to the `schemaVersion` found.
-** Use a factory or strategy pattern to delegate to different parsing logic.
-** This makes schema changes explicit and manageable.
+* Instantiate a specific `V1_Object.class`, `V2_Object.class`, etc. and deserialise into that.
+* Use a single class with conditional logic in `readMarshallable` that adapts to the `schemaVersion` found.
+* Use a factory or strategy pattern to delegate to different parsing logic.
+* This makes schema changes explicit and manageable.
`WireParselet` (for Text Formats) ::
-** A `WireParselet` is a functional interface `(s, v) -> {}` where `s` is a `CharSequence` (the field name/key) and `v` is a `ValueIn`.
+* A `WireParselet` is a functional interface `(s, v) -> {}` where `s` is a `CharSequence` (the field name/key) and `v` is a `ValueIn`.
You can provide a `WireParselet` to certain Wire methods (e.g., `wire.read().applyToMarshallable(parselet)`).
-** This allows for completely custom parsing logic for text-based formats.
+* This allows for completely custom parsing logic for text-based formats.
You can inspect field names, skip fields, transform values, or build up your object graph manually.
It's powerful for very complex transformations or when dealing with loosely structured text data.
Offline Data Migration ::
-** For major, incompatible schema changes, especially with large existing datasets (e.g., in Chronicle Queue or Map), an offline migration process might be necessary.
-** This involves writing a dedicated utility that:
+* For major, incompatible schema changes, especially with large existing datasets (e.g., in Chronicle Queue or Map), an offline migration process might be necessary.
+* This involves writing a dedicated utility that:
. Reads data using the old schema definition (`OldType.class`).
. Transforms the `OldType` instances into `NewType` instances (applying necessary business logic).
. Writes the `NewType` instances to a new data store (new queue, new map, or overwriting).
-** Chronicle Wire itself provides the tools for the reading (V1) and writing (V2) parts of this process.
+* Chronicle Wire itself provides the tools for the reading (V1) and writing (V2) parts of this process.
Diagnostic Flags (e.g., `Wires.WARN_ON_UNUSED_NOTES`) ::
-** Setting flags like `Wires.WARN_ON_UNUSED_NOTES = true;` can cause Chronicle Wire to log warnings if it encounters fields in the input stream that are not consumed by the reader's class.
+* Setting flags like `Wires.WARN_ON_UNUSED_NOTES = true;` can cause Chronicle Wire to log warnings if it encounters fields in the input stream that are not consumed by the reader's class.
This can help identify unexpected fields or schema discrepancies during development and testing.
(Check specific flags and their current status in your Wire version).
ClassAlias` and Evolution ::
-** When class names or packages are refactored, `Wires.CLASS_ALIASES.addAlias(NewClass.class, "OldSerializedName")` or `Wires.CLASS_ALIASES.addAlias(NewClass.class, OldClass.class.getName())` allows data serialised with the old class name (if the name was embedded, e.g., in YAML with type retention) to be deserialised into the new class.
+* When class names or packages are refactored, `Wires.CLASS_ALIASES.addAlias(NewClass.class, "OldSerializedName")` or `Wires.CLASS_ALIASES.addAlias(NewClass.class, OldClass.class.getName())` allows data serialised with the old class name (if the name was embedded, e.g., in YAML with type retention) to be deserialised into the new class.
This decouples the on-wire type identifier from the physical Java class name.
== Best Practices for Evolvable Schemas
@@ -319,7 +340,7 @@ Avoid Removing Fields if Possible :: If a field must be removed, ensure readers
Consider deprecating it first.
Be Extremely Cautious with Type Changes :: Changing the fundamental type of a field (e.g., `int` to `String`, `String` to a complex type) usually requires custom migration logic or a new field strategy.
-Simple widening of primitives (e.g., `int` to `long`) *may* work but needs thorough testing with the specific `WireType`.
+Simple widening of primitives (e.g., `int` to `long`) _may_ work but needs thorough testing with the specific `WireType`.
Consider Explicit Versioning :: For complex objects or critical data, embed a `schemaVersion` field within your `Marshallable` objects and use it to drive deserialisation logic.
diff --git a/src/main/docs/wire-visual-guide.adoc b/src/main/docs/wire-visual-guide.adoc
index e37ae1e1fa..540e048cac 100644
--- a/src/main/docs/wire-visual-guide.adoc
+++ b/src/main/docs/wire-visual-guide.adoc
@@ -1,9 +1,10 @@
= Chronicle Wire: Visual Guide
:toc:
+:sectnums:
+:lang: en-GB
:source-highlighter: rouge
Purpose: To provide visual representations of key concepts, processes, and components in the Chronicle Wire library.
-:sectnums:
== Introduction
@@ -209,4 +210,4 @@ graph TD
* link:wire-schema-evolution.adoc[Schema Evolution] - How to evolve your data structures over time
* link:wire-error-handling.adoc[Error Handling and Diagnostics] - Troubleshooting and error handling
* link:wire-faq.adoc[FAQ] - Answers to frequently asked questions
-* link:index.adoc[Documentation Home] - Return to the main documentation page
\ No newline at end of file
+* link:index.adoc[Documentation Home] - Return to the main documentation page
diff --git a/src/main/java/net/openhft/chronicle/wire/AbstractAnyWire.java b/src/main/java/net/openhft/chronicle/wire/AbstractAnyWire.java
index 2cdffc036f..b974215070 100644
--- a/src/main/java/net/openhft/chronicle/wire/AbstractAnyWire.java
+++ b/src/main/java/net/openhft/chronicle/wire/AbstractAnyWire.java
@@ -22,7 +22,7 @@
*
* @author Rob Austin.
*/
-@SuppressWarnings("rawtypes")
+@SuppressWarnings({"rawtypes", "deprecation"})
public abstract class AbstractAnyWire extends AbstractWire implements Wire {
@NotNull
@@ -56,6 +56,7 @@ public Wire underlyingWire() {
* @return A supplier yielding the {@code WireType}.
*/
@NotNull
+ @Deprecated(/* to be removed in 2027 */)
public Supplier underlyingType() {
return wireAcquisition.underlyingType();
}
@@ -222,6 +223,7 @@ interface WireAcquisition {
* @return A supplier yielding the {@code WireType}.
*/
@NotNull
+ @Deprecated(/* to be removed in 2027 */)
Supplier underlyingType();
/**
diff --git a/src/main/java/net/openhft/chronicle/wire/AbstractClassGenerator.java b/src/main/java/net/openhft/chronicle/wire/AbstractClassGenerator.java
index 3f02193343..d4a948572d 100644
--- a/src/main/java/net/openhft/chronicle/wire/AbstractClassGenerator.java
+++ b/src/main/java/net/openhft/chronicle/wire/AbstractClassGenerator.java
@@ -89,18 +89,14 @@ public synchronized Class acquireClass(ClassLoader classLoader) {
generateMainCode(mainCode);
// Append package and import statements.
- sourceCode.append("" +
- "package " + metaData.packageName() + ";\n" +
- "\n");
- String extendsClassName = nameForClass(extendsClass());
- String implementsSet = metaData.interfaces().stream()
+ sourceCode.append("" + "package ").append(metaData.packageName()).append(";\n").append("\n");
+ final String implementsSet = metaData.interfaces().stream()
.map(this::nameForClass)
.sorted()
.collect(Collectors.joining(", "));
for (String import0 : importSet) {
- sourceCode.append("" +
- "import " + import0 + ";\n");
+ sourceCode.append("" + "import ").append(import0).append(";\n");
}
// can't add classes to imports from this point.
importSet = Collections.unmodifiableSortedSet(importSet);
@@ -111,10 +107,12 @@ public synchronized Class acquireClass(ClassLoader classLoader) {
String genericType = generateGenericType();
if (genericType != null && !genericType.isEmpty())
sourceCode.append('<').append(genericType).append('>');
- if (extendsClass() != Object.class)
+ if (extendsClass() != Object.class) {
+ String extendsClassName = nameForClass(extendsClass());
sourceCode.append(" extends ")
.append(extendsClassName);
- if (implementsSet.length() > 0) {
+ }
+ if (!implementsSet.isEmpty()) {
sourceCode.append(" implements ")
.append(implementsSet);
}
diff --git a/src/main/java/net/openhft/chronicle/wire/AbstractGeneratedMethodReader.java b/src/main/java/net/openhft/chronicle/wire/AbstractGeneratedMethodReader.java
index 0f7527db31..7ae4495080 100644
--- a/src/main/java/net/openhft/chronicle/wire/AbstractGeneratedMethodReader.java
+++ b/src/main/java/net/openhft/chronicle/wire/AbstractGeneratedMethodReader.java
@@ -30,6 +30,7 @@
* Subclasses implement {@link #readOneGenerated(WireIn)} and
* {@link #readOneMetaGenerated(WireIn)} with optimised dispatch logic.
*/
+@SuppressWarnings("deprecation")
public abstract class AbstractGeneratedMethodReader implements MethodReader {
// A no-operation {@link Consumer} for {@link MessageHistory}.
@@ -41,6 +42,7 @@ public abstract class AbstractGeneratedMethodReader implements MethodReader {
private static final ConcurrentHashMap
TEMP_MESSAGE_HISTORY_BY_SERVICE_NAME = new ConcurrentHashMap<>();
// The parselet used for debug logging when {@link Jvm#isDebug()} is true.
+ @Deprecated(/* to be removed in 2027, as it is only used in tests */)
protected final WireParselet debugLoggingParselet;
// Input providing documents for this reader.
private final MarshallableIn in;
@@ -73,6 +75,7 @@ public abstract class AbstractGeneratedMethodReader implements MethodReader {
* @param in input providing documents
* @param debugLoggingParselet parselet used when debug logging is enabled
*/
+ @Deprecated(/* to be removed in 2027, as it is only used in tests */)
protected AbstractGeneratedMethodReader(MarshallableIn in,
WireParselet debugLoggingParselet) {
this.in = in;
@@ -110,6 +113,7 @@ public AbstractGeneratedMethodReader predicate(Predicate predicate
* @param parameterTypes The parameter types of the method
* @return The method if found, otherwise throws an AssertionError
*/
+ @Deprecated(/* to be removed in 2027, as it is only used in tests */)
protected static Method lookupMethod(Class> clazz, String name, Class>... parameterTypes) {
try {
final Method method = clazz.getMethod(name, parameterTypes);
@@ -390,6 +394,7 @@ public MethodReader closeIn(boolean closeIn) {
* {@code null} or an array. If the object is a collection or map, the method will clear its
* content and return the object.
*/
+ @Deprecated(/* to be removed in 2027, as it is only used in tests */)
protected T checkRecycle(T o) {
if (o == null || o.getClass().isArray()) // If the object is null or an array, return null to prevent recycling.
return null;
@@ -420,6 +425,7 @@ protected T checkRecycle(T o) {
* @return Returns the result of the method invocation.
* @throws RuntimeException if the method invocation throws an exception.
*/
+ @Deprecated(/* to be removed in 2027, as it is only used in tests */)
protected Object actualInvoke(Method method, Object o, Object[] objects) {
try {
return method.invoke(o, objects);
@@ -453,6 +459,7 @@ public void scanning(boolean scanning) {
* Thread-local holder for {@link VanillaMessageHistory} instances with source
* details enabled.
*/
+ @Deprecated(/* to be removed in 2027, as it is only used in tests */)
private static final class MessageHistoryThreadLocal {
private final ThreadLocal messageHistoryTL = withInitial(() -> {
diff --git a/src/main/java/net/openhft/chronicle/wire/AbstractWire.java b/src/main/java/net/openhft/chronicle/wire/AbstractWire.java
index e30a589264..175d21cf17 100644
--- a/src/main/java/net/openhft/chronicle/wire/AbstractWire.java
+++ b/src/main/java/net/openhft/chronicle/wire/AbstractWire.java
@@ -32,6 +32,7 @@
* Represents the AbstractWire class which serves as a base for all Wire implementations.
* This class provides fundamental shared behaviors, configurations, and initializations for Wire types.
*/
+@SuppressWarnings("deprecation")
public abstract class AbstractWire implements Wire, InternalWire {
// Default padding configuration loaded from the system properties.
@@ -134,8 +135,8 @@ public void clear() {
/**
* Internal method to set the header number at a specific position.
*
- * @param position The position in the bytes representation.
- * @param headerNumber The header number to set.
+ * @param position The position in the bytes representation.
+ * @param headerNumber The header number to set.
* @return The current Wire instance.
*/
@NotNull
@@ -147,8 +148,8 @@ private Wire headerNumber(long position, long headerNumber) {
/**
* Checks if the header at the given position and header number is valid.
*
- * @param position The position in the bytes representation.
- * @param headerNumber The header number to check.
+ * @param position The position in the bytes representation.
+ * @param headerNumber The header number to check.
* @return True if the header is valid, false otherwise.
*/
private boolean checkHeader(long position, long headerNumber) {
diff --git a/src/main/java/net/openhft/chronicle/wire/Base85LongConverter.java b/src/main/java/net/openhft/chronicle/wire/Base85LongConverter.java
index 4a27e1a3a2..e507ceb40a 100644
--- a/src/main/java/net/openhft/chronicle/wire/Base85LongConverter.java
+++ b/src/main/java/net/openhft/chronicle/wire/Base85LongConverter.java
@@ -21,6 +21,7 @@
* @see AbstractLongConverter
* @see ShortTextLongConverter
*/
+@SuppressWarnings("deprecation")
public class Base85LongConverter extends AbstractLongConverter {
/**
diff --git a/src/main/java/net/openhft/chronicle/wire/BinaryMethodWriterInvocationHandler.java b/src/main/java/net/openhft/chronicle/wire/BinaryMethodWriterInvocationHandler.java
index 077d9ad9ec..232d82457d 100644
--- a/src/main/java/net/openhft/chronicle/wire/BinaryMethodWriterInvocationHandler.java
+++ b/src/main/java/net/openhft/chronicle/wire/BinaryMethodWriterInvocationHandler.java
@@ -71,6 +71,7 @@ protected Object doInvoke(Object proxy, Method method, Object[] args) {
*
* @return {@code true} if metadata is enabled, {@code false} otherwise.
*/
+ @Deprecated(/* to be removed in 2027 */)
public boolean metaData() {
return metaData;
}
diff --git a/src/main/java/net/openhft/chronicle/wire/BinaryReadDocumentContext.java b/src/main/java/net/openhft/chronicle/wire/BinaryReadDocumentContext.java
index 50b93f3b45..b86d809869 100644
--- a/src/main/java/net/openhft/chronicle/wire/BinaryReadDocumentContext.java
+++ b/src/main/java/net/openhft/chronicle/wire/BinaryReadDocumentContext.java
@@ -5,9 +5,7 @@
import net.openhft.chronicle.bytes.Bytes;
import net.openhft.chronicle.bytes.BytesUtil;
-import net.openhft.chronicle.core.Jvm;
import net.openhft.chronicle.core.pool.StringBuilderPool;
-import net.openhft.chronicle.core.scoped.ScopedResource;
import net.openhft.chronicle.core.scoped.ScopedResourcePool;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -19,6 +17,7 @@
* It provides an implementation tailored for reading from binary document contexts and ensures
* full read capability if required.
*/
+@SuppressWarnings("deprecation")
public class BinaryReadDocumentContext implements ReadDocumentContext {
public long start = -1;
@@ -90,8 +89,6 @@ protected boolean rollback() {
return rollback;
}
- static final ScopedResourcePool SBP = StringBuilderPool.createThreadLocal(1);
-
@Override
public void close() {
if (rollbackIfNeeded())
diff --git a/src/main/java/net/openhft/chronicle/wire/BinaryWire.java b/src/main/java/net/openhft/chronicle/wire/BinaryWire.java
index 72e95afa65..38db0cb713 100644
--- a/src/main/java/net/openhft/chronicle/wire/BinaryWire.java
+++ b/src/main/java/net/openhft/chronicle/wire/BinaryWire.java
@@ -269,6 +269,7 @@ public boolean isBinary() {
*
{@code false} – never write type information
*
*/
+ @Deprecated(/* to be removed in 2027 */)
public Boolean getOverrideSelfDescribing() {
return overrideSelfDescribing;
}
@@ -628,7 +629,7 @@ private static void copyHistoryMessage(Bytes> bytes, @NotNull WireOut wire) {
/**
* Throw an {@link IORuntimeException} for an unexpected code.
*/
- protected static void unexpectedCode() throws IORuntimeException{
+ protected static void unexpectedCode() {
throw new IORuntimeException("Unexpected code in this context");
}
@@ -707,7 +708,7 @@ public void readWithLength(@NotNull WireOut wire, int len) throws InvalidMarshal
/**
* Throw an {@link IllegalArgumentException} if a code cannot be recognised.
*/
- protected void unknownCode(@NotNull WireOut wire) throws IllegalArgumentException{
+ protected void unknownCode(@NotNull WireOut wire) {
throw new IllegalArgumentException(stringForCode(bytes.readUnsignedByte()));
}
@@ -994,9 +995,6 @@ private int peekCodeAfterPadding() {
public K readEvent(@NotNull Class expectedClass) throws InvalidMarshallableException {
int peekCode = peekCodeAfterPadding();
switch (peekCode >> 4) {
- case BinaryWireHighCode.END_OF_STREAM:
- return null;
-
case BinaryWireHighCode.CONTROL:
case BinaryWireHighCode.SPECIAL:
return readSpecialField(peekCode, expectedClass);
@@ -1005,6 +1003,7 @@ public K readEvent(@NotNull Class expectedClass) throws InvalidMarshallab
case BinaryWireHighCode.FIELD1:
return readSmallField(peekCode, expectedClass);
+ case BinaryWireHighCode.END_OF_STREAM:
default:
return null;
}
@@ -1222,6 +1221,8 @@ private StringBuilder readSpecialField(int peekCode, CharSequence keyName, int k
// Get the textual representation of the event object.
valueIn.text(sb);
return sb;
+ default:
+ break;
}
// Return null for unknown special fields.
@@ -1639,6 +1640,8 @@ Number readInt0object(int code) {
case INT64_0x:
// 64-bit signed integer.
return bytes.readLong();
+ default:
+ break;
}
// If the encoding is unrecognized, throw an exception.
@@ -2382,24 +2385,6 @@ public WireOut fixedInt32(int i32) {
return BinaryWire.this;
}
- /**
- * Writes a 32-bit integer value to the byte storage in an order-preserving binary format.
- *
- * Additionally, if hex dump description is retained, it writes a hex dump description.
- *
- * @param i32 The 32-bit integer value to be written.
- * @return The current WireOut instance.
- */
- @NotNull
- public WireOut fixedOrderedInt32(int i32) {
- // Check if hex dump description should be written.
- if (bytes.retainedHexDumpDescription())
- bytes.writeHexDumpDescription(Integer.toString(i32));
- // Write the integer value in an ordered format.
- writeCode(INT32).writeOrderedInt(i32);
- return BinaryWire.this;
- }
-
@NotNull
@Override
public WireOut uint32checked(long u32) {
@@ -2642,7 +2627,8 @@ public WireOut int32forBinding(int value, @NotNull IntValue intValue) {
if (bytes.retainedHexDumpDescription())
bytes.writeHexDumpDescription("int32 for binding");
int32forBinding(value);
- ((BinaryIntReference) intValue).bytesStore(bytes, bytes.writePosition() - 4, 4);
+ BinaryIntReference reference = requireReference(intValue, BinaryIntReference.class, "int32forBinding");
+ reference.bytesStore(bytes, bytes.writePosition() - 4, 4);
return BinaryWire.this;
}
@@ -2652,7 +2638,8 @@ public WireOut int64forBinding(long value, @NotNull LongValue longValue) {
if (bytes.retainedHexDumpDescription())
bytes.writeHexDumpDescription("int64 for binding");
int64forBinding(value);
- ((BinaryLongReference) longValue).bytesStore(bytes, bytes.writePosition() - 8, 8);
+ BinaryLongReference reference = requireReference(longValue, BinaryLongReference.class, "int64forBinding");
+ reference.bytesStore(bytes, bytes.writePosition() - 8, 8);
return BinaryWire.this;
}
@@ -2660,8 +2647,8 @@ public WireOut int64forBinding(long value, @NotNull LongValue longValue) {
@Override
public WireOut boolForBinding(final boolean value, @NotNull final BooleanValue booleanValue) {
bool(value);
- ((BinaryBooleanReference) booleanValue).bytesStore(bytes, bytes.writePosition() - 1,
- 1);
+ BinaryBooleanReference reference = requireReference(booleanValue, BinaryBooleanReference.class, "boolForBinding");
+ reference.bytesStore(bytes, bytes.writePosition() - 1, 1);
return BinaryWire.this;
}
@@ -2739,10 +2726,13 @@ public WireOut marshallable(@NotNull WriteMarshallable object) throws InvalidMar
final BinaryLengthLength binaryLengthLength = object.binaryLengthLength();
long pos = binaryLengthLength.initialise(bytes);
- if (useSelfDescribingMessage(object))
+ if (useSelfDescribingMessage(object)) {
object.writeMarshallable(BinaryWire.this);
- else
+ } else {
+ if (!(object instanceof WriteBytesMarshallable))
+ throw new InvalidMarshallableException("Object must implement WriteBytesMarshallable when usesSelfDescribingMessage is false: " + object.getClass());
((WriteBytesMarshallable) object).writeMarshallable(BinaryWire.this.bytes());
+ }
binaryLengthLength.writeLength(bytes, pos, bytes.writePosition());
return BinaryWire.this;
@@ -3277,46 +3267,12 @@ public BracketType getBracketType() {
return getBracketTypeFor(bytes.readUnsignedByte(bytes.readPosition() + 4 + 1));
case NULL:
return BracketType.NONE;
+ default:
+ break;
}
return BracketType.NONE;
}
- /**
- * Reads text from the wire and consumes it using the provided string consumer.
- *
- * @param s A {@link Consumer} that accepts and processes the read string.
- * @return The instance of BinaryWire that this handler belongs to.
- */
- @NotNull
- WireIn text(@NotNull Consumer s) {
- // Consume any padding before reading text
- consumePadding();
- int code = readCode();
- switch (code) {
- case NULL:
- s.accept(null);
- break;
-
- case STRING_ANY:
- // Read the UTF-8 string from bytes and consume it
- s.accept(bytes.readUtf8());
- break;
- default:
- // Check for special string codes
- if (code >= STRING_0 && code <= STRING_31) {
- @NotNull StringBuilder sb = acquireStringBuilder();
- // Parse the UTF-8 string based on its length code and consume it
- bytes.parseUtf8(sb, code & 0b11111);
- s.accept(WireInternal.INTERNER.intern(sb));
-
- } else {
- // If an unrecognized code is found, throw an exception
- cantRead(code);
- }
- }
- return BinaryWire.this;
- }
-
/**
* Checks if the provided code corresponds to text data.
*
@@ -3329,6 +3285,21 @@ private boolean isText(int code) {
(code >= STRING_0 && code <= STRING_31);
}
+ private void copyTextToBytesOut(BytesOut> target) {
+ if (target instanceof Bytes) {
+ textTo((Bytes) target);
+ return;
+ }
+ try (ScopedResource> scoped = Wires.acquireBytesScoped()) {
+ Bytes> temp = scoped.get();
+ textTo(temp);
+ temp.readPosition(0);
+ long length = temp.readRemaining();
+ target.write(temp, 0L, length);
+ temp.clear();
+ }
+ }
+
@Nullable
@Override
public StringBuilder textTo(@NotNull StringBuilder sb) {
@@ -3440,10 +3411,10 @@ public WireIn bytes(@NotNull BytesOut> toBytes, boolean clearBytes) {
}
if (code == U8_ARRAY) {
- ((Bytes) bytes).readWithLength(length - 1, toBytes);
+ bytes.readWithLength(length - 1, toBytes);
} else {
bytes.uncheckedReadSkipBackOne();
- textTo((Bytes) toBytes);
+ copyTextToBytesOut(toBytes);
}
return wireIn();
}
@@ -3831,6 +3802,8 @@ private void int8b(@NotNull T t, @NotNull ObjByteConsumer tb, int code) {
consumePadding();
code = bytes.readUnsignedByte();
break;
+ default:
+ break;
}
// Check if the code indicates a text format
@@ -4499,6 +4472,8 @@ public boolean marshallable(@NotNull ReadMarshallable object, boolean overwrite)
else
Wires.readMarshallable(object, BinaryWire.this, false);
} else {
+ if (!(object instanceof ReadBytesMarshallable))
+ throw new InvalidMarshallableException("Object must implement ReadBytesMarshallable when usesSelfDescribingMessage is false: " + object.getClass());
((ReadBytesMarshallable) object).readMarshallable(BinaryWire.this.bytes);
}
} finally {
@@ -4596,7 +4571,7 @@ private long readTextAsLong(long otherwise) throws IORuntimeException, BufferUnd
} catch (Exception e) {
return otherwise; // On any exception, return the default value.
}
- if (text == null || text.length() == 0) // If text is empty or null, return the default value.
+ if (text == null || text.isEmpty()) // If text is empty or null, return the default value.
return otherwise;
try {
return Long.parseLong(text); // Try to parse the text as a long.
@@ -4620,7 +4595,7 @@ private double readTextAsDouble() throws IORuntimeException, BufferUnderflowExce
} catch (BufferUnderflowException e) {
return Double.NaN; // On buffer underflow, return NaN.
}
- if (text == null || text.length() == 0) // If text is empty or null, return NaN.
+ if (text == null || text.isEmpty()) // If text is empty or null, return NaN.
return Double.NaN;
return Double.parseDouble(text); // Try to parse the text as a double.
}
@@ -4629,7 +4604,7 @@ private double readTextAsDouble() throws IORuntimeException, BufferUnderflowExce
public boolean bool() throws IORuntimeException {
int code = readCode();
if (isText(code))
- return Boolean.valueOf(text());
+ return Boolean.parseBoolean(text());
switch (code) {
case TRUE:
@@ -4643,6 +4618,8 @@ public boolean bool() throws IORuntimeException {
bytes.uncheckedReadSkipBackOne();
consumePadding();
return bool();
+ default:
+ break;
}
throw new IORuntimeException(stringForCode(code));
}
@@ -4672,6 +4649,8 @@ private byte int8b(int code) {
consumePadding(); // Handle the padding or comment.
code = readCode(); // Read the next code.
break;
+ default:
+ break;
}
// Determine if the code represents text or an integer value.
@@ -4841,6 +4820,8 @@ public Object objectWithInferredType(Object using, @NotNull SerializationStrateg
case ANCHOR:
case UPDATED_ALIAS:
return typedMarshallable();
+ default:
+ break;
}
break;
@@ -4886,6 +4867,8 @@ public Object objectWithInferredType(Object using, @NotNull SerializationStrateg
case TYPE_LITERAL:
return typeLiteral();
+ default:
+ break;
}
break;
@@ -4899,6 +4882,8 @@ public Object objectWithInferredType(Object using, @NotNull SerializationStrateg
if (code == UUID)
return new java.util.UUID(bytes.readLong(), bytes.readLong());
return readInt0object(code);
+ default:
+ break;
}
// assume it a String
return text();
@@ -5005,6 +4990,8 @@ void consumeNext() throws InvalidMarshallableException {
consumeNext();
return;
}
+ default:
+ break;
}
break;
@@ -5084,9 +5071,18 @@ void consumeNext() throws InvalidMarshallableException {
}
// If none of the known integer codes were matched, throw an exception
throw new UnsupportedOperationException(stringForCode(code));
+ default:
+ break;
}
// If the code doesn't match any known pattern, assume it's a text encoding
text();
}
}
+
+ static T requireReference(Object value, Class expected, String action) {
+ if (expected.isInstance(value))
+ return expected.cast(value);
+ throw new IllegalArgumentException(action + " requires " + expected.getSimpleName() +
+ " but was " + (value == null ? "null" : value.getClass().getName()));
+ }
}
diff --git a/src/main/java/net/openhft/chronicle/wire/BinaryWriteDocumentContext.java b/src/main/java/net/openhft/chronicle/wire/BinaryWriteDocumentContext.java
index e060e82736..264cbcec8e 100644
--- a/src/main/java/net/openhft/chronicle/wire/BinaryWriteDocumentContext.java
+++ b/src/main/java/net/openhft/chronicle/wire/BinaryWriteDocumentContext.java
@@ -15,6 +15,7 @@
* documents that are currently being written. The binary format uses headers to
* denote metadata, data length, and completion status.
*/
+@SuppressWarnings("deprecation")
public class BinaryWriteDocumentContext implements WriteDocumentContext {
// The wire instance used for the binary writing process
@@ -163,6 +164,7 @@ public Wire wire() {
*
* @return The position in the wire where the current document starts.
*/
+ @Deprecated(/* to be removed in 2027 */)
protected long position() {
return position;
}
diff --git a/src/main/java/net/openhft/chronicle/wire/CSVWire.java b/src/main/java/net/openhft/chronicle/wire/CSVWire.java
index 7e5956d5f8..dd5ee6de29 100644
--- a/src/main/java/net/openhft/chronicle/wire/CSVWire.java
+++ b/src/main/java/net/openhft/chronicle/wire/CSVWire.java
@@ -4,6 +4,7 @@
package net.openhft.chronicle.wire;
import net.openhft.chronicle.bytes.*;
+import net.openhft.chronicle.core.Jvm;
import net.openhft.chronicle.core.io.InvalidMarshallableException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -30,12 +31,6 @@ public class CSVWire extends TextWire {
private static final ThreadLocal ESCAPED_END_OF_TEXT = ThreadLocal.withInitial(
StopCharTesters.COMMA_STOP::escaping);
- /**
- * Field names parsed from the first line of the input. These are used to
- * map subsequent column values when reading records.
- */
- private final List header = new ArrayList<>();
-
/**
* Creates a wire backed by the supplied bytes and parses the first line as
* the header row.
@@ -48,6 +43,11 @@ public CSVWire(@NotNull Bytes> bytes, boolean use8bit) {
super(bytes, use8bit);
while (lineStart == 0) {
long start = bytes.readPosition();
+ /*
+ * Field names parsed from the first line of the input. These are used to
+ * map subsequent column values when reading records.
+ */
+ List header = new ArrayList<>();
header.add(valueIn.text());
if (bytes.readPosition() == start)
break;
@@ -73,6 +73,7 @@ public CSVWire(@NotNull Bytes> bytes) {
* @throws IOException if the file cannot be read
*/
@NotNull
+ @Deprecated(/* to be removed in 2027, as it is only used in tests */)
public static CSVWire fromFile(String name) throws IOException {
return new CSVWire(BytesUtil.readFile(name), true);
}
@@ -84,6 +85,7 @@ public static CSVWire fromFile(String name) throws IOException {
* @return new instance containing the text
*/
@NotNull
+ @Deprecated(/* to be removed in 2027, as it is only used in tests */)
public static CSVWire from(@NotNull String text) {
return new CSVWire(Bytes.from(text));
}
@@ -139,7 +141,8 @@ public void consumePaddingStart() {
// Checks if the code point represents a comment.
if (codePoint == '#') {
// If so, skip characters until the end of the line.
- while (readCode() >= ' ') ;
+ while (readCode() >= ' ')
+ Jvm.nanoPause();
continue;
}
if (Character.isWhitespace(codePoint)) {
diff --git a/src/main/java/net/openhft/chronicle/wire/DefaultValueIn.java b/src/main/java/net/openhft/chronicle/wire/DefaultValueIn.java
index 949be46ad9..045f551fc3 100644
--- a/src/main/java/net/openhft/chronicle/wire/DefaultValueIn.java
+++ b/src/main/java/net/openhft/chronicle/wire/DefaultValueIn.java
@@ -30,7 +30,7 @@
* It returns either {@code null}, a primitive zero or the value configured by the {@link WireMarshaller}.
* This allows optional fields to be skipped without breaking deserialisation.
*/
-@SuppressWarnings("rawtypes")
+@SuppressWarnings({"rawtypes", "deprecation"})
public class DefaultValueIn implements ValueIn {
// The underlying WireIn source for fetching default values
@@ -102,8 +102,12 @@ public WireIn bytesSet(@NotNull PointerBytesStore toBytes) {
@NotNull
@Override
public WireIn bytesMatch(@NotNull BytesStore, ?> compareBytes, @NotNull BooleanConsumer consumer) {
- @Nullable Object o = defaultValue;
- @NotNull BytesStore, ?> bytes = (BytesStore) o;
+ Object o = defaultValue;
+ if (!(o instanceof BytesStore)) {
+ consumer.accept(false);
+ return wireIn();
+ }
+ BytesStore, ?> bytes = (BytesStore, ?>) o;
consumer.accept(compareBytes.contentEquals(bytes));
return wireIn();
}
@@ -323,8 +327,9 @@ public WireIn bool(@NotNull final BooleanValue ret) {
public WireIn int64(@Nullable LongValue value, T t, @NotNull BiConsumer setter) {
@NotNull Number o = (Number) defaultValue;
if (o == null) o = 0;
- value.setValue(o.longValue());
- setter.accept(t, value);
+ LongValue target = value == null ? wireIn.newLongReference() : value;
+ target.setValue(o.longValue());
+ setter.accept(t, target);
return wireIn();
}
@@ -333,8 +338,9 @@ public WireIn int64(@Nullable LongValue value, T t, @NotNull BiConsumer WireIn int32(@Nullable IntValue value, T t, @NotNull BiConsumer setter) {
@NotNull Number o = (Number) defaultValue;
if (o == null) o = 0;
- value.setValue(o.intValue());
- setter.accept(t, value);
+ IntValue target = value == null ? wireIn.newIntReference() : value;
+ target.setValue(o.intValue());
+ setter.accept(t, target);
return wireIn();
}
@@ -412,7 +418,7 @@ public Object marshallable(@NotNull Object object, @NotNull SerializationStrateg
@Override
public boolean bool() throws IORuntimeException {
- return defaultValue == Boolean.TRUE;
+ return Boolean.TRUE.equals(defaultValue);
}
@Override
diff --git a/src/main/java/net/openhft/chronicle/wire/DocumentContext.java b/src/main/java/net/openhft/chronicle/wire/DocumentContext.java
index b96c1a4733..a8479624f2 100644
--- a/src/main/java/net/openhft/chronicle/wire/DocumentContext.java
+++ b/src/main/java/net/openhft/chronicle/wire/DocumentContext.java
@@ -18,6 +18,7 @@
* Implementations must ensure proper handling of resources and consistency of the document state.
*/
public interface DocumentContext extends Closeable, SourceContext {
+ @Deprecated(/* to be removed in 2027 */)
DocumentContext NOOP = Mocker.ignored(DocumentContext.class);
/**
diff --git a/src/main/java/net/openhft/chronicle/wire/DocumentContextHolder.java b/src/main/java/net/openhft/chronicle/wire/DocumentContextHolder.java
index d8dee0f915..ae7c98185b 100644
--- a/src/main/java/net/openhft/chronicle/wire/DocumentContextHolder.java
+++ b/src/main/java/net/openhft/chronicle/wire/DocumentContextHolder.java
@@ -11,6 +11,7 @@
* and {@link WriteDocumentContext}. It acts as a wrapper or a delegate around an instance of
* {@link DocumentContext}, providing methods to interact with the encapsulated context.
*/
+@SuppressWarnings("deprecation")
public class DocumentContextHolder implements DocumentContext, WriteDocumentContext {
// The encapsulated DocumentContext instance.
diff --git a/src/main/java/net/openhft/chronicle/wire/Event.java b/src/main/java/net/openhft/chronicle/wire/Event.java
index 2015096639..cfa8e0267e 100644
--- a/src/main/java/net/openhft/chronicle/wire/Event.java
+++ b/src/main/java/net/openhft/chronicle/wire/Event.java
@@ -52,6 +52,7 @@ default E eventId(@NotNull final CharSequence eventId) {
* @return this event instance after the update
*/
@SuppressWarnings("unchecked")
+ @Deprecated(/* to be removed in 2027 */)
default E updateEvent(final String eventName) {
// Set the event ID to the given name if it's currently unset
if (this.eventId().length() == 0)
diff --git a/src/main/java/net/openhft/chronicle/wire/ExcerptListener.java b/src/main/java/net/openhft/chronicle/wire/ExcerptListener.java
index ac9a7d4a85..cb6b65faed 100644
--- a/src/main/java/net/openhft/chronicle/wire/ExcerptListener.java
+++ b/src/main/java/net/openhft/chronicle/wire/ExcerptListener.java
@@ -39,6 +39,7 @@ public interface ExcerptListener {
* @throws NullPointerException if {@code after} is {@code null }
*/
@NotNull
+ @Deprecated(/* to be removed in 2027 */)
default ExcerptListener andThen(@NotNull final ExcerptListener after) {
requireNonNull(after);
return ((wire, index) -> {
diff --git a/src/main/java/net/openhft/chronicle/wire/GenerateJsonSchemaMain.java b/src/main/java/net/openhft/chronicle/wire/GenerateJsonSchemaMain.java
index 31180b679a..db8ffc82a8 100644
--- a/src/main/java/net/openhft/chronicle/wire/GenerateJsonSchemaMain.java
+++ b/src/main/java/net/openhft/chronicle/wire/GenerateJsonSchemaMain.java
@@ -77,8 +77,7 @@ static String main0(String... args) throws ClassNotFoundException {
for (Class> aClass : interfaces) {
g.generateEventSchemaFor(aClass);
}
- final String json = g.asJson();
- return json;
+ return g.asJson();
}
/**
@@ -98,7 +97,7 @@ String asJson() {
String sep = "";
for (Map.Entry, String> entry : definitions.entrySet()) {
sb.append(sep);
- sb.append("\"" + entry.getKey().getSimpleName() + "\": {\n");
+ sb.append("\"").append(entry.getKey().getSimpleName()).append("\": {\n");
sb.append(entry.getValue());
sb.append("}");
sep = ",\n";
@@ -107,7 +106,7 @@ String asJson() {
sb.append("},\n" +
"\"properties\": {\n");
for (Map.Entry entry : events.entrySet()) {
- sb.append("\"" + entry.getKey() + "\": {\n");
+ sb.append("\"").append(entry.getKey()).append("\": {\n");
sb.append(entry.getValue());
sb.append("},\n");
}
@@ -167,7 +166,7 @@ private void addProperties(Map properties, StringBuilder sb) {
String sep = "\n";
for (Map.Entry entry : properties.entrySet()) {
sb.append(sep);
- sb.append("\"" + entry.getKey() + "\": {\n");
+ sb.append("\"").append(entry.getKey()).append("\": {\n");
sb.append(entry.getValue());
sb.append("}");
sep = ",\n";
@@ -218,7 +217,7 @@ void generateObjectSchemaFor(Class> type) {
}
Comment comment = Jvm.findAnnotation(type, Comment.class);
if (comment != null)
- sb.append("\"description\": \"" + comment.value() + "\",\n");
+ sb.append("\"description\": \"").append(comment.value()).append("\",\n");
addProperties(properties, sb);
definitions.put(type, sb.toString());
@@ -279,7 +278,7 @@ private void addTypeForFieldOrParam(StringBuilder desc, Class> pType, Annotati
generateObjectSchemaFor(pType);
String alias = aliases.get(pType);
String key = alias.startsWith("#") ? "$ref" : "type";
- desc.append("\"" + key + "\": \"" + alias + "\"\n");
+ desc.append("\"").append(key).append("\": \"").append(alias).append("\"\n");
}
}
diff --git a/src/main/java/net/openhft/chronicle/wire/GenerateMethodBridge.java b/src/main/java/net/openhft/chronicle/wire/GenerateMethodBridge.java
index e3058f4d08..4ed45814d0 100644
--- a/src/main/java/net/openhft/chronicle/wire/GenerateMethodBridge.java
+++ b/src/main/java/net/openhft/chronicle/wire/GenerateMethodBridge.java
@@ -45,6 +45,7 @@ public GenerateMethodBridge() {
* @param ui optional {@link UpdateInterceptor} applied to bridge invocations
* @return a new instance of the generated bridge class
*/
+ @Deprecated(/* to be removed in 2027 */)
public static Object bridgeFor(Class> destType, List