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. + *

+ * Measures latency for writing and reading a fixed structure of eight strings. */ - /* .2.21ea74 read: 50/90 97/99 99.7/99.9 99.97/99.99 99.997/99.999 99.9997/99.9999 - worst was 0.542 / 0.566 0.586 / 0.610 0.690 / 1.092 16.1 / 19.9 29.4 / 29.9 32.9 / 33.9 - 178 @@ -25,7 +26,6 @@ read: 50/90 97/99 99.7/99.9 99.97/99.99 99.997/99.999 99.9997/99.9999 - worst was 0.233 / 0.245 0.253 / 0.259 0.303 / 0.439 0.574 / 15.9 21.2 / 29.1 29.2 / 32.6 - 58.2 write: 50/90 97/99 99.7/99.9 99.97/99.99 99.997/99.999 99.9997/99.9999 - worst was 0.062 / 0.066 0.068 / 0.073 0.081 / 0.126 0.172 / 0.305 15.6 / 19.4 28.7 / 29.0 - 41.9 */ - public class StringsInBytesMarshallableMain { /** diff --git a/marshallingperf/src/main/java/run/chronicle/wire/perf/package-info.java b/marshallingperf/src/main/java/run/chronicle/wire/perf/package-info.java new file mode 100644 index 0000000000..24e357486a --- /dev/null +++ b/marshallingperf/src/main/java/run/chronicle/wire/perf/package-info.java @@ -0,0 +1,11 @@ +/* + * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 + */ +/** + * Marshalling performance experiments for Chronicle Wire. + *

+ * 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 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.openhft third-party-bom - 3.27ea5 + 3.27ea7 pom import 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):: 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 toInvoke, UpdateInterceptor ui) { GenerateMethodBridge gmb = new GenerateMethodBridge(); MethodBridgeMetaData md = gmb.metaData(); @@ -171,6 +172,7 @@ static final class MethodBridgeMetaData extends AbstractClassGenerator.MetaData< /** * Returns the handler types. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public List> invokes() { return invokes; } diff --git a/src/main/java/net/openhft/chronicle/wire/GenerateMethodReader.java b/src/main/java/net/openhft/chronicle/wire/GenerateMethodReader.java index 1a5765c5a3..b61bd921fa 100644 --- a/src/main/java/net/openhft/chronicle/wire/GenerateMethodReader.java +++ b/src/main/java/net/openhft/chronicle/wire/GenerateMethodReader.java @@ -236,36 +236,23 @@ private void generateSourceCode() { // Start constructing the source code. if (!packageName().isEmpty()) - sourceCode.append(format("package %s;\n", packageName())); + sourceCode.append(format("package %s;%n", packageName())); // Import statements required for the generated code. boolean hasMultipleNonMarshallableParamTypes = !Boolean.FALSE.equals(multipleNonMarshallableParamTypes); - sourceCode.append("" + - "import net.openhft.chronicle.core.Jvm;\n" + - "import net.openhft.chronicle.core.util.InvocationTargetRuntimeException;\n" + - "import net.openhft.chronicle.core.util.ObjectUtils;\n" + - "import net.openhft.chronicle.bytes.*;\n" + - "import net.openhft.chronicle.wire.*;\n" + - "import net.openhft.chronicle.wire.utils.*;\n" + - "import net.openhft.chronicle.wire.BinaryWireCode;\n" + - "\n" + - (hasMultipleNonMarshallableParamTypes ? "import java.util.HashMap;\n" : "") + - "import java.util.Map;\n" + - (hasMultipleNonMarshallableParamTypes ? "import java.util.function.Function;\n" : "") + - "import java.lang.reflect.Method;\n" + - "\n"); + sourceCode.append("" + "import net.openhft.chronicle.core.Jvm;\n" + "import net.openhft.chronicle.core.util.InvocationTargetRuntimeException;\n" + "import net.openhft.chronicle.core.util.ObjectUtils;\n" + "import net.openhft.chronicle.bytes.*;\n" + "import net.openhft.chronicle.wire.*;\n" + "import net.openhft.chronicle.wire.utils.*;\n" + "import net.openhft.chronicle.wire.BinaryWireCode;\n" + "\n").append(hasMultipleNonMarshallableParamTypes ? "import java.util.HashMap;\n" : "").append("import java.util.Map;\n").append(hasMultipleNonMarshallableParamTypes ? "import java.util.function.Function;\n" : "").append("import java.lang.reflect.Method;\n").append("\n"); // Declare the generated class extending AbstractGeneratedMethodReader. - sourceCode.append(format("public class %s extends AbstractGeneratedMethodReader {\n", generatedClassName())); + sourceCode.append(format("public class %s extends AbstractGeneratedMethodReader {%n", generatedClassName())); // Inline comment for instances section. sourceCode.append("// instances on which parsed calls are invoked\n"); for (int i = 0; metaDataHandler != null && i < metaDataHandler.length; i++) { - sourceCode.append(format("private final Object metaInstance%d;\n", i)); + sourceCode.append(format("private final Object metaInstance%d;%n", i)); } for (int i = 0; i < instances.length; i++) { - sourceCode.append(format("private final Object instance%d;\n", i)); + sourceCode.append(format("private final Object instance%d;%n", i)); } sourceCode.append("private final WireParselet defaultParselet;\n"); sourceCode.append("\n"); @@ -316,13 +303,13 @@ private void generateSourceCode() { // Initialize metaInstance objects. for (int i = 0; metaDataHandler != null && i < metaDataHandler.length; i++) - sourceCode.append(format("metaInstance%d = metaInstances[%d];\n", i, i)); + sourceCode.append(format("metaInstance%d = metaInstances[%d];%n", i, i)); // Initialize instance objects. for (int i = 0; i < instances.length - 1; i++) - sourceCode.append(format("instance%d = instances[%d];\n", i, i)); + sourceCode.append(format("instance%d = instances[%d];%n", i, i)); - sourceCode.append(format("instance%d = instances[%d];\n}\n\n", instances.length - 1, instances.length - 1)); + sourceCode.append(format("instance%d = instances[%d];%n}%n%n", instances.length - 1, instances.length - 1)); // Override the restIgnored method if chained calls are present. if (hasChainedCalls) { @@ -549,7 +536,7 @@ private void handleMethod(Method m, Class anInterface, String instanceFieldNa // Field setup based on method parameters and interceptor if (parameterTypes.length > 0 || hasRealInterceptorReturns()) - fields.append(format("// %s\n", m.getName())); + fields.append(format("// %s%n", m.getName())); // Iterating through method parameters to setup fields for (int i = 0; i < parameterTypes.length; i++) { @@ -559,13 +546,13 @@ private void handleMethod(Method m, Class anInterface, String instanceFieldNa String fieldName = m.getName() + "arg" + i; if (fieldNames.add(fieldName)) { if (parameterType == Bytes.class) { - fields.append(format("private Bytes %s = Bytes.allocateElasticOnHeap();\n", fieldName)); + fields.append(format("private Bytes %s = Bytes.allocateElasticOnHeap();%n", fieldName)); } else { if (!parameterType.isPrimitive() && !Modifier.isFinal(parameterType.getModifiers()) && multipleNonMarshallableParamTypes(parameterType)) { - fields.append(format("private final Map, %s> %sInstances = new HashMap<>();\n", typeName, typeName, fieldName)); - fields.append(format("private final Function, %s> %sFunc = %sInstances::get;\n", typeName, typeName, fieldName, fieldName)); + fields.append(format("private final Map, %s> %sInstances = new HashMap<>();%n", typeName, typeName, fieldName)); + fields.append(format("private final Function, %s> %sFunc = %sInstances::get;%n", typeName, typeName, fieldName, fieldName)); } - fields.append(format("private %s %s;\n", typeName, fieldName)); + fields.append(format("private %s %s;%n", typeName, fieldName)); } } } @@ -575,7 +562,7 @@ private void handleMethod(Method m, Class anInterface, String instanceFieldNa hasChainedCalls = true; if (hasRealInterceptorReturns()) { - fields.append(format("private final Object[] interceptor%sArgs = new Object[%d];\n", + fields.append(format("private final Object[] interceptor%sArgs = new Object[%d];%n", m.getName(), parameterTypes.length)); String parameterTypesArg = parameterTypes.length == 0 ? "" : @@ -584,7 +571,7 @@ private void handleMethod(Method m, Class anInterface, String instanceFieldNa .map(s -> s + ".class") .collect(Collectors.joining(", ")); - fields.append(format("private static final Method %smethod = lookupMethod(%s.class, \"%s\"%s);\n", + fields.append(format("private static final Method %smethod = lookupMethod(%s.class, \"%s\"%s);%n", m.getName(), anInterface.getCanonicalName(), m.getName(), parameterTypesArg)); } @@ -602,7 +589,7 @@ private void handleMethod(Method m, Class anInterface, String instanceFieldNa String chainedCallPrefix = chainReturnType != null ? "chainedCallReturnResult = " : ""; // Handling code generation for event name switch block - eventNameSwitchBlock.append(format("case \"%s\":\n", m.getName())); + eventNameSwitchBlock.append(format("case \"%s\":%n", m.getName())); if (parameterTypes.length == 0) { eventNameSwitchBlock.append("valueIn.skipValue();\n"); eventNameSwitchBlock.append(methodCall(m, instanceFieldName, chainedCallPrefix, chainReturnType)); @@ -676,9 +663,9 @@ private void handleMethod(Method m, Class anInterface, String instanceFieldNa */ private void addMethodIdSwitch(String methodName, int methodId, SourceCodeFormatter eventIdSwitchBlock) { // Append the switch case based on method ID - eventIdSwitchBlock.append(format("case %d:\n", methodId)); + eventIdSwitchBlock.append(format("case %d:%n", methodId)); // Set the last executed method's name - eventIdSwitchBlock.append(format("lastEventName = \"%s\";\n", methodName)); + eventIdSwitchBlock.append(format("lastEventName = \"%s\";%n", methodName)); // End of the switch case eventIdSwitchBlock.append("break;\n\n"); } @@ -812,16 +799,17 @@ private String argumentRead(Method m, int argIndex, boolean inLambda, Type[] par // If numeric conversion is available and has a shared instance. if (numericConversionClass != null && hasInstance(numericConversionClass)) { return format("%s = (byte) %s.INSTANCE.parse(%s.text());\n", argumentName, numericConversionClass.getName(), valueInName); - } + } else if (numericConversionClass != null && LongConverter.class.isAssignableFrom(numericConversionClass)) { // If numeric conversion is available and is an instance of LongConverter. - else if (numericConversionClass != null && LongConverter.class.isAssignableFrom(numericConversionClass)) { // Register a converter for this type. numericConverters.append(format("private final %s %sConverter = ObjectUtils.newInstance(%s.class);\n", numericConversionClass.getCanonicalName(), trueArgumentName, numericConversionClass.getCanonicalName())); return format("%s = (byte) %sConverter.parse(%s.text());\n", argumentName, argumentName, valueInName); - } else // Default byte reading logic. + } else { + // Default byte reading logic. return format("%s = %s.readByte();\n", argumentName, valueInName); + } } else if (char.class.equals(argumentType)) { // Handling character type arguments. return format("%s = %s.character();\n", argumentName, valueInName); @@ -835,8 +823,9 @@ else if (numericConversionClass != null && LongConverter.class.isAssignableFrom( numericConversionClass.getCanonicalName(), trueArgumentName, numericConversionClass.getCanonicalName())); return format("%s = (short) %sConverter.parse(%s.text());\n", argumentName, argumentName, valueInName); - } else + } else { return format("%s = %s.int16();\n", argumentName, valueInName); + } } else if (int.class.equals(argumentType)) { // Generate code based on the type of the argument and presence of numeric conversion. if (numericConversionClass != null && hasInstance(numericConversionClass)) { @@ -847,8 +836,9 @@ else if (numericConversionClass != null && LongConverter.class.isAssignableFrom( numericConversionClass.getCanonicalName(), trueArgumentName, numericConversionClass.getCanonicalName())); return format("%s = (int) %sConverter.parse(%s.text());\n", argumentName, argumentName, valueInName); - } else + } else { return format("%s = %s.int32();\n", argumentName, valueInName); + } } else if (long.class.equals(argumentType)) { // Generate code based on the type of the argument and presence of numeric conversion. if (numericConversionClass != null && hasInstance(numericConversionClass)) { @@ -901,10 +891,10 @@ private static boolean isRecyclable(Class argumentType) { * based on {@link #multipleNonMarshallableParamTypes} and the type itself. */ private boolean multipleNonMarshallableParamTypes(Class argumentType) { - Boolean _multipleNonMarshallableParamTypes = this.multipleNonMarshallableParamTypes; - return _multipleNonMarshallableParamTypes == null + Boolean cachedMultipleNonMarshallableParamTypes = this.multipleNonMarshallableParamTypes; + return cachedMultipleNonMarshallableParamTypes == null ? argumentType.isInterface() && !isRecyclable(argumentType) || argumentType == Object.class - : _multipleNonMarshallableParamTypes; + : cachedMultipleNonMarshallableParamTypes; } /** diff --git a/src/main/java/net/openhft/chronicle/wire/GenerateMethodWriter.java b/src/main/java/net/openhft/chronicle/wire/GenerateMethodWriter.java index be2edf1a47..9765539c49 100644 --- a/src/main/java/net/openhft/chronicle/wire/GenerateMethodWriter.java +++ b/src/main/java/net/openhft/chronicle/wire/GenerateMethodWriter.java @@ -32,6 +32,7 @@ import static java.util.Collections.*; import static net.openhft.chronicle.core.util.GenericReflection.erase; import static net.openhft.chronicle.core.util.GenericReflection.getParameterTypes; + /** * Dynamically generates and compiles Java code for method writer proxies. The * generated proxy serialises invocations to a {@link MarshallableOut} @@ -142,7 +143,7 @@ public class GenerateMethodWriter { // Concurrent map to cache method writers private final ConcurrentMap, String> methodWritersMap = new ConcurrentHashMap<>(); // AtomicInteger to manage indentation in the generated code - final private AtomicInteger indent = new AtomicInteger(); + private final AtomicInteger indent = new AtomicInteger(); // Indicates if verbose types are used in the generated method writer private final boolean verboseTypes; @@ -150,16 +151,16 @@ public class GenerateMethodWriter { * Internal constructor used by {@link #newClass}. * All parameters configure a single proxy generation run. * - * @param packageName The package name for the generated method writer. - * @param interfaces The interfaces to be implemented by the generated method writer. - * @param className The name of the generated class. - * @param classLoader The class loader to use. - * @param wireType The wire type for serialization. - * @param genericEvent The generic event type. - * @param metaData Indicates if metadata should be included. - * @param useMethodId Indicates if method ID should be used. + * @param packageName The package name for the generated method writer. + * @param interfaces The interfaces to be implemented by the generated method writer. + * @param className The name of the generated class. + * @param classLoader The class loader to use. + * @param wireType The wire type for serialization. + * @param genericEvent The generic event type. + * @param metaData Indicates if metadata should be included. + * @param useMethodId Indicates if method ID should be used. * @param useUpdateInterceptor Indicates if the update interceptor should be used. - * @param verboseTypes Indicates if verbose types should be used. + * @param verboseTypes Indicates if verbose types should be used. */ private GenerateMethodWriter(final String packageName, final Set> interfaces, @@ -187,17 +188,17 @@ private GenerateMethodWriter(final String packageName, /** * Creates and compiles a new method writer class based on the provided interface class. * - * @param fullClassName Fully qualified class name for the generated proxy class. - * @param interfaces A set of interface classes that the generated proxy class will implement. - * @param classLoader The class loader to use for generating the proxy class. - * @param wireType The wire type for serialization. - * @param genericEvent The generic event type. - * @param metaData Indicates if metadata should be included. - * @param useMethodId Indicates if {@link MethodId} should be used. - * @param useUpdateInterceptor Indicates if the {@link UpdateInterceptor} should be used. - * @param verboseTypes Indicates if verbose types should be used. - * @return A generated proxy class based on the provided interface class, - * or {@code null} if it can't be created. + * @param fullClassName Fully qualified class name for the generated proxy class. + * @param interfaces A set of interface classes that the generated proxy class will implement. + * @param classLoader The class loader to use for generating the proxy class. + * @param wireType The wire type for serialization. + * @param genericEvent The generic event type. + * @param metaData Indicates if metadata should be included. + * @param useMethodId Indicates if {@link MethodId} should be used. + * @param useUpdateInterceptor Indicates if the {@link UpdateInterceptor} should be used. + * @param verboseTypes Indicates if verbose types should be used. + * @return A generated proxy class based on the provided interface class, + * or {@code null} if it can't be created. */ @Nullable public static Class newClass(String fullClassName, @@ -228,10 +229,10 @@ public static Class newClass(String fullClassName, * Acquires a {@link DocumentContext} instance, either by reusing the existing one from the thread-local * context holder if it's not closed or by creating a new one using the provided output. * - * @param metaData Indicates if metadata should be included in the {@link DocumentContext}. - * @param documentContextTL The thread-local holder of the {@link DocumentContext}. - * @param out The output where the document will be written. - * @return An instance of {@link DocumentContext}. + * @param metaData Indicates if metadata should be included in the {@link DocumentContext}. + * @param documentContextTL The thread-local holder of the {@link DocumentContext}. + * @param out The output where the document will be written. + * @return An instance of {@link DocumentContext}. */ @SuppressWarnings("unused") public static DocumentContext acquireDocumentContext(boolean metaData, @@ -249,8 +250,8 @@ public static DocumentContext acquireDocumentContext(boolean metaData, * Converts a class type into a representative string, e.g., int to "int32", boolean to "bool", etc. * For types not explicitly mapped, a default representation is returned. * - * @param type The class type to be converted. - * @return A representative string for the given class type. + * @param type The class type to be converted. + * @return A representative string for the given class type. */ private static CharSequence toString(Class type) { if (boolean.class.equals(type)) { @@ -280,8 +281,8 @@ private static CharSequence toString(Class type) { /** * Retrieves the full canonical name of a class, with any '$' characters replaced by '.'. * - * @param type The class for which the name is required. - * @return The full name of the class with '$' characters replaced. + * @param type The class for which the name is required. + * @return The full name of the class with '$' characters replaced. */ @NotNull private static String nameForClass(Class type) { @@ -293,9 +294,9 @@ private static String nameForClass(Class type) { * If the type is part of the provided import set, or if it belongs to the "java.lang" package, * only the simple name of the class is returned. Otherwise, the full canonical name is returned. * - * @param importSet A set of class names or package patterns that have been imported. - * @param type The class for which the name is required. - * @return The appropriate name of the class based on the import context. + * @param importSet A set of class names or package patterns that have been imported. + * @param type The class for which the name is required. + * @return The appropriate name of the class based on the import context. */ @NotNull private static String nameForClass(Set importSet, Class type) { @@ -315,9 +316,9 @@ private static String nameForClass(Set importSet, Class type) { * Constructs a method signature string for a given method and type. * The signature string includes the return type, method name, and parameter types. * - * @param m The method for which the signature is to be generated. - * @param type The type that might contain the method. - * @return A string representing the method signature. + * @param m The method for which the signature is to be generated. + * @param type The type that might contain the method. + * @return A string representing the method signature. */ private static String signature(Method m, Type type) { final Type returnType = GenericReflection.getReturnType(m, type); @@ -328,8 +329,8 @@ private static String signature(Method m, Type type) { /** * Checks if a given modifier represents a synthetic entity. * - * @param modifiers The modifiers to check. - * @return True if the modifier is synthetic, false otherwise. + * @param modifiers The modifiers to check. + * @return True if the modifier is synthetic, false otherwise. */ static boolean isSynthetic(int modifiers) { return (modifiers & SYNTHETIC) != 0; // Check the SYNTHETIC flag in the modifiers @@ -339,10 +340,10 @@ static boolean isSynthetic(int modifiers) { * Constructs the method signature for a method, considering its annotations, * parameters, and the provided import set. * - * @param importSet The set of imported classes or packages. - * @param dm The method for which the signature is required. - * @param parameterTypes The parameter types for the method. - * @return An {@link Appendable} containing the method signature. + * @param importSet The set of imported classes or packages. + * @param dm The method for which the signature is required. + * @param parameterTypes The parameter types for the method. + * @return An {@link Appendable} containing the method signature. */ @NotNull private Appendable methodSignature(SortedSet importSet, final Method dm, Type[] parameterTypes) { @@ -535,10 +536,10 @@ private Class createClass() { * It makes use of {@code GenericReflection} to get the return type and, if the return type isn't a class instance, * it attempts to resolve it as a generic declaration. * - * @param dm The method whose return type needs to be determined. + * @param dm The method whose return type needs to be determined. * @param interfaceClazz The interface class relative to which the method's return type is evaluated. * @return The class type of the method's return type. - */ + */ private Class returnType(Method dm, Class interfaceClazz) { Type returnType = GenericReflection.getReturnType(dm, interfaceClazz); if (!(returnType instanceof Class)) @@ -550,7 +551,7 @@ private Class returnType(Method dm, Class interfaceClazz) { * Looks up a template for a given method and interface type. * The method searches for predefined templates using the method's name. * - * @param dm The method for which a template is required. + * @param dm The method for which a template is required. * @param interfaceType The interface type in which the method is defined. * @return The template string if found, otherwise {@code null}. */ @@ -577,7 +578,7 @@ private void addMarshallableOut(SourceCodeFormatter codeFormatter) { codeFormatter.append("public void marshallableOut(MarshallableOut out) {\n"); codeFormatter.append("this.out = () -> out;"); for (Map.Entry, String> e : methodWritersMap.entrySet()) { - codeFormatter.append(format("\n this.%s.remove();", e.getValue())); + codeFormatter.append(format("%n this.%s.remove();", e.getValue())); } codeFormatter.append("\n}\n"); @@ -587,9 +588,9 @@ private void addMarshallableOut(SourceCodeFormatter codeFormatter) { * Constructs the source code for class fields and the class constructor. * The method defines the state of the generated class and provides a constructor to initialize this state. * - * @param importSet The set of classes that need to be imported. - * @param className The name of the generated class. - * @param result The formatter that helps structure the generated source code. + * @param importSet The set of classes that need to be imported. + * @param className The name of the generated class. + * @param result The formatter that helps structure the generated source code. * @return The structured source code containing the fields and constructor for the generated class. */ private CharSequence constructorAndFields(Set importSet, final String className, SourceCodeFormatter result) { @@ -597,27 +598,27 @@ private CharSequence constructorAndFields(Set importSet, final String cl result.append("// result\n" + "private transient final Closeable closeable;\n"); if (useUpdateInterceptor) - result.append("private transient final " + UPDATE_INTERCEPTOR + " " + UPDATE_INTERCEPTOR_FIELD + ";\n"); + result.append("private transient final ").append(UPDATE_INTERCEPTOR).append(" ").append(UPDATE_INTERCEPTOR_FIELD).append(";\n"); result.append("private transient Supplier<") .append(MARSHALLABLE_OUT) .append("> out;\n"); for (Map.Entry, String> e : methodWritersMap.entrySet()) { - result.append(format("private transient ThreadLocal<%s> %s;\n", nameForClass(importSet, e.getKey()), e.getValue())); + result.append(format("private transient ThreadLocal<%s> %s;%n", nameForClass(importSet, e.getKey()), e.getValue())); } result.append('\n'); - result.append(format("// constructor\npublic %s(Supplier<" + MARSHALLABLE_OUT + "> out, " + result.append(format("// constructor%npublic %s(Supplier<" + MARSHALLABLE_OUT + "> out, " + CLOSEABLE + " closeable, " + - UpdateInterceptor.class.getSimpleName() + " " + UPDATE_INTERCEPTOR_FIELD + ") {\n", className)); + UpdateInterceptor.class.getSimpleName() + " " + UPDATE_INTERCEPTOR_FIELD + ") {%n", className)); if (useUpdateInterceptor) result.append("this." + UPDATE_INTERCEPTOR_FIELD + "= " + UPDATE_INTERCEPTOR_FIELD + ";\n"); result.append("this.out = out;\n" + "this.closeable = closeable;"); for (Map.Entry, String> e : methodWritersMap.entrySet()) { - result.append(format("\n%s = ThreadLocal.withInitial(() -> out.get().methodWriter(%s.class));", e.getValue(), nameForClass(e.getKey()))); - result.append(format("\n%s = ThreadLocal.withInitial(() -> out.get().methodWriterBuilder(%s.class)" + + result.append(format("%n%s = ThreadLocal.withInitial(() -> out.get().methodWriter(%s.class));", e.getValue(), nameForClass(e.getKey()))); + result.append(format("%n%s = ThreadLocal.withInitial(() -> out.get().methodWriterBuilder(%s.class)" + ".verboseTypes(%b).build());", e.getValue(), nameForClass(e.getKey()), verboseTypes)); } @@ -628,10 +629,10 @@ private CharSequence constructorAndFields(Set importSet, final String cl /** * Creates the method writer code for a given method. * - * @param importSet The set of imports required for the method - * @param dm The method for which the writer code is to be generated + * @param importSet The set of imports required for the method + * @param dm The method for which the writer code is to be generated * @param interfaceClazz The class of the interface being processed - * @param methodIds The set of method IDs to track the generated methods + * @param methodIds The set of method IDs to track the generated methods * @return A CharSequence containing the generated method writer code */ private CharSequence createMethod(SortedSet importSet, final Method dm, final Class interfaceClazz, Set methodIds) { @@ -653,7 +654,6 @@ private CharSequence createMethod(SortedSet importSet, final Method dm, final String typeName = nameForClass(importSet, returnType); final StringBuilder body = new StringBuilder(); - String methodIDAnotation = ""; final Type[] parameterTypes = getParameterTypes(dm, interfaceClazz); // UpdateInterceptor logic @@ -666,16 +666,15 @@ private CharSequence createMethod(SortedSet importSet, final Method dm, if (type instanceof Class && ((Class) type).isPrimitive()) Jvm.warn().on(getClass(), "Generated code to call updateInterceptor for " + dm + " will box and generate garbage"); name = parameters[parameterCount - 1].getName(); - } else + } else { name = "null"; - body.append("// updateInterceptor\n" - + "if (! this." + UPDATE_INTERCEPTOR_FIELD + - ".update(\"" + dm.getName() + "\", " + name + ")) return" + returnDefault(returnType) + ";\n"); + } + body.append("// updateInterceptor\n" + "if (! this." + UPDATE_INTERCEPTOR_FIELD + ".update(\"").append(dm.getName()).append("\", ").append(name).append(")) return").append(returnDefault(returnType)).append(";\n"); } body.append("MarshallableOut out = this.out.get();\n"); - boolean terminating = returnType == Void.class || returnType == void.class || returnType.isPrimitive(); - boolean passthrough = returnType == DocumentContext.class; + final boolean terminating = returnType == Void.class || returnType == void.class || returnType.isPrimitive(); + final boolean passthrough = returnType == DocumentContext.class; // MarshallableOut setup logic if (!passthrough) @@ -691,7 +690,7 @@ private CharSequence createMethod(SortedSet importSet, final Method dm, else body.append(") {\n"); body.append("try {\n"); - body.append("_dc_.chainedElement(" + (!terminating && !passthrough) + ");\n"); + body.append("_dc_.chainedElement(").append(!terminating && !passthrough).append(");\n"); body.append("if (out.recordHistory()) MessageHistory.writeHistory(_dc_);\n"); int startJ = 0; @@ -706,11 +705,11 @@ private CharSequence createMethod(SortedSet importSet, final Method dm, } // Determine the appropriate event name or ID for the method - methodIDAnotation = writeEventNameOrId(dm, body, eventName); + final String methodIdAnnotation = writeEventNameOrId(dm, body, eventName); // Check for duplicate method IDs and throw an exception if a duplicate is found - if (methodIDAnotation.length() > 0 && !methodIds.add(methodIDAnotation)) - throw new MethodWriterValidationException("Duplicate methodIds. Cannot add " + methodIDAnotation + " to " + methodIds); + if (!methodIdAnnotation.isEmpty() && !methodIds.add(methodIdAnnotation)) + throw new MethodWriterValidationException("Duplicate methodIds. Cannot add " + methodIdAnnotation + " to " + methodIds); // Write out the parameters for the method, if they exist if (parameters.length > 0) @@ -736,8 +735,8 @@ private CharSequence createMethod(SortedSet importSet, final Method dm, body.append("}\n"); // Return the formatted method writer code - return format("\n%s public %s %s(%s) {\n %s%s}\n", - methodIDAnotation, + return format("%n%s public %s %s(%s) {%n %s%s}%n", + methodIdAnnotation, typeName, dm.getName(), methodSignature(importSet, dm, parameterTypes), @@ -780,11 +779,12 @@ private String writeEventNameOrId(final Method dm, final StringBuilder body, fin if ((wireType != WireType.TEXT && wireType != WireType.YAML) && methodId.isPresent()) { long value = ((MethodId) methodId.get()).value(); - body.append(format("final " + VALUE_OUT + " _valueOut_ = _dc_.wire().writeEventId(%s, %d);\n", eventName, value)); - methodID = format("@" + METHOD_ID + "(%d)\n", value); + body.append(format("final " + VALUE_OUT + " _valueOut_ = _dc_.wire().writeEventId(%s, %d);%n", eventName, value)); + methodID = format("@" + METHOD_ID + "(%d)%n", value); - } else - body.append(format("final " + VALUE_OUT + " _valueOut_ = _dc_.wire().writeEventName(%s);\n", eventName)); + } else { + body.append(format("final " + VALUE_OUT + " _valueOut_ = _dc_.wire().writeEventName(%s);%n", eventName)); + } return methodID; } @@ -792,11 +792,11 @@ private String writeEventNameOrId(final Method dm, final StringBuilder body, fin * Writes out the parameters for a given method in the desired format. Handles * different parameter types and annotations to generate the appropriate method writer code. * - * @param dm The method whose parameters need to be written out. + * @param dm The method whose parameters need to be written out. * @param parameterTypes An array of the types of the method's parameters. - * @param len The length of the parameters array. - * @param body The StringBuilder used to build the body of the method writer. - * @param startJ Starting index to loop through the parameters. + * @param len The length of the parameters array. + * @param body The StringBuilder used to build the body of the method writer. + * @param startJ Starting index to loop through the parameters. */ private void writeArrayOfParameters(final Method dm, Type[] parameterTypes, final int len, final StringBuilder body, final int startJ) { final int parameterCount = dm.getParameterCount(); @@ -813,14 +813,15 @@ private void writeArrayOfParameters(final Method dm, Type[] parameterTypes, fina // Append appropriate value to the body based on parameter type and annotations if (!name.isEmpty() && (WireType.TEXT == wireType || WireType.YAML == wireType)) - body.append(format("_valueOut_.rawText(%s.INSTANCE.asText(%s));\n", name, p.getName())); + body.append(format("_valueOut_.rawText(%s.INSTANCE.asText(%s));%n", name, p.getName())); else if (p.getType().isPrimitive() || CharSequence.class.isAssignableFrom(p.getType())) { if (longConversion != null && (p.getType() == long.class || CharSequence.class.isAssignableFrom(p.getType()))) - body.append(format("%s.writeLong(%s.INSTANCE, %s);\n", multipleArgs ? "_v_" : "_valueOut_", longConversion.value().getName(), p.getName())); + body.append(format("%s.writeLong(%s.INSTANCE, %s);%n", multipleArgs ? "_v_" : "_valueOut_", longConversion.value().getName(), p.getName())); else - body.append(format("%s.%s(%s);\n", multipleArgs ? "_v_" : "_valueOut_", toString(erase(parameterTypes[j])), p.getName())); - } else + body.append(format("%s.%s(%s);%n", multipleArgs ? "_v_" : "_valueOut_", toString(erase(parameterTypes[j])), p.getName())); + } else { writeValue(dm, erase(parameterTypes[j]), body, startJ, p); + } } // Close the parameter array if there are multiple arguments @@ -831,11 +832,11 @@ else if (p.getType().isPrimitive() || CharSequence.class.isAssignableFrom(p.getT /** * Writes the value of a parameter to the method body, handling various types of parameter values. * - * @param dm The method whose parameter value needs to be written. - * @param type The type of the parameter. - * @param body The StringBuilder used to build the body of the method writer. - * @param startJ The starting index to check if the current parameter is among multiple arguments. - * @param p The parameter whose value is being written. + * @param dm The method whose parameter value needs to be written. + * @param type The type of the parameter. + * @param body The StringBuilder used to build the body of the method writer. + * @param startJ The starting index to check if the current parameter is among multiple arguments. + * @param p The parameter whose value is being written. */ private void writeValue(final Method dm, Class type, final StringBuilder body, final int startJ, final Parameter p) { final String name = p.getName(); @@ -894,7 +895,7 @@ private StringBuilder methodReturn(final Method dm, final Class interfaceClaz } else if (returnType.isInterface()) { methodWritersMap.computeIfAbsent(returnType, k -> "methodWriter" + k.getSimpleName() + "TL"); result.append("// method return\n"); - result.append(format("return methodWriter%sTL.get();\n", returnType.getSimpleName())); + result.append(format("return methodWriter%sTL.get();%n", returnType.getSimpleName())); } else if (!returnType.isPrimitive()) { result.append("return null;\n"); } else if (returnType == boolean.class) { diff --git a/src/main/java/net/openhft/chronicle/wire/GenerateMethodWriter2.java b/src/main/java/net/openhft/chronicle/wire/GenerateMethodWriter2.java index 14009b91d5..20cda6afd4 100644 --- a/src/main/java/net/openhft/chronicle/wire/GenerateMethodWriter2.java +++ b/src/main/java/net/openhft/chronicle/wire/GenerateMethodWriter2.java @@ -18,6 +18,7 @@ import static java.util.Arrays.stream; import static java.util.Collections.*; + /** * The {@code GenerateMethodWriter2} class is responsible for generating method writers based on the provided metadata. *

    @@ -90,9 +91,9 @@ public GenerateMethodWriter2() { * The method looks up the template from the predefined {@code TEMPLATE_METHODS}. If no matching template is * found, it returns {@code null}. * - * @param name The method name to look up + * @param name The method name to look up * @param returnType The return type of the method - * @param pts The parameter types of the method + * @param pts The parameter types of the method * @return The method template as a string, or {@code null} if not found */ private static String templateFor(String name, Class returnType, Class[] pts) { @@ -206,7 +207,7 @@ protected void generateMethod(Method method, StringBuilder params, List if (passthrough) mainCode.append(";\n"); else mainCode.append(") {\n"); - mainCode.append("_dc_.chainedElement(" + (!terminating && !passthrough) + ");\n"); + mainCode.append("_dc_.chainedElement(").append(String.valueOf(!terminating && !passthrough)).append(");\n"); mainCode.append("if (_out_.recordHistory()) MessageHistory.writeHistory(_dc_);\n"); int startJ = 0; @@ -292,9 +293,10 @@ private void writeArrayOfParameters(final Method dm, final SourceCodeFormatter b // For primitive types and CharSequences, write directly if (p.getType().isPrimitive() || CharSequence.class.isAssignableFrom(p.getType())) { body.append(multipleParams ? "v." : ".").append(asString(p.getType())).append("(").append(p.getName()).append(");\n"); - } else + } else { // For non-primitive types, delegate to writeValue writeValue(dm, body, startJ, p); + } } // Close array writing if there were multiple parameters @@ -330,8 +332,8 @@ private void writeValue(final Method dm, final SourceCodeFormatter body, final i * Determines the return value based on the method's return type and available interfaces. * The method ensures that the correct return type or default value is appended to the result. * - * @param result The code formatter to which the return value should be appended. - * @param method The method whose return value needs to be determined. + * @param result The code formatter to which the return value should be appended. + * @param method The method whose return value needs to be determined. * @param interfaceClases Set of interfaces to determine if the return type matches any. */ private void methodReturn(SourceCodeFormatter result, final Method method, final Set> interfaceClases) { @@ -416,6 +418,7 @@ public GMWMetaData useMethodIds(boolean useMethodIds) { * * @return The generic event string. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public String genericEvent() { return genericEvent; } diff --git a/src/main/java/net/openhft/chronicle/wire/GeneratedProxyClass.java b/src/main/java/net/openhft/chronicle/wire/GeneratedProxyClass.java index a6a1c47713..9db1be30ee 100644 --- a/src/main/java/net/openhft/chronicle/wire/GeneratedProxyClass.java +++ b/src/main/java/net/openhft/chronicle/wire/GeneratedProxyClass.java @@ -20,6 +20,7 @@ * format for the proxy class. Furthermore, it provides an option to dump the generated code for debugging purposes. */ @SuppressWarnings("restriction") +@Deprecated(/* to be removed in 2027 */) public enum GeneratedProxyClass { ; // This enum does not have any instances; it is used solely for its static members. @@ -37,6 +38,7 @@ public enum GeneratedProxyClass { * @return The proxy class based on the provided interface classes, or null if it cannot be created. */ @SuppressWarnings("rawtypes") + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static Class from(String packageName, Set interfaces, String className, ClassLoader classLoader) { int maxArgs = 0; Set methods = new LinkedHashSet<>(16); @@ -149,8 +151,7 @@ private static void addFieldsAndConstructor(final int maxArgs, final Set sb.append(" private final MethodWriterInvocationHandlerSupplier handler;\n" + " private final Method[] methods = new Method[") .append(declaredMethods.size()) - .append("];\n") - .append(" private static final int maxArgs = " + maxArgs + ";\n") + .append("];\n").append(" private static final int maxArgs = ").append(maxArgs).append(";\n") .append(" private final ThreadLocal argsTL = " + "ThreadLocal.withInitial(() -> IntStream.range(0, maxArgs + 1)" + ".mapToObj(Object[]::new).toArray(Object[][]::new));\n\n") diff --git a/src/main/java/net/openhft/chronicle/wire/HashWire.java b/src/main/java/net/openhft/chronicle/wire/HashWire.java index 24555ea9ec..6f27fe54e6 100644 --- a/src/main/java/net/openhft/chronicle/wire/HashWire.java +++ b/src/main/java/net/openhft/chronicle/wire/HashWire.java @@ -35,7 +35,7 @@ * instance is obtained from a {@linkplain ThreadLocal thread-local} and the hash * is cleared on retrieval. */ -@SuppressWarnings("rawtypes") +@SuppressWarnings({"rawtypes", "deprecation"}) public class HashWire implements WireOut, HexDumpBytesDescription { // Thread-local storage for HashWire instances. private static final ThreadLocal hwTL = new ThreadLocal() { @@ -443,6 +443,7 @@ public WireOut bytes(@NotNull byte[] fromBytes) { /** Mixes the type name and array content. */ @NotNull @Override + @Deprecated(/* to be removed in 2027 */) public WireOut bytes(@NotNull String type, @NotNull byte[] fromBytes) { hash = hash * M1 + Maths.hash64(type) ^ Maths.hash64(Bytes.wrapForRead(fromBytes)); return HashWire.this; @@ -709,7 +710,6 @@ public void resetState() { /** No-op. */ @Override public void elementSeparator() { - } } } diff --git a/src/main/java/net/openhft/chronicle/wire/InputStreamToWire.java b/src/main/java/net/openhft/chronicle/wire/InputStreamToWire.java index b459b70047..4b933e0687 100644 --- a/src/main/java/net/openhft/chronicle/wire/InputStreamToWire.java +++ b/src/main/java/net/openhft/chronicle/wire/InputStreamToWire.java @@ -27,6 +27,7 @@ * @see InputStream * @see DataInputStream */ +@Deprecated(/* to be removed in 2027, as it is only used in tests */) public class InputStreamToWire { /** diff --git a/src/main/java/net/openhft/chronicle/wire/JSONWire.java b/src/main/java/net/openhft/chronicle/wire/JSONWire.java index a415b5e7b5..91a205804b 100644 --- a/src/main/java/net/openhft/chronicle/wire/JSONWire.java +++ b/src/main/java/net/openhft/chronicle/wire/JSONWire.java @@ -36,7 +36,7 @@ * The core capability of this class is to handle JSON data structures as {@code Bytes} * objects, allowing for efficient manipulation and parsing. */ -@SuppressWarnings("this-escape") +@SuppressWarnings({"this-escape", "deprecation"}) public class JSONWire extends TextWire { // The rest of null @@ -98,6 +98,7 @@ public JSONWire(@NotNull Bytes bytes) { * @return A new instance of JSONWire. */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static JSONWire from(@NotNull String text) { return new JSONWire(Bytes.from(text)); } @@ -109,6 +110,7 @@ public static JSONWire from(@NotNull String text) { * @return The string representation of the JSON content. * @throws InvalidMarshallableException If there's an error during conversion. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static String asText(@NotNull Wire wire) throws InvalidMarshallableException { long pos = wire.bytes().readPosition(); @NotNull JSONWire tw = new JSONWire(nativeBytes()); @@ -156,6 +158,7 @@ public JSONWire useTypes(boolean outputTypes) { * * @return {@code true} if types are being used in the current instance, otherwise {@code false}. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public boolean useTypes() { return useTypes; } @@ -259,9 +262,9 @@ private int peekPreviousByte() { * The segment copied depends on the first character encountered (e.g., '{' indicates a map). * This method understands JSON structural elements and translates them appropriately. * - * @param destWire destination wire to copy the data to. + * @param destWire destination wire to copy the data to. * @param expectKeyValues Flag indicating if the current position is inside a map structure. - * @param topLevel Flag indicating if this is the topmost level of the copy operation. + * @param topLevel Flag indicating if this is the topmost level of the copy operation. * @throws InvalidMarshallableException if there's a problem with copying the data. */ public void copyOne(@NotNull WireOut destWire, boolean expectKeyValues, boolean topLevel) throws InvalidMarshallableException { @@ -429,8 +432,8 @@ private boolean isTypePrefix() { * * @param destWire destination wire * @param quoteChar opening quote character - * @param inMap Flag indicating if the current position is inside a map structure. - * @param topLevel Flag indicating if this is the topmost level of the copy operation. + * @param inMap Flag indicating if the current position is inside a map structure. + * @param topLevel Flag indicating if this is the topmost level of the copy operation. * @throws InvalidMarshallableException if there's a problem with copying the data. */ private void copyQuote(WireOut destWire, int quoteChar, boolean inMap, boolean topLevel) throws InvalidMarshallableException { @@ -649,7 +652,7 @@ void escape(@NotNull CharSequence s) { * This ensures that the resulting string can be safely embedded within a JSON string while preserving its meaning. * See RFC 7159, Section 7 for more details. * - * @param s The CharSequence to escape. + * @param s The CharSequence to escape. * @param quotes Specifies the type of quotes used in the CharSequence and guides escaping. * @see RFC 7159, Section 7 */ @@ -768,7 +771,7 @@ public void close() { * It provides a specialized context for writing JSON data, adjusting writing positions * and handling JSON-specific syntax such as curly braces. * - */ + */ class JSONWriteDocumentContext extends TextWriteDocumentContext { // Position marker to track the start of a JSON object private long start; @@ -850,7 +853,7 @@ public String nullOut() { public JSONWire typeLiteral(@Nullable CharSequence type) { startBlock('{'); - bytes.append("\"@type\":\"" + type + "\""); + bytes.append("\"@type\":\"").append(String.valueOf(type)).append("\""); endBlock('}'); return (JSONWire) wireOut(); @@ -868,7 +871,7 @@ public JSONValueOut typePrefix(@NotNull CharSequence typeName) { bytes.append("\":"); if (nested) { if (valueOutFromStart == null) - valueOutFromStart = new JSONValueOutFromStart(); + valueOutFromStart = new JSONValueOutFromStart(); return valueOutFromStart; } } @@ -1101,8 +1104,8 @@ private Type consumeTypeLiteral(BiFunction E parseType(@Nullable E using, @Nullable Class clazz, boolean bestEffort) throws InvalidMarshallableException { @@ -1298,6 +1301,7 @@ void readTypeDefinition(StringBuilder sb) { * * @return true if types are being used, false otherwise. */ + @Deprecated(/* to be removed in 2027 */) public boolean useTypes() { return useTypes; } diff --git a/src/main/java/net/openhft/chronicle/wire/LongArrayValueBitSet.java b/src/main/java/net/openhft/chronicle/wire/LongArrayValueBitSet.java index 4430471678..17e64c627f 100644 --- a/src/main/java/net/openhft/chronicle/wire/LongArrayValueBitSet.java +++ b/src/main/java/net/openhft/chronicle/wire/LongArrayValueBitSet.java @@ -78,6 +78,7 @@ private static int wordIndex(int bitIndex) { * @param bytes The byte array to be used for constructing the {@code BitSet}. * @return A new {@code BitSet} containing all bits from the given byte array. */ + @Deprecated(/* to be removed in 2027 */) public static BitSet valueOf(byte[] bytes) { return BitSet.valueOf(ByteBuffer.wrap(bytes)); } @@ -170,6 +171,7 @@ private Pauser pauser() { * @param word The {@code LongValue} instance representing the word to set. * @param newValue The new value to set for the word. */ + @Deprecated(/* to be removed in 2027 */) public void set(LongValue word, long newValue) { throwExceptionIfClosed(); @@ -186,6 +188,7 @@ public void set(LongValue word, long newValue) { * * @return A byte array containing all the bits in this bit set. */ + @Deprecated(/* to be removed in 2027 */) public byte[] toByteArray() { throwExceptionIfClosed(); @@ -569,6 +572,7 @@ public int nextClearBit(int fromIndex) { * @param fromIndex The index to start the reverse search from (inclusive). * @return Index of the previous set bit or {@code -1} if no set bit is found. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public int previousSetBit(int fromIndex) { throwExceptionIfClosed(); @@ -606,6 +610,7 @@ public int previousSetBit(int fromIndex) { * @param fromIndex The index to start the reverse search from (inclusive). * @return Index of the previous clear bit or {@code -1} if no clear bit is found. */ + @Deprecated(/* to be removed in 2027 */) public int previousClearBit(int fromIndex) { throwExceptionIfClosed(); @@ -860,6 +865,7 @@ public String toString() { * * @return An ordered IntStream of indices of bits set to true. */ + @Deprecated(/* to be removed in 2027 */) public IntStream stream() { throwExceptionIfClosed(); diff --git a/src/main/java/net/openhft/chronicle/wire/LongConverter.java b/src/main/java/net/openhft/chronicle/wire/LongConverter.java index 5df3984068..303db54b12 100644 --- a/src/main/java/net/openhft/chronicle/wire/LongConverter.java +++ b/src/main/java/net/openhft/chronicle/wire/LongConverter.java @@ -123,6 +123,7 @@ default String asString(long numericValue) { * @param numericValue the integer value to convert * @return The CharSequence representation of the value. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default CharSequence asText(int numericValue) { return asText(numericValue & 0xFFFF_FFFFL); } @@ -180,6 +181,7 @@ default void lengthCheck(CharSequence textToCheck, int beginIndex, int endIndex) * * @return {@code true} if no characters need escaping or additional quoting for JSON or YAML, {@code false} otherwise. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default boolean allSafeChars() { return true; } diff --git a/src/main/java/net/openhft/chronicle/wire/LongValueBitSet.java b/src/main/java/net/openhft/chronicle/wire/LongValueBitSet.java index 390ba65068..e51ddaccfa 100644 --- a/src/main/java/net/openhft/chronicle/wire/LongValueBitSet.java +++ b/src/main/java/net/openhft/chronicle/wire/LongValueBitSet.java @@ -102,6 +102,7 @@ private static int wordIndex(int bitIndex) { * @param bytes The byte array containing the bits. * @return A BitSet containing the bits from the byte array. */ + @Deprecated(/* to be removed in 2027 */) public static BitSet valueOf(byte[] bytes) { return BitSet.valueOf(ByteBuffer.wrap(bytes)); } @@ -190,6 +191,7 @@ private Pauser pauser() { * Atomically sets {@code word} to {@code newValue}. A CAS loop is used * with {@link #pauser()} invoked between attempts when contention occurs. */ + @Deprecated(/* to be removed in 2027 */) public void set(LongValue word, long newValue) { throwExceptionIfClosed(); @@ -204,6 +206,7 @@ public void set(LongValue word, long newValue) { * Returns a little‑endian byte array representing this set. Each word * is written in sequence. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public byte[] toByteArray() { throwExceptionIfClosed(); @@ -602,6 +605,7 @@ public int nextClearBit(int fromIndex) { * @return The index of the nearest set bit (with value {@code true}) before the specified starting index, or {@code -1} if none exists. * @throws IndexOutOfBoundsException if {@code fromIndex} is less than {@code -1} */ + @Deprecated(/* to be removed in 2027 */) public int previousSetBit(int fromIndex) { throwExceptionIfClosed(); @@ -637,6 +641,7 @@ public int previousSetBit(int fromIndex) { * @return The index of the nearest unset bit (with value {@code false}) before the specified starting index, or {@code -1} if none exists. * @throws IndexOutOfBoundsException if {@code fromIndex} is less than {@code -1} */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public int previousClearBit(int fromIndex) { throwExceptionIfClosed(); @@ -687,6 +692,7 @@ public boolean intersects(ChronicleBitSet set) { * @param set The {@code LongValueBitSet} to compare with the current instance. * @return {@code true} if there's an intersection, otherwise {@code false}. */ + @Deprecated(/* to be removed in 2027 */) public boolean intersects(LongValueBitSet set) { return intersects((ChronicleBitSet) set); } @@ -736,6 +742,7 @@ public void and(ChronicleBitSet set) { * * @param set The {@code LongValueBitSet} to perform the logical AND operation with. */ + @Deprecated(/* to be removed in 2027 */) public void and(LongValueBitSet set) { and((ChronicleBitSet) set); } @@ -746,6 +753,7 @@ public void and(LongValueBitSet set) { * * @param set The {@code LongValueBitSet} to perform the logical OR operation with. */ + @Deprecated(/* to be removed in 2027 */) public void or(LongValueBitSet set) { or((ChronicleBitSet) set); } @@ -812,6 +820,7 @@ public void xor(ChronicleBitSet set) { * * @param set The {@code LongValueBitSet} to perform the logical XOR operation with. */ + @Deprecated(/* to be removed in 2027 */) public void xor(LongValueBitSet set) { xor((ChronicleBitSet) set); } @@ -838,6 +847,7 @@ public void andNot(ChronicleBitSet set) { * * @param set The {@code LongValueBitSet} to use for clearing matching bits. */ + @Deprecated(/* to be removed in 2027 */) public void andNot(LongValueBitSet set) { andNot((ChronicleBitSet) set); } @@ -932,9 +942,11 @@ public String toString() { * Returns a stream of indices for which this {@code ChronicleBitSet} contains a bit in the set state. The indices are returned in order, from lowest to * highest. The size of the stream is the number of bits in the set state, equal to the value returned by the {@link #cardinality()} method. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public IntStream stream() { throwExceptionIfClosed(); + @Deprecated(/* to be removed in 2027, as it is only used in tests */) class BitSetIterator implements PrimitiveIterator.OfInt { int next = nextSetBit(0); diff --git a/src/main/java/net/openhft/chronicle/wire/Marshallable.java b/src/main/java/net/openhft/chronicle/wire/Marshallable.java index 647f0165ed..c5e20ab946 100644 --- a/src/main/java/net/openhft/chronicle/wire/Marshallable.java +++ b/src/main/java/net/openhft/chronicle/wire/Marshallable.java @@ -19,6 +19,7 @@ import java.util.function.Function; import java.util.stream.Stream; +import static java.nio.charset.StandardCharsets.UTF_8; import static net.openhft.chronicle.wire.WireMarshaller.WIRE_MARSHALLER_CL; import static net.openhft.chronicle.wire.WireType.TEXT; @@ -33,13 +34,14 @@ * forms. */ @DontChain +@SuppressWarnings("deprecation") public interface Marshallable extends WriteMarshallable, ReadMarshallable, Resettable { /** * Compares a given {@code WriteMarshallable} object with another object for equality. * * @param $this The reference {@code WriteMarshallable} object. - * @param o The object to compare with. + * @param o The object to compare with. * @return {@code true} if both objects are equal, {@code false} otherwise. */ static boolean $equals(@NotNull WriteMarshallable $this, Object o) { @@ -83,7 +85,7 @@ static T fromString(@NotNull CharSequence cs) throws InvalidMarshallableExce * expecting a specific type as the result. * * @param tClass The expected class of the resulting object. - * @param cs The character sequence to convert. + * @param cs The character sequence to convert. * @return The corresponding marshallable object of type {@code T}, or {@code null} if the conversion is not possible. */ @Nullable @@ -111,7 +113,7 @@ static T fromFile(String filename) throws IOException, InvalidMarshallableEx * @return The corresponding marshallable object, or {@code null} if the conversion is not possible. */ static T fromString(@NotNull InputStream is) throws InvalidMarshallableException { - Scanner s = new Scanner(is).useDelimiter("\\A"); + Scanner s = new Scanner(is, UTF_8.name()).useDelimiter("\\A"); return TEXT.fromString(s.hasNext() ? s.next() : ""); } @@ -120,7 +122,7 @@ static T fromString(@NotNull InputStream is) throws InvalidMarshallableExcep * content as a marshallable object of a specific type. * * @param expectedType The expected type of the resulting object. - * @param filename The name or path of the file to read. + * @param filename The name or path of the file to read. * @return The marshallable object interpreted from the file content. */ @Nullable @@ -143,10 +145,11 @@ static Stream streamFromFile(String filename) throws IOException { * Streams the content of a file as marshallable objects of a specific type. * * @param expectedType The expected type of the resulting objects in the stream. - * @param filename The name or path of the file to read. + * @param filename The name or path of the file to read. * @return A stream of marshallable objects of type {@code T}. */ @Nullable + @Deprecated(/* to be removed in 2027, as it is only used in tests */) static Stream streamFromFile(@NotNull Class expectedType, String filename) throws IOException { return TEXT.streamFromFile(expectedType, filename); } @@ -155,7 +158,7 @@ static Stream streamFromFile(@NotNull Class expectedType, String filen * Retrieves the value of a specific field from the current marshallable object, expecting * a certain type for the field's value. * - * @param name The name of the field. + * @param name The name of the field. * @param tClass The expected class/type of the field's value. * @return The value of the specified field. */ @@ -167,7 +170,7 @@ default T getField(String name, Class tClass) throws NoSuchFieldException /** * Sets the value of a specific field in the current marshallable object. * - * @param name The name of the field. + * @param name The name of the field. * @param value The new value for the specified field. */ default void setField(String name, Object value) throws NoSuchFieldException { @@ -187,9 +190,10 @@ default long getLongField(String name) throws NoSuchFieldException { /** * Sets the long value of a specific field in the current marshallable object. * - * @param name The name of the field. + * @param name The name of the field. * @param value The new long value for the specified field. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default void setLongField(String name, long value) throws NoSuchFieldException { Wires.setLongField(this, name, value); } @@ -250,9 +254,9 @@ default T deepCopy() throws InvalidMarshallableException { * Copy fields from this to dest by marshalling out and then in. Allows copying of fields by name * even if there is no type relationship between this and dest * + * @param destination type * @param dest destination * @return t - * @param destination type */ default T copyTo(@NotNull T dest) throws InvalidMarshallableException { return Wires.copyTo(this, dest); @@ -261,7 +265,7 @@ default T copyTo(@NotNull T dest) throws InvalidMarshal /** * Merges the current marshallable object into a map, using a specified function to determine the key. * - * @param map The map to merge into. + * @param map The map to merge into. * @param getKey The function to determine the key for the current object in the map. * @return The merged marshallable object in the map. */ diff --git a/src/main/java/net/openhft/chronicle/wire/MarshallableOut.java b/src/main/java/net/openhft/chronicle/wire/MarshallableOut.java index fab465697c..0287689928 100644 --- a/src/main/java/net/openhft/chronicle/wire/MarshallableOut.java +++ b/src/main/java/net/openhft/chronicle/wire/MarshallableOut.java @@ -32,6 +32,7 @@ public interface MarshallableOut extends DocumentWritten, RollbackIfNotCompleteN * @param url The URL which will dictate the specific type of {@code MarshallableOut} to create. * @return A new instance of {@code MarshallableOutBuilder}. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) static MarshallableOutBuilder builder(URL url) { return new MarshallableOutBuilder(url); } @@ -88,6 +89,7 @@ default boolean recordHistory() { * @param key to write * @param value to write with it. */ + @Deprecated(/* to be removed in 2027 */) default void writeMessage(WireKey key, Object value) throws UnrecoverableTimeoutException { @NotNull DocumentContext dc = writingDocument(); try { diff --git a/src/main/java/net/openhft/chronicle/wire/MarshallableOutBuilder.java b/src/main/java/net/openhft/chronicle/wire/MarshallableOutBuilder.java index 2337c3ffce..2cee057a9c 100644 --- a/src/main/java/net/openhft/chronicle/wire/MarshallableOutBuilder.java +++ b/src/main/java/net/openhft/chronicle/wire/MarshallableOutBuilder.java @@ -15,6 +15,7 @@ * The class follows the builder pattern, enabling the caller to set desired configurations and then retrieve * the appropriate {@code MarshallableOut} implementation based on the URL's protocol. */ +@Deprecated(/* to be removed in 2027, as it is only used in tests */) public class MarshallableOutBuilder implements Supplier { // The URL for which the MarshallableOut instance will be created. diff --git a/src/main/java/net/openhft/chronicle/wire/MarshallableParser.java b/src/main/java/net/openhft/chronicle/wire/MarshallableParser.java index f7f1131d0b..2eacae307f 100644 --- a/src/main/java/net/openhft/chronicle/wire/MarshallableParser.java +++ b/src/main/java/net/openhft/chronicle/wire/MarshallableParser.java @@ -14,6 +14,7 @@ * @param the type produced after parsing the input value */ @FunctionalInterface +@Deprecated(/* to be removed in 2027 */) public interface MarshallableParser { /** diff --git a/src/main/java/net/openhft/chronicle/wire/MessageHistory.java b/src/main/java/net/openhft/chronicle/wire/MessageHistory.java index 1c02bec095..1c28c2889d 100644 --- a/src/main/java/net/openhft/chronicle/wire/MessageHistory.java +++ b/src/main/java/net/openhft/chronicle/wire/MessageHistory.java @@ -57,7 +57,7 @@ static void emptyHistory() { */ @UsedViaReflection static void writeHistory(DocumentContext dc) { - if (((WriteDocumentContext) dc).isEmpty()) { // only add to the start of a message. i.e. for chained calls. + if (dc instanceof WriteDocumentContext && ((WriteDocumentContext) dc).isEmpty()) { // only add to the start of a message. i.e. for chained calls. get().doWriteHistory(dc); } } diff --git a/src/main/java/net/openhft/chronicle/wire/MessagePathClassifier.java b/src/main/java/net/openhft/chronicle/wire/MessagePathClassifier.java index fa0ee86da9..c609cbfe74 100644 --- a/src/main/java/net/openhft/chronicle/wire/MessagePathClassifier.java +++ b/src/main/java/net/openhft/chronicle/wire/MessagePathClassifier.java @@ -24,6 +24,7 @@ * Implements {@link IntSupplier} so the current thread's * {@link MessageHistory} can be classified directly via {@link #getAsInt()}. */ +@Deprecated(/* to be removed in 2027, as it is only used in tests */) public class MessagePathClassifier implements IntSupplier { /** @@ -52,6 +53,7 @@ public class MessagePathClassifier implements IntSupplier { * @throws IllegalArgumentException if the same sequence is registered with a * different {@code pathId} */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public MessagePathClassifier addPathForSourcesEnding(int pathId, int... sources) { OptionalInt duplicate = IntStream.range(0, sourcePattern.size()) .filter(s -> Arrays.equals(sources, sourcePattern.get(s))) diff --git a/src/main/java/net/openhft/chronicle/wire/MethodDelegate.java b/src/main/java/net/openhft/chronicle/wire/MethodDelegate.java index aefa6f7234..248494ae01 100644 --- a/src/main/java/net/openhft/chronicle/wire/MethodDelegate.java +++ b/src/main/java/net/openhft/chronicle/wire/MethodDelegate.java @@ -15,10 +15,10 @@ * set via the {@link #delegate(Object)} method, provided that the delegate also * implements {@code MyService}. *

    - * The type parameter {@code } specifies the type of the delegate object to + * The type parameter {@code } specifies the type of the delegate object to * which methods will be forwarded. */ -public interface MethodDelegate { +public interface MethodDelegate { /** * Sets the delegate to which method invocations will be forwarded. @@ -29,8 +29,8 @@ public interface MethodDelegate { * proxy that implements this {@code MethodDelegate} interface so that calls can be * successfully forwarded. * - * @param delegate The target object of type {@code OUT} that will receive the + * @param delegate The target object of type {@code O} that will receive the * forwarded method calls. */ - void delegate(OUT delegate); + void delegate(O delegate); } diff --git a/src/main/java/net/openhft/chronicle/wire/MethodWriterInvocationHandlerSupplier.java b/src/main/java/net/openhft/chronicle/wire/MethodWriterInvocationHandlerSupplier.java index 3402d39a33..2ad43a332a 100644 --- a/src/main/java/net/openhft/chronicle/wire/MethodWriterInvocationHandlerSupplier.java +++ b/src/main/java/net/openhft/chronicle/wire/MethodWriterInvocationHandlerSupplier.java @@ -83,6 +83,7 @@ public void genericEvent(String genericEvent) { /** * Determines whether method identifiers are emitted. */ + @Deprecated(/* to be removed in 2027 */) public void useMethodIds(boolean useMethodIds) { this.useMethodIds = useMethodIds; } diff --git a/src/main/java/net/openhft/chronicle/wire/MicroDurationLongConverter.java b/src/main/java/net/openhft/chronicle/wire/MicroDurationLongConverter.java index e5f168f7e1..3b98630e56 100644 --- a/src/main/java/net/openhft/chronicle/wire/MicroDurationLongConverter.java +++ b/src/main/java/net/openhft/chronicle/wire/MicroDurationLongConverter.java @@ -11,6 +11,7 @@ * Implementation of {@link LongConverter} to convert durations represented as microseconds. * This class operates on long values, converting them to and from Java's {@link Duration}. */ +@Deprecated(/* to be removed in 2027, as it is only used in tests */) public class MicroDurationLongConverter implements LongConverter { /** diff --git a/src/main/java/net/openhft/chronicle/wire/MilliTimestampLongConverter.java b/src/main/java/net/openhft/chronicle/wire/MilliTimestampLongConverter.java index 1f2be18fb4..b4dd3f139f 100644 --- a/src/main/java/net/openhft/chronicle/wire/MilliTimestampLongConverter.java +++ b/src/main/java/net/openhft/chronicle/wire/MilliTimestampLongConverter.java @@ -37,6 +37,7 @@ public MilliTimestampLongConverter() { * to be used for formatting date-time strings. This converter * handles timestamps with millisecond precision. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public MilliTimestampLongConverter(String zoneId) { super(zoneId, TimeUnit.MILLISECONDS); } diff --git a/src/main/java/net/openhft/chronicle/wire/NoDocumentContext.java b/src/main/java/net/openhft/chronicle/wire/NoDocumentContext.java index 42e511295b..820f10cf59 100644 --- a/src/main/java/net/openhft/chronicle/wire/NoDocumentContext.java +++ b/src/main/java/net/openhft/chronicle/wire/NoDocumentContext.java @@ -12,6 +12,7 @@ * that works with document contexts. Using `NoDocumentContext.INSTANCE` denotes * a guaranteed uninitialized state for a document context. */ +@SuppressWarnings("deprecation") public enum NoDocumentContext implements DocumentContext { /** The singleton instance of the NoDocumentContext */ INSTANCE; diff --git a/src/main/java/net/openhft/chronicle/wire/QueryWire.java b/src/main/java/net/openhft/chronicle/wire/QueryWire.java index d908ff19b9..62f85f1674 100644 --- a/src/main/java/net/openhft/chronicle/wire/QueryWire.java +++ b/src/main/java/net/openhft/chronicle/wire/QueryWire.java @@ -7,7 +7,6 @@ import net.openhft.chronicle.bytes.BytesStore; import net.openhft.chronicle.bytes.StopCharTester; import net.openhft.chronicle.bytes.ref.BinaryLongArrayReference; -import net.openhft.chronicle.core.annotation.ForceInline; import net.openhft.chronicle.core.io.InvalidMarshallableException; import net.openhft.chronicle.core.scoped.ScopedResource; import net.openhft.chronicle.core.util.StringUtils; @@ -30,7 +29,7 @@ * Extends {@link TextWire} and supplies {@link QueryValueIn} and * {@link QueryValueOut} for query specific value handling. */ -@SuppressWarnings({"rawtypes", "java:S2387"}) +@SuppressWarnings({"rawtypes", "java:S2387", "deprecation"}) public class QueryWire extends TextWire { // The specialized output handler for query string values. @@ -54,6 +53,7 @@ public QueryWire(@NotNull Bytes bytes) { */ @NotNull @Override + @Deprecated(/* to be removed in 2027 */) protected QueryValueOut createValueOut() { return new QueryValueOut(); } @@ -63,6 +63,7 @@ protected QueryValueOut createValueOut() { */ @NotNull @Override + @Deprecated(/* to be removed in 2027 */) protected TextValueIn createValueIn() { return new QueryValueIn(); } @@ -85,7 +86,6 @@ protected StringBuilder readField(@NotNull StringBuilder sb) { * Skips any leading whitespace from the current read position. */ @Override - @ForceInline public void consumePadding() { int codePoint = peekCode(); while (Character.isWhitespace(codePoint)) { @@ -154,28 +154,36 @@ int rewindAndRead() { return bytes.readUnsignedByte(bytes.readPosition() - 1); } - /** Unsupported for query strings. */ + /** + * Unsupported for query strings. + */ @NotNull @Override public LongValue newLongReference() { throw new UnsupportedOperationException(); } - /** Unsupported for query strings. */ + /** + * Unsupported for query strings. + */ @NotNull @Override public IntValue newIntReference() { throw new UnsupportedOperationException(); } - /** Unsupported for query strings. */ + /** + * Unsupported for query strings. + */ @NotNull @Override public BinaryLongArrayReference newLongArrayReference() { throw new UnsupportedOperationException(); } - /** Unsupported for query strings. */ + /** + * Unsupported for query strings. + */ @Override public @NotNull IntArrayValues newIntArrayReference() { throw new UnsupportedOperationException(); @@ -215,7 +223,7 @@ class QueryValueOut extends YamlValueOut { // The separator to prepend before writing the next value. @NotNull - String sep = ""; + String separator = ""; // The field name to prepend before writing the next value. @Nullable @@ -226,8 +234,8 @@ class QueryValueOut extends YamlValueOut { */ @Override void prependSeparator() { - bytes.appendUtf8(sep); - sep = ""; + bytes.appendUtf8(separator); + separator = ""; if (fieldName != null) { bytes.appendUtf8(fieldName).appendUtf8('='); fieldName = null; @@ -236,7 +244,7 @@ void prependSeparator() { @Override public void elementSeparator() { - sep = "&"; + separator = "&"; } /** @@ -279,7 +287,9 @@ public QueryWire int8(byte i8) { return QueryWire.this; } - /** Unsupported for query strings. */ + /** + * Unsupported for query strings. + */ @NotNull @Override public QueryWire bytes(@Nullable BytesStore fromBytes) { @@ -313,14 +323,18 @@ public QueryWire bytes(byte[] byteArray) { return QueryWire.this; } - /** Unsupported for query strings. */ + /** + * Unsupported for query strings. + */ @NotNull @Override public QueryWire int64array(long capacity) { throw new UnsupportedOperationException(); } - /** Unsupported for query strings. */ + /** + * Unsupported for query strings. + */ @NotNull @Override public QueryWire int64array(long capacity, @NotNull LongArrayValues values) { @@ -335,60 +349,74 @@ public QueryWire int64array(long capacity, @NotNull LongArrayValues values) { public QueryValueOut typePrefix(@NotNull CharSequence typeName) { prependSeparator(); bytes.appendUtf8(typeName); - sep = " "; + separator = " "; return this; } - /** Unsupported for query strings. */ + /** + * Unsupported for query strings. + */ @NotNull @Override public QueryWire typeLiteral(@Nullable CharSequence type) { throw new UnsupportedOperationException(); } - /** Unsupported for query strings. */ + /** + * Unsupported for query strings. + */ @NotNull @Override public QueryWire typeLiteral(@NotNull BiConsumer> typeTranslator, @NotNull Class type) { throw new UnsupportedOperationException(); } - /** Unsupported for query strings. */ + /** + * Unsupported for query strings. + */ @NotNull @Override public QueryWire int32forBinding(int value) { throw new UnsupportedOperationException(); } - /** Unsupported for query strings. */ + /** + * Unsupported for query strings. + */ @NotNull @Override public QueryWire int32forBinding(int value, @NotNull IntValue intValue) { throw new UnsupportedOperationException(); } - /** Unsupported for query strings. */ + /** + * Unsupported for query strings. + */ @NotNull @Override public QueryWire int64forBinding(long value) { throw new UnsupportedOperationException(); } - /** Unsupported for query strings. */ + /** + * Unsupported for query strings. + */ @NotNull @Override public QueryWire int64forBinding(long value, @NotNull LongValue longValue) { throw new UnsupportedOperationException(); } - /** Writes a sequence using comma separated values. */ + /** + * Writes a sequence using comma separated values. + */ @NotNull @Override public QueryWire sequence(T t, @NotNull BiConsumer writer) { prependSeparator(); pushState(); bytes.appendUtf8("["); - sep = ","; + separator = ","; long pos = bytes.writePosition(); writer.accept(t, this); if (pos != bytes.writePosition()) @@ -400,14 +428,16 @@ public QueryWire sequence(T t, @NotNull BiConsumer writer) { return QueryWire.this; } - /** Writes a sequence with a provided class. */ + /** + * Writes a sequence with a provided class. + */ @NotNull @Override public QueryWire sequence(T t, K kls, @NotNull TriConsumer writer) throws InvalidMarshallableException { prependSeparator(); pushState(); bytes.appendUtf8("["); - sep = ","; + separator = ","; long pos = bytes.writePosition(); writer.accept(t, kls, this); if (pos != bytes.writePosition()) @@ -427,7 +457,9 @@ protected void popState() { protected void pushState() { } - /** Writes a marshallable object in braces. */ + /** + * Writes a marshallable object in braces. + */ @NotNull @Override public QueryWire marshallable(@NotNull WriteMarshallable object) throws InvalidMarshallableException { @@ -435,7 +467,7 @@ public QueryWire marshallable(@NotNull WriteMarshallable object) throws InvalidM prependSeparator(); bytes.appendUtf8("{"); - sep = ","; + separator = ","; object.writeMarshallable(QueryWire.this); @@ -446,14 +478,18 @@ public QueryWire marshallable(@NotNull WriteMarshallable object) throws InvalidM return QueryWire.this; } - /** Unsupported for query strings. */ + /** + * Unsupported for query strings. + */ @NotNull @Override public QueryWire map(@NotNull final Map map) { throw new UnsupportedOperationException(); } - /** Unsupported for query strings. */ + /** + * Unsupported for query strings. + */ @Override @NotNull public QueryValueOut write() { @@ -479,7 +515,9 @@ public QueryValueOut write(@NotNull CharSequence name) { * {@link ValueIn} implementation for query strings. */ class QueryValueIn extends TextValueIn { - /** Returns the value text of the current parameter. */ + /** + * Returns the value text of the current parameter. + */ @Override public String text() { try (ScopedResource stlSb = Wires.acquireStringBuilderScoped()) { diff --git a/src/main/java/net/openhft/chronicle/wire/RawText.java b/src/main/java/net/openhft/chronicle/wire/RawText.java index 3037d8f7cb..85c1bdbdfa 100644 --- a/src/main/java/net/openhft/chronicle/wire/RawText.java +++ b/src/main/java/net/openhft/chronicle/wire/RawText.java @@ -13,7 +13,7 @@ */ class RawText { // The encapsulated raw textual data - String text; + final String text; /** * Constructs a new instance of {@code RawText} initialised with the provided diff --git a/src/main/java/net/openhft/chronicle/wire/RawWire.java b/src/main/java/net/openhft/chronicle/wire/RawWire.java index b801089f35..026a49c546 100644 --- a/src/main/java/net/openhft/chronicle/wire/RawWire.java +++ b/src/main/java/net/openhft/chronicle/wire/RawWire.java @@ -4,6 +4,7 @@ package net.openhft.chronicle.wire; import net.openhft.chronicle.bytes.*; +import net.openhft.chronicle.bytes.ref.BinaryBooleanReference; import net.openhft.chronicle.bytes.ref.BinaryIntArrayReference; import net.openhft.chronicle.bytes.ref.BinaryIntReference; import net.openhft.chronicle.bytes.ref.BinaryLongArrayReference; @@ -32,6 +33,8 @@ import java.util.UUID; import java.util.function.*; +import static net.openhft.chronicle.wire.BinaryWire.requireReference; + /** * Wire implementation that serialises values in sequence without any field names. *

    @@ -42,7 +45,7 @@ * Used for performance-critical exchanges where writer and reader share a * fixed layout. Unlike {@link BinaryWire} no field identifiers are emitted */ -@SuppressWarnings({"rawtypes", "unchecked", "this-escape"}) +@SuppressWarnings({"rawtypes", "unchecked", "this-escape", "deprecation"}) public class RawWire extends AbstractWire implements Wire { // Output mechanism for writing raw values @@ -66,6 +69,7 @@ public class RawWire extends AbstractWire implements Wire { public RawWire() { this(Bytes.allocateElasticOnHeap()); } + /** * Creates a {@code RawWire} backed by the given buffer. Strings are encoded * using 8-bit length prefixes. @@ -405,7 +409,7 @@ public WireOut text(@Nullable CharSequence s) { @NotNull @Override public WireOut text(@Nullable BytesStore s) { - if (use8bit) + if (use8bit) { if (s == null) { bytes.writeStopBit(-1); } else { @@ -418,8 +422,9 @@ public WireOut text(@Nullable BytesStore s) { throw new AssertionError(e); } } - else + } else { bytes.writeUtf8(s); + } return RawWire.this; } @@ -656,7 +661,8 @@ public WireOut int64forBinding(long value) { @Override public WireOut int32forBinding(int value, @NotNull IntValue intValue) { 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 RawWire.this; } @@ -664,7 +670,8 @@ public WireOut int32forBinding(int value, @NotNull IntValue intValue) { @Override public WireOut int64forBinding(long value, @NotNull LongValue longValue) { 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 RawWire.this; } @@ -672,7 +679,8 @@ public WireOut int64forBinding(long value, @NotNull LongValue longValue) { @Override public WireOut boolForBinding(final boolean value, @NotNull final BooleanValue longValue) { bool(value); - ((BinaryLongReference) longValue).bytesStore(bytes, bytes.writePosition() - 1, 1); + BinaryBooleanReference reference = requireReference(longValue, BinaryBooleanReference.class, "boolForBinding"); + reference.bytesStore(bytes, bytes.writePosition() - 1, 1); return RawWire.this; } @@ -780,14 +788,17 @@ public void resetState() { stack.reset(); } + @Deprecated(/* to be removed in 2027 */) public void pushState() { stack.push(); } + @Deprecated(/* to be removed in 2027 */) public void popState() { stack.pop(); } + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public ValueInState curr() { return stack.curr(); } diff --git a/src/main/java/net/openhft/chronicle/wire/ReadAnyWire.java b/src/main/java/net/openhft/chronicle/wire/ReadAnyWire.java index e909fd8e6a..59b5f90fb2 100644 --- a/src/main/java/net/openhft/chronicle/wire/ReadAnyWire.java +++ b/src/main/java/net/openhft/chronicle/wire/ReadAnyWire.java @@ -18,6 +18,7 @@ * The specific wire type is determined dynamically based on the provided bytes. * This class provides flexibility in reading from wires that could be in either format. */ +@SuppressWarnings("deprecation") public class ReadAnyWire extends AbstractAnyWire implements Wire { /** @@ -141,6 +142,7 @@ public Wire acquireWire() { return null; } + @Deprecated(/* to be removed in 2027 */) public Bytes bytes() { return bytes; } diff --git a/src/main/java/net/openhft/chronicle/wire/ReadMarshallable.java b/src/main/java/net/openhft/chronicle/wire/ReadMarshallable.java index 2a9d0efe28..679b93daa1 100644 --- a/src/main/java/net/openhft/chronicle/wire/ReadMarshallable.java +++ b/src/main/java/net/openhft/chronicle/wire/ReadMarshallable.java @@ -26,6 +26,7 @@ public interface ReadMarshallable extends CommonMarshallable { // An instance of ReadMarshallable that doesn't perform any action when reading. + @Deprecated(/* to be removed in 2027 */) ReadMarshallable DISCARD = w -> {}; /** diff --git a/src/main/java/net/openhft/chronicle/wire/ScalarStrategy.java b/src/main/java/net/openhft/chronicle/wire/ScalarStrategy.java index 4126df5198..03b377594b 100644 --- a/src/main/java/net/openhft/chronicle/wire/ScalarStrategy.java +++ b/src/main/java/net/openhft/chronicle/wire/ScalarStrategy.java @@ -49,7 +49,7 @@ class ScalarStrategy implements SerializationStrategy { * @return A new instance of {@code ScalarStrategy}. */ @NotNull - static ScalarStrategy< E > of(Class< E > clazz, @NotNull BiFunction read) { + static ScalarStrategy of(Class clazz, @NotNull BiFunction read) { return new ScalarStrategy<>(clazz, read); } @@ -64,7 +64,7 @@ static ScalarStrategy< E > of(Class< E > clazz, @NotNull BiFunction ScalarStrategy< E > text(Class< E > clazz, @NotNull Function func) { + static ScalarStrategy text(Class clazz, @NotNull Function func) { return new ScalarStrategy<>(clazz, (Object o, ValueIn in) -> { @Nullable String text = in.text(); return text == null ? null : func.apply(text); @@ -88,7 +88,7 @@ public BracketType bracketType() { @SuppressWarnings("rawtypes") @NotNull @Override - public T newInstanceOrNull(Classtype) { + public T newInstanceOrNull(Class type) { return Jvm.uncheckedCast(ObjectUtils.newInstance(this.type)); } diff --git a/src/main/java/net/openhft/chronicle/wire/SelfDescribingTriviallyCopyable.java b/src/main/java/net/openhft/chronicle/wire/SelfDescribingTriviallyCopyable.java index 2d7b38cbc9..15f1edb377 100644 --- a/src/main/java/net/openhft/chronicle/wire/SelfDescribingTriviallyCopyable.java +++ b/src/main/java/net/openhft/chronicle/wire/SelfDescribingTriviallyCopyable.java @@ -30,7 +30,7 @@ public abstract class SelfDescribingTriviallyCopyable extends SelfDescribingMars // Contains the description of the data layout. @FieldGroup("header") - transient int description = $description(); + final transient int description = $description(); /** * Fetches the description of the current data layout. @@ -61,7 +61,7 @@ public abstract class SelfDescribingTriviallyCopyable extends SelfDescribingMars @Override public void readMarshallable(BytesIn bytes) throws IORuntimeException, BufferUnderflowException, IllegalStateException { int description0 = bytes.readInt(); - if (description0 != $description()) + if (description0 != description) carefulCopy(bytes, description0); else bytes.unsafeReadObject(this, $start(), $length()); @@ -98,7 +98,7 @@ private void carefulCopy(BytesIn in, int description0) { throw new IllegalStateException("Invalid description: " + Integer.toHexString(description0) + ", length: " + length + ", remaining: " + in.readRemaining()); // Copy long values from the input source to the object's memory - int longs = $description() >>> 24; // max 255 + int longs = description >>> 24; // max 255 for (int i = 0; i < Math.max(longs, longs0); i++) { long value = 0; if (i < longs0) @@ -110,7 +110,7 @@ private void carefulCopy(BytesIn in, int description0) { } // Copy int values from the input source to the object's memory - int ints = ($description() >>> 16) & 0xFF; // max 255 + int ints = (description >>> 16) & 0xFF; // max 255 for (int i = 0; i < Math.max(ints, ints0); i++) { int value = 0; if (i < ints0) @@ -122,7 +122,7 @@ private void carefulCopy(BytesIn in, int description0) { } // Copy short values from the input source to the object's memory - int shorts = ($description() >>> 8) & 0x7F; // max 127 + int shorts = (description >>> 8) & 0x7F; // max 127 for (int i = 0; i < Math.max(shorts, shorts0); i++) { short value = 0; if (i < shorts0) @@ -134,7 +134,7 @@ private void carefulCopy(BytesIn in, int description0) { } // Copy byte values from the input source to the object's memory - int bytes = $description() & 0xFF; // max 255 + int bytes = description & 0xFF; // max 255 for (int i = 0; i < Math.max(bytes, bytes0); i++) { byte value = 0; if (i < bytes0) @@ -152,7 +152,7 @@ private void carefulCopy(BytesIn in, int description0) { */ @Override public void writeMarshallable(BytesOut bytes) throws IllegalStateException, BufferOverflowException, BufferUnderflowException, ArithmeticException { - bytes.writeInt($description()); + bytes.writeInt(description); bytes.unsafeWriteObject(this, $start(), $length()); } } diff --git a/src/main/java/net/openhft/chronicle/wire/Sequence.java b/src/main/java/net/openhft/chronicle/wire/Sequence.java index 8793479ed1..07dd2b4f19 100644 --- a/src/main/java/net/openhft/chronicle/wire/Sequence.java +++ b/src/main/java/net/openhft/chronicle/wire/Sequence.java @@ -54,6 +54,7 @@ public interface Sequence { * @param sequence The lower-order sequence number within the header. * @return A combined index representing the header and sequence. */ + @Deprecated(/* to be removed in 2027 */) long toIndex(long headerNumber, long sequence); /** diff --git a/src/main/java/net/openhft/chronicle/wire/SerializationStrategies.java b/src/main/java/net/openhft/chronicle/wire/SerializationStrategies.java index e2df54ae05..7afa4bc3f4 100644 --- a/src/main/java/net/openhft/chronicle/wire/SerializationStrategies.java +++ b/src/main/java/net/openhft/chronicle/wire/SerializationStrategies.java @@ -207,7 +207,7 @@ public BracketType bracketType() { DYNAMIC_ENUM { // Reflective field access to the ordinal of the Enum class - private Field ordinal = Jvm.getField(Enum.class, "ordinal"); + private final Field ordinal = Jvm.getField(Enum.class, "ordinal"); /** * Reads a dynamic enum value from the provided input source. diff --git a/src/main/java/net/openhft/chronicle/wire/ServicesTimestampLongConverter.java b/src/main/java/net/openhft/chronicle/wire/ServicesTimestampLongConverter.java index df114c60a8..16cecc7b7b 100644 --- a/src/main/java/net/openhft/chronicle/wire/ServicesTimestampLongConverter.java +++ b/src/main/java/net/openhft/chronicle/wire/ServicesTimestampLongConverter.java @@ -9,9 +9,11 @@ import net.openhft.chronicle.core.time.TimeProvider; import java.util.concurrent.TimeUnit; +import java.util.function.LongUnaryOperator; import java.util.function.ToLongFunction; import static net.openhft.chronicle.core.time.SystemTimeProvider.CLOCK; + /** * This is the ServicesTimestampLongConverter class implementing the {@link LongConverter} interface. * The class is specifically designed to convert timestamps representing service times across different @@ -29,7 +31,7 @@ public class ServicesTimestampLongConverter implements LongConverter { private static final String SERVICES_TIME_UNIT = System.getProperty("service.time.unit", "ns"); // Functional interface to convert the time. - private static final longFunction toTime; + private static final LongUnaryOperator toTime; // Functional interface to fetch the current time. private static final ToLongFunction currentTime; @@ -75,7 +77,7 @@ public class ServicesTimestampLongConverter implements LongConverter { * @return The converted long value based on the system-configured time unit. */ public static long toTime(long arg) { - return toTime.apply(arg); + return toTime.applyAsLong(arg); } /** @@ -109,6 +111,7 @@ public static TimeUnit timeUnit() { /** * Parses the provided {@link CharSequence} into a timestamp in the configured time unit. + * * @param text The character sequence representing a date-time string, which will be parsed by * the underlying timestamp converter (for example * {@link NanoTimestampLongConverter} or {@link MicroTimestampLongConverter}) based @@ -123,9 +126,9 @@ public long parse(CharSequence text) { /** * Parses a part of the provided {@link CharSequence} using the underlying converter. * - * @param text The character sequence containing the date-time string to parse. + * @param text The character sequence containing the date-time string to parse. * @param beginIndex The starting index (inclusive) of the subsequence in {@code text} to be parsed. - * @param endIndex The ending index (exclusive) of the subsequence in {@code text} to be parsed. + * @param endIndex The ending index (exclusive) of the subsequence in {@code text} to be parsed. * @return the parsed timestamp as a long value in the configured time unit. */ @Override @@ -160,19 +163,4 @@ public void append(StringBuilder text, long value) { public void append(Bytes bytes, long value) { underlying.append(bytes, value); } - - /** - * This is the longFunction interface. It's a functional interface designed to perform operations - * on long values and return a long result. It is used internally in ServicesTimestampLongConverter - * to abstract the conversion logic based on the system-configured time unit. - */ - interface longFunction { - /** - * Processes a long value and returns the result. - * - * @param value The input long value to be processed by the function. - * @return The processed value. - */ - long apply(long value); - } } diff --git a/src/main/java/net/openhft/chronicle/wire/ShortTextLongConverter.java b/src/main/java/net/openhft/chronicle/wire/ShortTextLongConverter.java index 01151da5eb..2f378da9d1 100644 --- a/src/main/java/net/openhft/chronicle/wire/ShortTextLongConverter.java +++ b/src/main/java/net/openhft/chronicle/wire/ShortTextLongConverter.java @@ -18,6 +18,7 @@ * @see AbstractLongConverter * @see Base85LongConverter */ +@SuppressWarnings("deprecation") public class ShortTextLongConverter extends AbstractLongConverter { /** diff --git a/src/main/java/net/openhft/chronicle/wire/TextReadDocumentContext.java b/src/main/java/net/openhft/chronicle/wire/TextReadDocumentContext.java index 911049e8a0..041fe1485c 100644 --- a/src/main/java/net/openhft/chronicle/wire/TextReadDocumentContext.java +++ b/src/main/java/net/openhft/chronicle/wire/TextReadDocumentContext.java @@ -14,6 +14,7 @@ * It provides methods and utilities for understanding the structure and boundaries * of the document within a given wire format. */ +@SuppressWarnings("deprecation") public class TextReadDocumentContext implements ReadDocumentContext { // Byte sequences for start and end of the document @@ -56,8 +57,10 @@ public TextReadDocumentContext(@Nullable Wire wire) { */ public static void consumeToEndOfMessage(Bytes bytes) { while (bytes.readRemaining() > 0) { - while (bytes.readRemaining() > 0 && bytes.readUnsignedByte() >= ' ') { - // read skips forward. + while (bytes.readRemaining() > 0) { + if (bytes.readUnsignedByte() < ' ') { + break; + } } if (isEndOfMessage(bytes)) { break; @@ -131,7 +134,7 @@ public void close() { bytes.readPosition(readPosition); if (isEndOfMessage(bytes)) bytes.readSkip(3); - while(!bytes.isEmpty()) { + while (!bytes.isEmpty()) { if (bytes.peekUnsignedByte() > ' ') break; bytes.readSkip(1); @@ -161,7 +164,7 @@ public void start() { present = false; wire.consumePadding(); - while(isEndOfMessage(bytes)) + while (isEndOfMessage(bytes)) skipSep(bytes); if (bytes.readRemaining() < 1) { diff --git a/src/main/java/net/openhft/chronicle/wire/TextWire.java b/src/main/java/net/openhft/chronicle/wire/TextWire.java index 89117afd6b..382a50bc7e 100644 --- a/src/main/java/net/openhft/chronicle/wire/TextWire.java +++ b/src/main/java/net/openhft/chronicle/wire/TextWire.java @@ -8,7 +8,10 @@ import net.openhft.chronicle.bytes.util.Compression; import net.openhft.chronicle.core.Jvm; import net.openhft.chronicle.core.Maths; -import net.openhft.chronicle.core.io.*; +import net.openhft.chronicle.core.io.IORuntimeException; +import net.openhft.chronicle.core.io.IOTools; +import net.openhft.chronicle.core.io.InvalidMarshallableException; +import net.openhft.chronicle.core.io.ValidatableUtil; import net.openhft.chronicle.core.pool.ClassLookup; import net.openhft.chronicle.core.scoped.ScopedResource; import net.openhft.chronicle.core.threads.ThreadLocalHelper; @@ -44,7 +47,7 @@ *

    Important: Some configurations and methods in this class are marked as deprecated * and are slated for removal in future versions, suggesting that its behavior might evolve in future releases. */ -@SuppressWarnings({"rawtypes", "unchecked", "this-escape"}) +@SuppressWarnings({"rawtypes", "unchecked", "this-escape", "deprecation"}) public class TextWire extends YamlWireOut { // Constants representing specific textual constructs in YAML. @@ -68,7 +71,6 @@ public class TextWire extends YamlWireOut { static final Supplier SINGLE_QUOTES_ESCAPING = StopCharTesters.SINGLE_QUOTES::escaping; static final Supplier END_OF_TEXT_ESCAPING = TextStopCharTesters.END_OF_TEXT::escaping; static final Supplier STRICT_END_OF_TEXT_ESCAPING = TextStopCharsTesters.STRICT_END_OF_TEXT::escaping; - static final Supplier END_EVENT_NAME_ESCAPING = TextStopCharsTesters.END_EVENT_NAME::escaping; // Metadata representation in bytes. static final Bytes META_DATA = Bytes.from("!!meta-data"); @@ -116,6 +118,7 @@ public TextWire() { this(Bytes.allocateElasticOnHeap()); useTextDocuments(); } + /** * Constructor to initialize the `TextWire` with a specific bytes representation * and a flag to determine if 8-bit encoding is to be used. @@ -166,6 +169,7 @@ public static TextWire from(@NotNull String text) { * @param wire The wire format to be converted. * @return The text representation of the wire format. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static String asText(@NotNull Wire wire) { NativeBytes bytes = nativeBytes(); ValidatableUtil.startValidateDisabled(); @@ -182,6 +186,7 @@ public static String asText(@NotNull Wire wire) { } // https://yaml.org/spec/1.2.2/#escaped-characters + /** * Processes and unescapes the provided {@link CharSequence} containing escaped sequences. * For instance, "\\n" is converted to a newline character, "\\t" to a tab, etc. @@ -190,7 +195,7 @@ public static String asText(@NotNull Wire wire) { * @param sb A {@link CharSequence} that is also an {@link Appendable}, containing potentially escaped sequences. * This sequence will be modified directly. */ - public static void unescape(@NotNull ACS sb) { + public static void unescape(@NotNull S sb) { int end = 0; int length = sb.length(); for (int i = 0; i < length; i++) { @@ -269,7 +274,7 @@ public static void unescape(@NotNull ACS * This method utilizes thread-local storage to ensure that the returned instance is thread-safe. * * @return A {@link StopCharTester} instance specifically designed for escaping single quotes, - * or null if such an instance could not be acquired. + * or null if such an instance could not be acquired. */ @Nullable static StopCharTester getEscapingSingleQuotes() { @@ -288,6 +293,7 @@ static StopCharTester getEscapingSingleQuotes() { * @return an instance of the object created from the data in the file * @throws IOException if the file can not be found or read */ + @Deprecated(/* to be removed in 2027 */) public static T load(String filename) throws IOException, InvalidMarshallableException { return (T) TextWire.fromFile(filename).readObject(); } @@ -302,6 +308,7 @@ public boolean isBinary() { * * @return A boolean indicating whether strict mode is enabled (true) or disabled (false). */ + @Deprecated(/* to be removed in 2027 */) public boolean strict() { return strict; } @@ -313,6 +320,7 @@ public boolean strict() { * @param strict A boolean value to set the strict mode. True to enable, false to disable. * @return The current TextWire instance, allowing for method chaining. */ + @Deprecated(/* to be removed in 2027 */) public TextWire strict(boolean strict) { this.strict = strict; return this; @@ -471,8 +479,9 @@ public String toString() { } finally { bytes.readLimit(l); } - } else + } else { return bytes.toString(); + } } /** @@ -480,6 +489,7 @@ public String toString() { * * @return A string representation of the TextWire's underlying bytes in ISO-8859-1 encoding. */ + @Deprecated(/* to be removed in 2027 */) public String to8bitString() { return bytes.to8bitString(); } @@ -670,7 +680,7 @@ protected Class defaultKeyClass() { * The content of the StringBuilder is interned before the conversion. * * @param expectedClass The class to which the StringBuilder's content should be converted. - * @param sb The StringBuilder containing the data to be converted. + * @param sb The StringBuilder containing the data to be converted. * @return An instance of the expected class, converted from the StringBuilder's content. */ @Nullable @@ -706,15 +716,6 @@ protected StopCharsTester getStrictEscapingEndOfText() { return escaping; } - @NotNull - protected StopCharsTester getEscapingEndEventName() { - StopCharsTester escaping = ThreadLocalHelper.getTL(STRICT_ESCAPED_END_OF_TEXT, END_EVENT_NAME_ESCAPING); - - // Reset the stop characters tester to stop at space characters. - escaping.isStopChar(' ', ' '); - return escaping; - } - /** * Retrieves the StopCharTester that determines the end of a quoted text section with escaping. * The tester is fetched from thread-local storage and is then reset. @@ -741,6 +742,7 @@ public String readingPeekYaml() { } // TODO Move to valueIn + /** * Consumes padding characters from the current reading position. * Padding characters include spaces, tabs, new lines, commas, and comments. This method also @@ -898,7 +900,7 @@ public ValueIn read(@NotNull WireKey key) { /** * Reads the value associated with a given key name, code, and provides a default value. * - * @param keyName The name of the key. + * @param keyName The name of the key. * @param defaultValue The default value to return if the key isn't found. * @return The value associated with the given key or the default value if not found. */ @@ -948,13 +950,13 @@ private ValueIn read(@NotNull CharSequence keyName, Object defaultValue) { * Attempts to read the value of a given key, continuing the read operation from the primary `read` method. * If the current and old fields do not match the specified key, the default value is returned. * - * @param keyName The name of the key for which the value needs to be read. - * @param keyCode The code for the key. - * @param defaultValue The default value to return if the key isn't found. - * @param currentState The current state of the ValueIn. - * @param tempNameBuilder The StringBuilder used to capture the field name. - * @param name The name of the key (same as keyName, possibly added for clarity in some cases). - * @return The value associated with the key or the default value if the key is not found. + * @param keyName The name of the key for which the value needs to be read. + * @param keyCode The code for the key. + * @param defaultValue The default value to return if the key isn't found. + * @param currentState The current state of the ValueIn. + * @param tempNameBuilder The StringBuilder used to capture the field name. + * @param name The name of the key (same as keyName, possibly added for clarity in some cases). + * @return The value associated with the key or the default value if the key is not found. */ @Deprecated(/* to be removed in x.29 */) protected ValueIn read2(CharSequence keyName, int keyCode, Object defaultValue, @NotNull ValueInState currentState, @NotNull StringBuilder tempNameBuilder, @NotNull CharSequence name) { @@ -965,11 +967,11 @@ protected ValueIn read2(CharSequence keyName, int keyCode, Object defaultValue, * Attempts to read the value, continuing the read operation from the primary `read` method. * If the current and old fields do not match the specified key, the default value is returned. * - * @param defaultValue The default value to return if the key isn't found. - * @param currentState The current state of the ValueIn. - * @param tempNameBuilder The StringBuilder used to capture the field name. - * @param name The name of the key (same as keyName, possibly added for clarity in some cases). - * @return The value associated with the key or the default value if the key is not found. + * @param defaultValue The default value to return if the key isn't found. + * @param currentState The current state of the ValueIn. + * @param tempNameBuilder The StringBuilder used to capture the field name. + * @param name The name of the key (same as keyName, possibly added for clarity in some cases). + * @return The value associated with the key or the default value if the key is not found. */ protected ValueIn read2(Object defaultValue, @NotNull ValueInState currentState, @NotNull StringBuilder tempNameBuilder, @NotNull CharSequence name) { final long position2 = bytes.readPosition(); @@ -1085,8 +1087,8 @@ public void parseWord(@NotNull StringBuilder sb) { * Parses characters from the current byte position until one of the specified stop characters * in the tester is encountered. The parsed characters are then appended to the provided StringBuilder. * - * @param sb The StringBuilder to which the parsed characters will be appended. - * @param stopTester A StopCharTester which determines which characters should stop the parsing. + * @param sb The StringBuilder to which the parsed characters will be appended. + * @param stopTester A StopCharTester which determines which characters should stop the parsing. */ public void parseUntil(@NotNull StringBuilder sb, @NotNull StopCharTester stopTester) { if (use8bit) @@ -1100,9 +1102,10 @@ public void parseUntil(@NotNull StringBuilder sb, @NotNull StopCharTester stopTe * until one of the specified stop characters in the tester is encountered. * The parsed characters are then appended to the provided StringBuilder. * - * @param sb The StringBuilder to which the parsed characters will be appended. - * @param stopTester A StopCharsTester which determines which characters should stop the parsing. + * @param sb The StringBuilder to which the parsed characters will be appended. + * @param stopTester A StopCharsTester which determines which characters should stop the parsing. */ + @Deprecated(/* to be removed in 2027 */) public void parseUntil(@NotNull StringBuilder sb, @NotNull StopCharsTester stopTester) { sb.setLength(0); if (use8bit) { @@ -1133,7 +1136,7 @@ public Object readObject() throws InvalidMarshallableException { * * @param indentation The current indentation level to handle nested objects. * @return An instance of the read object, `NoObject.NO_OBJECT` if the object denotes - * an end of block or structure, or null if the end of the stream is reached. + * an end of block or structure, or null if the end of the stream is reached. * @throws InvalidMarshallableException If the object could not be properly unmarshalled. */ @Nullable @@ -1165,7 +1168,7 @@ Object readObject(int indentation) throws InvalidMarshallableException { * between the current read position and the start of the line. * * @return The amount of indentation in terms of the number of characters from - * the start of the line to the current read position. + * the start of the line to the current read position. */ private int indentation() { long pos = bytes.readPosition(); @@ -1242,8 +1245,8 @@ List readList(int indentation, Class elementType) throws InvalidMarshallableE * Each key is followed by its value. If a key named "..." is encountered, the parsing breaks. * * @param indentation The current indentation level to handle nested key-value pairs. - * @param valueType The expected type of values within the map. Used when inferring - * the type of the read object. + * @param valueType The expected type of values within the map. Used when inferring + * the type of the read object. * @return A map containing key-value pairs read from the bytes stream. * @throws InvalidMarshallableException If any key-value pair within the map could not be properly unmarshalled. */ @@ -1406,7 +1409,7 @@ public BracketType getBracketType() { * {@code !binary}, and resolves anchors or aliases. */ @SuppressWarnings("fallthrough") - @Nullable CharSequence textTo0(@NotNull ACS destination) { + @Nullable CharSequence textTo0(@NotNull S destination) { consumePadding(); int ch = peekCode(); @Nullable CharSequence ret = destination; @@ -1512,7 +1515,7 @@ public BracketType getBracketType() { * encountered but not expanded. A warning is logged and the literal * characters are copied into {@code destination}. */ - private void unsubstitutedString(@NotNull ACS destination) { + private void unsubstitutedString(@NotNull S destination) { String text = bytes.toString(); // Limit the log output to 32 characters for brevity if (text.length() > 32) @@ -1538,7 +1541,7 @@ private void unsubstitutedString(@NotNul * {@code quotes}. The surrounding quote is skipped, the body parsed and * unescaped, then any trailing padding is consumed. */ - private void readText(@NotNull ACS destination, @NotNull StopCharTester quotes) { + private void readText(@NotNull S destination, @NotNull StopCharTester quotes) { // Skip the initial quote (either ' or ") bytes.readSkip(1); // Read the content based on the character encoding being used @@ -1812,8 +1815,6 @@ private void consumeType2() { * Consumes a sequence or list (e.g., `[item1, item2]`) in the text format. */ private void consumeSeq() { - int code; - // Skip the opening '[' character bytes.readSkip(1); for (; ; ) { @@ -1838,7 +1839,7 @@ private void consumeSeq() { consumePadding(); // Read the next character - code = readCode(); + final int code = readCode(); // Ensure that the sequence is properly closed with a ']' if (code != ']') { @@ -1851,8 +1852,6 @@ private void consumeSeq() { * Consumes a map structure (e.g., `{key1: value1, key2: value2}`) in the text format. */ private void consumeMap() { - int code; - // Skip the opening '{' character for the map bytes.readSkip(1); for (; ; ) { @@ -1879,7 +1878,7 @@ private void consumeMap() { consumePadding(); // Read the next character to ensure the map is closed properly - code = readCode(); + final int code = readCode(); if (code != '}') { bytes.readSkip(-1); throw new IllegalStateException("Expected a } was " + (char) code); @@ -2000,6 +1999,8 @@ long getALong() { case '[': // Throw an exception if attempting to read a map or list as a number throw new IORuntimeException("Cannot read a " + (char) code + " as a number"); + default: + break; } // Read and return the long value from the stream @@ -2201,14 +2202,19 @@ public boolean sequence(@NotNull T t, @NotNull BiConsumer tReade return true; } + @Override + public boolean sequence(@NotNull List list, @NotNull List buffer, @NotNull Supplier bufferAdd) throws InvalidMarshallableException { + return sequence(list, buffer, bufferAdd, this::reader0); + } + /** * Handles the processing of a sequence. * - * @param The type of items in the lists. - * @param list The main list that should be populated based on the buffer. - * @param buffer A temporary buffer used for staging data. + * @param The type of items in the lists. + * @param list The main list that should be populated based on the buffer. + * @param buffer A temporary buffer used for staging data. * @param bufferAdd A supplier function that can add items to the buffer. - * @param reader0 The reader that processes each item in the sequence. + * @param reader0 The reader that processes each item in the sequence. * @return Returns a boolean indicating success/failure or some other status. * @throws InvalidMarshallableException if there's an error during the sequence processing. */ @@ -2556,6 +2562,7 @@ public Object marshallable(@NotNull Object object, @NotNull SerializationStrateg * @return A new instance of the class initialized with the data from the wire. */ @NotNull + @Deprecated(/* to be removed in 2027 */) public Demarshallable demarshallable(@NotNull Class clazz) { pushState(); @@ -2566,9 +2573,8 @@ public Demarshallable demarshallable(@NotNull Class clazz) { // Handle type prefix indicated by '!' character. if (code == '!') { typePrefix(null, (o, x) -> { /* sets acquireStringBuilder(); */}); - } - // Throw exception if unsupported type is encountered. - else if (code != '{') { + } else if (code != '{') { + // Throw exception if unsupported type is encountered. throw new IORuntimeException("Unsupported type " + stringForCode(code)); } @@ -2616,9 +2622,9 @@ public T typedMarshallable() throws InvalidMarshallableException { /** * Deserialize the wire input into a Map of a given key and value type. * - * @param kClass The class type of the key. - * @param vClass The class type of the value. - * @param usingMap An optional map to populate. If null, a new map will be created. + * @param kClass The class type of the key. + * @param vClass The class type of the value. + * @param usingMap An optional map to populate. If null, a new map will be created. * @return A Map populated with deserialized keys and values. * @throws InvalidMarshallableException If there's a problem deserializing the input. */ @@ -2650,10 +2656,10 @@ public T typedMarshallable() throws InvalidMarshallableException { /** * Deserialize a typed map from the wire input. * - * @param kClazz The class type of the key. - * @param vClass The class type of the value. - * @param usingMap The map to populate. - * @param sb A StringBuilder to use during deserialization. + * @param kClazz The class type of the key. + * @param vClass The class type of the value. + * @param usingMap The map to populate. + * @param sb A StringBuilder to use during deserialization. * @return The populated map or null if the input represents a null value. * @throws InvalidMarshallableException If there's a problem deserializing the input. */ @@ -2670,7 +2676,7 @@ private Map typedMap(@NotNull Class kClazz, @NotNull Class vC text(); return null; - // If the string indicates a sequence map type. + // If the string indicates a sequence map type. } else if (("!" + SEQ_MAP).contentEquals(sb)) { consumePadding(); int start = readCode(); @@ -2689,7 +2695,7 @@ private Map typedMap(@NotNull Class kClazz, @NotNull Class vC } while (hasNextSequenceItem()); return usingMap; - // Unsupported type. + // Unsupported type. } else { throw new IORuntimeException("Unsupported type :" + str); } @@ -2752,6 +2758,8 @@ public long int64() { case '{': Jvm.warn().on(getClass(), "Unable to read " + valueIn.objectBestEffort() + " as a long."); return 0; + default: + break; } long l = getALong(); @@ -2802,6 +2810,8 @@ public double float64() { case '"': sep = bytes.readUnsignedByte(); break; + default: + break; } final double v = bytes.parseDouble(); @@ -2882,7 +2892,7 @@ public Object objectWithInferredType(Object using, @NotNull SerializationStrateg * from the stream, appending both to the resulting Map. * * @param using The object instance to be used for the result. It can be reused for efficiency. - * @param o The key that has been read earlier. + * @param o The key that has been read earlier. * @return The constructed map containing all key-value pairs. * @throws InvalidMarshallableException If any errors occur during the deserialization process. */ @@ -2908,8 +2918,8 @@ Object readRestOfMap(Object using, Object o) throws InvalidMarshallableException * deserialization logic for that type. * * @param reusableInstance An object to potentially reuse during deserialization for efficiency. - * @param strategy The serialization strategy to be applied during deserialization. - * @param type The expected type of the resulting object. + * @param strategy The serialization strategy to be applied during deserialization. + * @param type The expected type of the resulting object. * @return The deserialized object. * @throws InvalidMarshallableException If any issues are encountered during the deserialization process. */ @@ -2947,6 +2957,8 @@ Object objectWithInferredType0(Object reusableInstance, @NotNull SerializationSt case '9': case '+': return valueIn.readNumber(); + default: + break; } // Convert the content to a Bytes or StringBuilder if the using object is of that type. @@ -2980,7 +2992,7 @@ Object objectWithInferredType0(Object reusableInstance, @NotNull SerializationSt * recognizable as any of these formats, the original string is returned. * * @return The decoded number, date, time, or original string. Returns null if the - * string is either null or exceeds 40 characters in length. + * string is either null or exceeds 40 characters in length. */ @Nullable protected Object readNumber() { @@ -3040,7 +3052,7 @@ protected Object readNumber() { /** * Reads a sequence from the current stream context and attempts to interpret * it based on the provided class type. This method has specialized handling - * for arrays and collections including {@link Object[]}, {@link String[]}, + * for arrays and collections including {@code Object[]}, {@code String[]}, * {@link List}, and {@link Set}. *

    * If the class type isn't one of the recognized specialized types, an @@ -3062,7 +3074,7 @@ private Object readSequence(@NotNull Class clazz) { }); return clazz == Object[].class ? list.toArray() : list; - // Handle sequences expected to be of type String[]. + // Handle sequences expected to be of type String[]. } else if (clazz == String[].class) { @NotNull List list = new ArrayList<>(); sequence(list, (l, v) -> { @@ -3072,7 +3084,7 @@ private Object readSequence(@NotNull Class clazz) { }); return list.toArray(new String[0]); - // Handle sequences expected to be of type List. + // Handle sequences expected to be of type List. } else if (clazz == List.class) { @NotNull List list = new ArrayList<>(); sequence(list, (l, v) -> { @@ -3082,7 +3094,7 @@ private Object readSequence(@NotNull Class clazz) { }); return list; - // Handle sequences expected to be of type Set. + // Handle sequences expected to be of type Set. } else if (clazz == Set.class) { @NotNull Set list = new HashSet<>(); sequence(list, (l, v) -> { @@ -3092,7 +3104,7 @@ private Object readSequence(@NotNull Class clazz) { }); return list; - // Throw an exception if the class type is unsupported. + // Throw an exception if the class type is unsupported. } else { throw new UnsupportedOperationException("Arrays of type " + clazz + " not supported."); diff --git a/src/main/java/net/openhft/chronicle/wire/TextWriteDocumentContext.java b/src/main/java/net/openhft/chronicle/wire/TextWriteDocumentContext.java index 1dbb3919a0..bfa248c38f 100644 --- a/src/main/java/net/openhft/chronicle/wire/TextWriteDocumentContext.java +++ b/src/main/java/net/openhft/chronicle/wire/TextWriteDocumentContext.java @@ -15,6 +15,7 @@ * While writing, it can be ensured that meta-data is correctly specified, and the position of the write * operation is recorded. */ +@SuppressWarnings("deprecation") public class TextWriteDocumentContext implements WriteDocumentContext { // The wire used for writing. diff --git a/src/main/java/net/openhft/chronicle/wire/TriConsumer.java b/src/main/java/net/openhft/chronicle/wire/TriConsumer.java index dfe14295e9..72a569a894 100644 --- a/src/main/java/net/openhft/chronicle/wire/TriConsumer.java +++ b/src/main/java/net/openhft/chronicle/wire/TriConsumer.java @@ -47,6 +47,7 @@ public interface TriConsumer { * @throws NullPointerException if {@code after} is null */ @NotNull + @Deprecated(/* to be removed in 2027 */) default TriConsumer andThen(@NotNull TriConsumer after) { Objects.requireNonNull(after); diff --git a/src/main/java/net/openhft/chronicle/wire/ValueIn.java b/src/main/java/net/openhft/chronicle/wire/ValueIn.java index 6f20da7ba4..08574630bf 100644 --- a/src/main/java/net/openhft/chronicle/wire/ValueIn.java +++ b/src/main/java/net/openhft/chronicle/wire/ValueIn.java @@ -77,6 +77,7 @@ default WireIn text(@NotNull StringBuilder sb) { * * @return The first character of the text data or '\u0000' if none. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default char character() { try (ScopedResource stlSb = Wires.acquireStringBuilderScoped()) { @Nullable CharSequence cs = textTo(stlSb.get()); @@ -94,6 +95,7 @@ default char character() { * @return The current WireIn instance. */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default WireIn text(@NotNull Bytes sdo) { sdo.clear(); textTo(sdo); @@ -142,6 +144,7 @@ default WireIn text(@NotNull Bytes sdo) { * @param clearBytes If true, the BytesOut object will be cleared before reading. * @return The current WireIn instance. */ + @Deprecated(/* to be removed in 2027 */) default WireIn bytes(@NotNull BytesOut toBytes, boolean clearBytes) { if (clearBytes) toBytes.clear(); @@ -167,6 +170,7 @@ default WireIn bytesLiteral(@NotNull BytesOut toBytes) { * @return The BytesStore object or null. */ @Nullable + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default BytesStore bytesLiteral() { return bytesStore(); } @@ -178,6 +182,7 @@ default WireIn bytesLiteral(@NotNull BytesOut toBytes) { * @return The current WireIn instance. */ @Nullable + @Deprecated(/* to be removed in 2027, as it is only used in tests */) WireIn bytesSet(@NotNull PointerBytesStore toBytes); /** @@ -188,6 +193,7 @@ default WireIn bytesLiteral(@NotNull BytesOut toBytes) { * @return The current WireIn instance. */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) WireIn bytesMatch(@NotNull BytesStore compareBytes, BooleanConsumer consumer); /** @@ -195,6 +201,7 @@ default WireIn bytesLiteral(@NotNull BytesOut toBytes) { * custom deserialisation. */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) WireIn bytes(@NotNull ReadBytesMarshallable bytesMarshallable); /** @@ -227,6 +234,7 @@ default WireIn bytesLiteral(@NotNull BytesOut toBytes) { * * @param bb The ByteBuffer to put the byte data. */ + @Deprecated(/* to be removed in 2027 */) default void byteBuffer(@NotNull ByteBuffer bb) { bb.put(bytes()); } @@ -244,6 +252,7 @@ default void byteBuffer(@NotNull ByteBuffer bb) { * * @return The length of the field in bytes. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) long readLength(); /** @@ -261,29 +270,34 @@ default void byteBuffer(@NotNull ByteBuffer bb) { * @param type of the context object * @return the parent {@link WireIn} */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) @NotNull WireIn bool(T target, @NotNull ObjBooleanConsumer flagConsumer); /** * Reads the value as a signed byte and passes it to {@code byteConsumer} together with * {@code target}. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) @NotNull WireIn int8(@NotNull T target, @NotNull ObjByteConsumer byteConsumer); /** * Reads the value as an unsigned byte and passes it to {@code shortConsumer} with * {@code target}. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) @NotNull WireIn uint8(@NotNull T target, @NotNull ObjShortConsumer shortConsumer); /** * Reads the value as a short and passes it to {@code shortConsumer} with {@code target}. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) @NotNull WireIn int16(@NotNull T target, @NotNull ObjShortConsumer shortConsumer); /** * Reads the value as an unsigned short and passes it to {@code intConsumer} with * {@code target}. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) @NotNull WireIn uint16(@NotNull T target, @NotNull ObjIntConsumer intConsumer); /** @@ -296,6 +310,7 @@ default void byteBuffer(@NotNull ByteBuffer bb) { * Reads the value as an unsigned int and passes it to {@code longConsumer} with * {@code target}. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) @NotNull WireIn uint32(@NotNull T target, @NotNull ObjLongConsumer longConsumer); /** @@ -308,6 +323,7 @@ default void byteBuffer(@NotNull ByteBuffer bb) { * Reads the value as a {@code float} and passes it to {@code floatConsumer} with * {@code target}. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) @NotNull WireIn float32(@NotNull T target, @NotNull ObjFloatConsumer floatConsumer); /** @@ -316,6 +332,7 @@ default void byteBuffer(@NotNull ByteBuffer bb) { */ @NotNull WireIn float64(@NotNull T target, @NotNull ObjDoubleConsumer doubleConsumer); + @Deprecated(/* to be removed in 2027, as it is only used in tests */) @NotNull WireIn time(@NotNull T t, @NotNull BiConsumer setLocalTime); /** @@ -326,6 +343,7 @@ default void byteBuffer(@NotNull ByteBuffer bb) { * @param tZonedDateTime The BiConsumer that accepts the object and the read ZonedDateTime. * @return The WireIn instance for method chaining. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) @NotNull WireIn zonedDateTime(@NotNull T t, @NotNull BiConsumer tZonedDateTime); /** @@ -336,6 +354,7 @@ default void byteBuffer(@NotNull ByteBuffer bb) { * @param tLocalDate The BiConsumer that accepts the object and the read LocalDate. * @return The WireIn instance for method chaining. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) @NotNull WireIn date(@NotNull T t, @NotNull BiConsumer tLocalDate); /** @@ -396,6 +415,7 @@ default ZonedDateTime zonedDateTime() { * @param tuuid The BiConsumer that accepts the object and the read UUID. * @return The WireIn instance for method chaining. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) @NotNull WireIn uuid(@NotNull T t, @NotNull BiConsumer tuuid); /** @@ -457,6 +477,7 @@ default LongValue int64ForBinding(@Nullable LongValue value) { * @param ret The BooleanValue to be populated. * @return The current WireIn instance. */ + @Deprecated(/* to be removed in 2027 */) WireIn bool(@NotNull BooleanValue ret); /** @@ -468,6 +489,7 @@ default LongValue int64ForBinding(@Nullable LongValue value) { * @param The type of the target object. * @return The current WireIn instance. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) @NotNull WireIn int64(@Nullable LongValue value, T t, @NotNull BiConsumer setter); /** @@ -479,6 +501,7 @@ default LongValue int64ForBinding(@Nullable LongValue value) { * @param The type of the target object. * @return The current WireIn instance. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) @NotNull WireIn int32(@Nullable IntValue value, T t, @NotNull BiConsumer setter); /** @@ -510,6 +533,7 @@ default LongValue int64ForBinding(@Nullable LongValue value) { * @param tReader The SerializationStrategy to process the object. * @return True if the sequence was processed, false otherwise. */ + @Deprecated(/* to be removed in 2027 */) default boolean sequence(@NotNull T t, @NotNull SerializationStrategy tReader) throws InvalidMarshallableException { return sequence(t, (using, in) -> tReader.readUsing(null, using, in, BracketType.UNKNOWN)); } @@ -582,6 +606,7 @@ default int sequenceWithLength(@NotNull T t, @NotNull ToIntBiFunction { int i = 0; @@ -600,6 +625,7 @@ default int array(Bytes[] array) { * @param array The array of double values to be populated. * @return The number of double values read and populated. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default int array(double[] array) { return sequenceWithLength(array, (in, a) -> { int i = 0; @@ -615,6 +641,7 @@ default int array(double[] array) { * @param array The array of double values to be populated. * @return The number of double values read and populated. */ + @Deprecated(/* to be removed in 2027 */) default int arrayDelta(double[] array) { return sequenceWithLength(array, (in, a) -> { if (!in.hasNextSequenceItem() || a.length == 0) @@ -633,6 +660,7 @@ default int arrayDelta(double[] array) { * @param array The array of boolean values to be populated. * @return The number of boolean values read and populated. */ + @Deprecated(/* to be removed in 2027 */) default int array(boolean[] array) { return sequenceWithLength(array, (in, a) -> { int i = 0; @@ -648,6 +676,7 @@ default int array(boolean[] array) { * @param array The array of long values to be populated. * @return The number of long values read and populated. */ + @Deprecated(/* to be removed in 2027 */) default int array(long[] array) { return sequenceWithLength(array, (in, a) -> { int i = 0; @@ -663,6 +692,7 @@ default int array(long[] array) { * @param array The array of long values to be populated. * @return The number of long values read and populated. */ + @Deprecated(/* to be removed in 2027 */) default int arrayDelta(long[] array) { return sequenceWithLength(array, (in, a) -> { if (!in.hasNextSequenceItem() || a.length == 0) @@ -681,6 +711,7 @@ default int arrayDelta(long[] array) { * @param array The array of int values to be populated. * @return The number of int values read and populated. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default int array(int[] array) { return sequenceWithLength(array, (in, a) -> { int i = 0; @@ -696,6 +727,7 @@ default int array(int[] array) { * @param array The array of byte values to be populated. * @return The number of byte values read and populated. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default int array(byte[] array) { return sequenceWithLength(array, (in, a) -> { int i = 0; @@ -712,6 +744,7 @@ default int array(byte[] array) { * @param t The Class object representing the type T. * @return A Set containing objects of type T, or throws InvalidMarshallableException in case of an error. */ + @Deprecated(/* to be removed in 2027 */) default Set set(Class t) throws InvalidMarshallableException { return collection(LinkedHashSet::new, t); } @@ -723,6 +756,7 @@ default Set set(Class t) throws InvalidMarshallableException { * @param t The Class object representing the type T. * @return A List containing objects of type T, or throws InvalidMarshallableException in case of an error. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default List list(Class t) throws InvalidMarshallableException { return collection(ArrayList::new, t); } @@ -755,6 +789,7 @@ default > C collection(@NotNull Supplier supplier, * @return The WireIn instance for method chaining. */ @NotNull + @Deprecated(/* to be removed in 2027 */) default WireIn set(@NotNull O o, Function tSupplier) throws InvalidMarshallableException { return collection(o, tSupplier); } @@ -769,6 +804,7 @@ default WireIn set(@NotNull O o, Function * @return The WireIn instance for method chaining. */ @NotNull + @Deprecated(/* to be removed in 2027 */) default WireIn list(@NotNull O o, Function tSupplier) throws InvalidMarshallableException { return collection(o, tSupplier); } @@ -831,6 +867,7 @@ default Map marshallableAsMap(Class kClass, @NotNull Class vC * @param marshallableReader The Function to apply to this ValueIn. * @return The result of applying the Function to this ValueIn, or null if it cannot be applied. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) @Nullable T applyToMarshallable(Function marshallableReader); /** @@ -851,6 +888,7 @@ default Map marshallableAsMap(Class kClass, @NotNull Class vC * @throws InvalidMarshallableException if the marshallable object is invalid */ @Nullable + @Deprecated(/* to be removed in 2027 */) default T typedMarshallable(@NotNull Function, ReadMarshallable> marshallableFunction) throws IORuntimeException, InvalidMarshallableException { @Nullable final Class aClass = (Class) typePrefix(); @@ -871,6 +909,7 @@ default T typedMarshallable(@NotNull Function, ReadMarshallable> ma * @param ts The BiConsumer that accepts the object and the type prefix. * @return The WireIn instance for method chaining. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) @NotNull ValueIn typePrefix(T t, @NotNull BiConsumer ts); /** @@ -921,6 +960,7 @@ default WireIn typeLiteral(T t, @NotNull BiConsumer classConsumer) * @return The WireIn instance for method chaining. */ @NotNull + @Deprecated(/* to be removed in 2027 */) default WireIn typeLiteral(T t, @NotNull BiConsumer classConsumer, Class defaultClass) { return typeLiteralAsText(t, (o, x) -> { Class u = classLookup().forName(x); @@ -951,6 +991,7 @@ Object marshallable(@NotNull Object object, @NotNull SerializationStrategy strat * @throws IORuntimeException if an I/O error occurs * @throws InvalidMarshallableException if the Serializable object is invalid */ + @Deprecated(/* to be removed in 2027 */) default boolean marshallable(@NotNull Serializable object) throws BufferUnderflowException, IORuntimeException, InvalidMarshallableException { return marshallable(object, SerializationStrategies.SERIALIZABLE) != null; } @@ -1133,6 +1174,7 @@ default > E asEnum(Class eClass) { * @return The WireIn instance for method chaining. */ @NotNull + @Deprecated(/* to be removed in 2027 */) default > WireIn asEnum(Class eClass, @NotNull Consumer eConsumer) { eConsumer.accept(asEnum(eClass)); return wireIn(); @@ -1147,6 +1189,7 @@ default > WireIn asEnum(Class eClass, @NotNull Consumer * @return The WireIn instance for method chaining. */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default , T> WireIn asEnum(Class eClass, T t, @NotNull BiConsumer teConsumer) { teConsumer.accept(t, asEnum(eClass)); return wireIn(); @@ -1275,6 +1318,7 @@ default E object(@Nullable E using, @Nullable Class clazz, bool * @throws InvalidMarshallableException if the object is invalid */ @Nullable + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default WireIn object(@NotNull Class clazz, T t, @NotNull BiConsumer e) throws InvalidMarshallableException { e.accept(t, object(clazz)); return wireIn(); @@ -1371,6 +1415,7 @@ default long readLong(LongConverter longConverter) { * * @return The boolean value read from the wire. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default boolean readBoolean() { return bool(); } @@ -1389,6 +1434,7 @@ default byte readByte() { * * @return The char value read from the wire. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default char readChar() { return (char) uint16(); } @@ -1398,6 +1444,7 @@ default char readChar() { * * @return The short value read from the wire. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default short readShort() { return int16(); } @@ -1425,6 +1472,7 @@ default long readLong() { * * @return The float value read from the wire. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default float readFloat() { return float32(); } diff --git a/src/main/java/net/openhft/chronicle/wire/ValueOut.java b/src/main/java/net/openhft/chronicle/wire/ValueOut.java index 710090f517..6ac64f3283 100644 --- a/src/main/java/net/openhft/chronicle/wire/ValueOut.java +++ b/src/main/java/net/openhft/chronicle/wire/ValueOut.java @@ -17,7 +17,6 @@ import net.openhft.chronicle.core.util.ObjectUtils; import net.openhft.chronicle.core.values.*; import net.openhft.chronicle.threads.NamedThreadFactory; -import net.openhft.chronicle.wire.internal.MapMarshaller; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -44,7 +43,7 @@ * Defines an interface for writing out values after writing a field. * Implementations of this interface should provide methods to handle writing various data types. */ -@SuppressWarnings({"rawtypes", "unchecked"}) +@SuppressWarnings({"rawtypes", "unchecked", "deprecation"}) public interface ValueOut { /** @@ -126,6 +125,7 @@ default WireOut text(char c) { * Alias for {@link #text(char)}. */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default WireOut character(char c) { return text(c); } @@ -202,6 +202,7 @@ default WireOut bytesLiteral(@Nullable BytesStore fromBytes) { * @return The WireOut instance for chained calls. */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) WireOut rawBytes(byte[] value); /** @@ -216,6 +217,14 @@ default WireOut rawText(CharSequence value) { return text(value); } + /** + * Compatibility shim preserving the public nested MapMarshaller type from 2.27ea0. + * Delegates to the implementation in {@code net.openhft.chronicle.wire.internal.MapMarshaller}. + */ + class MapMarshaller extends net.openhft.chronicle.wire.internal.MapMarshaller { + // no-op subclass to preserve binary compatibility + } + /** * Write the length of a value if supported by the implementing class. * @@ -223,6 +232,7 @@ default WireOut rawText(CharSequence value) { * @return A ValueOut instance for chained calls. */ @NotNull + @Deprecated(/* to be removed in 2027 */) ValueOut writeLength(long remaining); /** @@ -242,6 +252,7 @@ default WireOut rawText(CharSequence value) { * @return The WireOut instance for chained calls. */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) WireOut bytes(String type, byte[] fromBytes); /** @@ -319,6 +330,7 @@ default WireOut uint16(long x) { * @return The WireOut instance for chained calls. */ @NotNull + @Deprecated(/* to be removed in 2027 */) WireOut utf8(int codepoint); /** @@ -581,7 +593,7 @@ default WireOut typeLiteral(@Nullable Class type) { @NotNull default WireOut typeLiteral(@Nullable Type type) { return type == null ? nu11() - : type instanceof Class? typeLiteral((Class) type) + : type instanceof Class ? typeLiteral((Class) type) : typeLiteral(type.getTypeName()); } @@ -637,6 +649,7 @@ default WireOut typeLiteral(@Nullable Type type) { * Throws an unsupported operation exception by default. May be overridden by specific implementations. */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default WireOut int128forBinding(long value, long value2) { throw new UnsupportedOperationException(); } @@ -651,6 +664,7 @@ default WireOut int128forBinding(long value, long value2) { * Writes a boolean value for binding with the given BooleanValue. This may be used for additional metadata or configuration. */ @NotNull + @Deprecated(/* to be removed in 2027 */) WireOut boolForBinding(boolean value, @NotNull BooleanValue longValue); /** @@ -735,6 +749,7 @@ default WireOut sequenceWithLength(T t, int length, ObjectIntObjectConsumer< * @param length The length of the sequence. * @return The WireOut instance for chained calls. */ + @Deprecated(/* to be removed in 2027 */) default WireOut array(Bytes[] array, int length) { return sequenceWithLength(array, length, (a, len, out) -> { for (int i = 0; i < len; i++) @@ -749,6 +764,7 @@ default WireOut array(Bytes[] array, int length) { * @param length The length of the sequence. * @return The WireOut instance for chained calls. */ + @Deprecated(/* to be removed in 2027 */) default WireOut array(double[] array, int length) { return sequenceWithLength(array, length, (a, len, out) -> { for (int i = 0; i < len; i++) @@ -763,6 +779,7 @@ default WireOut array(double[] array, int length) { * @param length to write * @return this */ + @Deprecated(/* to be removed in 2027 */) default WireOut arrayDelta(double[] array, int length) { return sequenceWithLength(array, length, (a, len, out) -> { if (len <= 0) return; @@ -781,6 +798,7 @@ default WireOut arrayDelta(double[] array, int length) { * @param length The number of elements from the array to write. * @return The current instance of the WireOut. */ + @Deprecated(/* to be removed in 2027 */) default WireOut array(boolean[] array, int length) { return sequenceWithLength(array, length, (a, len, out) -> { for (int i = 0; i < len; i++) @@ -795,6 +813,7 @@ default WireOut array(boolean[] array, int length) { * @param length The number of elements from the array to write. * @return The current instance of the WireOut. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default WireOut array(long[] array, int length) { return sequenceWithLength(array, length, (a, len, out) -> { for (int i = 0; i < len; i++) @@ -811,6 +830,7 @@ default WireOut array(long[] array, int length) { * @param length The number of elements from the array to write. * @return The current instance of the WireOut. */ + @Deprecated(/* to be removed in 2027 */) default WireOut arrayDelta(long[] array, int length) { return sequenceWithLength(array, length, (a, len, out) -> { if (len <= 0) return; @@ -828,6 +848,7 @@ default WireOut arrayDelta(long[] array, int length) { * @param length The number of elements from the array to write. * @return The current instance of the WireOut. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default WireOut array(int[] array, int length) { return sequenceWithLength(array, length, (a, len, out) -> { for (int i = 0; i < len; i++) @@ -842,6 +863,7 @@ default WireOut array(int[] array, int length) { * @param length The number of elements from the array to write. * @return The current instance of the WireOut. */ + @Deprecated(/* to be removed in 2027 */) default WireOut array(byte[] array, int length) { return sequenceWithLength(array, length, (a, len, out) -> { for (int i = 0; i < len; i++) @@ -1021,6 +1043,7 @@ default > WireOut asEnum(@Nullable E e) { * @throws InvalidMarshallableException If the set cannot be marshalled. */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default WireOut set(Set coll) throws InvalidMarshallableException { return set(coll, null); } @@ -1048,6 +1071,7 @@ default WireOut set(Set coll, Class assumedClass) throws InvalidMarsha * @throws InvalidMarshallableException If the list cannot be marshalled. */ @NotNull + @Deprecated(/* to be removed in 2027 */) default WireOut list(List coll) throws InvalidMarshallableException { return list(coll, null); } @@ -1308,6 +1332,8 @@ default WireOut object(@Nullable Object value) throws InvalidMarshallableExcepti endTypePrefix(); return result; } + default: + break; } // Check if the value is an instance of WriteMarshallable interface if (value instanceof WriteMarshallable) { @@ -1323,15 +1349,11 @@ default WireOut object(@Nullable Object value) throws InvalidMarshallableExcepti // Check if the value is an instance of WriteBytesMarshallable interface if (value instanceof WriteBytesMarshallable) { - // Warn about possible unmarshalling issue - if (!Wires.warnedUntypedBytesOnce) { + if (Wires.markUntypedBytesWarning()) { Jvm.warn().on(ValueOut.class, "BytesMarshallable found in field which is not matching exactly, " + "the object may not unmarshall correctly if that type is not specified: " + valueClass.getName() + ". The warning will not repeat so there may be more types affected."); - - Wires.warnedUntypedBytesOnce = true; } - return bytesMarshallable((BytesMarshallable) value); } @@ -1519,6 +1541,8 @@ default WireOut untypedObject(@Nullable Object value) throws InvalidMarshallable case "java.math.BigDecimal": case "java.io.File": return text(value.toString()); + default: + break; } // Check if value is an Enum and get its name if (isAnEnum(value)) { @@ -1622,6 +1646,7 @@ default WireOut compress(@NotNull String compression, @Nullable Bytes uncompr } // Gets the size of the compressed data, if available, or returns max int value as a default + @Deprecated(/* to be removed in 2027 */) default int compressedSize() { return Integer.MAX_VALUE; } @@ -1651,6 +1676,7 @@ default boolean isBinary() { * @param x The boolean value to be written. * @return The WireOut instance after the operation. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default WireOut writeBoolean(boolean x) { return bool(x); } @@ -1673,6 +1699,7 @@ default WireOut writeByte(byte x) { * @param x The char value to be written. * @return The WireOut instance after the operation. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default WireOut writeChar(char x) { return uint16(x); } @@ -1684,6 +1711,7 @@ default WireOut writeChar(char x) { * @param x The short value to be written. * @return The WireOut instance after the operation. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default WireOut writeShort(short x) { return int16(x); } @@ -1717,6 +1745,7 @@ default WireOut writeLong(long x) { * @param x The float value to be written. * @return The WireOut instance after the operation. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default WireOut writeFloat(float x) { return float32(x); } @@ -1751,6 +1780,7 @@ default WireOut writeString(CharSequence x) { * @param i The integer to be converted and written. * @return The WireOut instance after the operation. */ + @Deprecated(/* to be removed in 2027 */) default WireOut writeInt(LongConverter converter, int i) { try (ScopedResource stlSb = Wires.acquireStringBuilderScoped()) { StringBuilder sb = stlSb.get(); @@ -1784,5 +1814,4 @@ default WireOut writeLong(LongConverter longConverter, long l) { default void elementSeparator() { // Do nothing in the default implementation } - } diff --git a/src/main/java/net/openhft/chronicle/wire/VanillaMessageHistory.java b/src/main/java/net/openhft/chronicle/wire/VanillaMessageHistory.java index 45a0a84f14..3018ec6faa 100644 --- a/src/main/java/net/openhft/chronicle/wire/VanillaMessageHistory.java +++ b/src/main/java/net/openhft/chronicle/wire/VanillaMessageHistory.java @@ -24,7 +24,7 @@ * {@link #MESSAGE_HISTORY_LENGTH}. The object can be marshalled in a compact * binary form or as a verbose textual structure. */ -@SuppressWarnings("rawtypes") +@SuppressWarnings({"rawtypes", "deprecation"}) public class VanillaMessageHistory extends SelfDescribingMarshallable implements MessageHistory { /** @@ -173,6 +173,7 @@ public void reset() { * * @return True if source details are being added, false otherwise. */ + @Deprecated(/* to be removed in 2027 */) public boolean addSourceDetails() { return addSourceDetails; } @@ -407,20 +408,19 @@ private void writeMarshallableDirect(BytesOut b) { /** Fallback binary serialisation when direct memory is unavailable. */ public void writeMarshallable0(@NotNull BytesOut b) { - BytesOut bytes = b; - bytes.writeHexDumpDescription("sources") + b.writeHexDumpDescription("sources") .writeUnsignedByte(sources); for (int i = 0; i < sources; i++) - bytes.writeInt(sourceIdArray[i]); + b.writeInt(sourceIdArray[i]); for (int i = 0; i < sources; i++) - bytes.writeLong(sourceIndexArray[i]); + b.writeLong(sourceIndexArray[i]); - bytes.writeHexDumpDescription("timings") + b.writeHexDumpDescription("timings") .writeUnsignedByte(timings + 1);// one more time for this output for (int i = 0; i < timings; i++) { - bytes.writeLong(timingsArray[i]); + b.writeLong(timingsArray[i]); } - bytes.writeLong(nanoTime()); // add time for this output + b.writeLong(nanoTime()); // add time for this output dirty = false; } diff --git a/src/main/java/net/openhft/chronicle/wire/VanillaMethodReader.java b/src/main/java/net/openhft/chronicle/wire/VanillaMethodReader.java index 61bab51a41..7088090c4a 100644 --- a/src/main/java/net/openhft/chronicle/wire/VanillaMethodReader.java +++ b/src/main/java/net/openhft/chronicle/wire/VanillaMethodReader.java @@ -40,7 +40,7 @@ * Supports interception via {@link MethodReaderInterceptorReturns} and custom * parsing through {@link WireParselet} and {@link FieldNumberParselet}. */ -@SuppressWarnings({"rawtypes","this-escape"}) +@SuppressWarnings({"rawtypes", "this-escape", "deprecation"}) public class VanillaMethodReader implements MethodReader { // beware enabling DEBUG_ENABLED as logMessage will not work unless Wire marshalling used - https://github.com/ChronicleEnterprise/Chronicle-Services/issues/240 @@ -83,12 +83,12 @@ public class VanillaMethodReader implements MethodReader { /** * Convenience constructor used by generated code. * - * @param in source of wire messages - * @param ignoreDefault if true default interface methods are skipped - * @param defaultParselet parselet for unknown events + * @param in source of wire messages + * @param ignoreDefault if true default interface methods are skipped + * @param defaultParselet parselet for unknown events * @param methodReaderInterceptorReturns optional interceptor - * @param metadataHandlers handlers for metadata messages - * @param handlers handler instances for data messages + * @param metadataHandlers handlers for metadata messages + * @param handlers handler instances for data messages */ @UsedViaReflection public VanillaMethodReader(MarshallableIn in, @@ -103,12 +103,12 @@ public VanillaMethodReader(MarshallableIn in, /** * Convenience constructor used by generated code. * - * @param in source of wire messages - * @param ignoreDefault if true default interface methods are skipped - * @param defaultParselet parselet for unknown events - * @param fieldNumberParselet parselet for numeric ids + * @param in source of wire messages + * @param ignoreDefault if true default interface methods are skipped + * @param defaultParselet parselet for unknown events + * @param fieldNumberParselet parselet for numeric ids * @param methodReaderInterceptorReturns optional interceptor - * @param handlers handler instances for data messages + * @param handlers handler instances for data messages */ @UsedViaReflection public VanillaMethodReader(MarshallableIn in, @@ -124,13 +124,13 @@ public VanillaMethodReader(MarshallableIn in, * Constructor that defaults the predicate to always true. * It ultimately calls the primary constructor. * - * @param in source of wire messages - * @param ignoreDefault if true default interface methods are skipped - * @param defaultParselet parselet for unknown events - * @param fieldNumberParselet parselet for numeric ids + * @param in source of wire messages + * @param ignoreDefault if true default interface methods are skipped + * @param defaultParselet parselet for unknown events + * @param fieldNumberParselet parselet for numeric ids * @param methodReaderInterceptorReturns optional interceptor - * @param metadataHandlers handlers for metadata messages - * @param handlers handler instances for data messages + * @param metadataHandlers handlers for metadata messages + * @param handlers handler instances for data messages */ public VanillaMethodReader(MarshallableIn in, boolean ignoreDefault, @@ -150,14 +150,14 @@ public VanillaMethodReader(MarshallableIn in, /** * Primary constructor configuring parsers and interceptors. * - * @param in source of wire messages - * @param ignoreDefault if true default interface methods are skipped - * @param defaultParselet parselet for unknown events - * @param fieldNumberParselet parselet for numeric ids + * @param in source of wire messages + * @param ignoreDefault if true default interface methods are skipped + * @param defaultParselet parselet for unknown events + * @param fieldNumberParselet parselet for numeric ids * @param methodReaderInterceptorReturns optional interceptor - * @param metadataHandlers handlers for metadata messages - * @param predicate predicate controlling readOne execution - * @param handlers handler instances for data messages + * @param metadataHandlers handlers for metadata messages + * @param predicate predicate controlling readOne execution + * @param handlers handler instances for data messages */ public VanillaMethodReader(MarshallableIn in, boolean ignoreDefault, @@ -211,15 +211,15 @@ private static LongConversion longConversionForFirstParam(Method method) { * Invokes {@code method} on {@code target} (or {@code context[0]}) with one long argument. * The argument is read from {@code valueIn}, applying any {@link LongConversion}. * - * @param target handler when {@code context[0]} is null + * @param target handler when {@code context[0]} is null * @param contextHolder invocation context array - * @param method method to call - * @param methodName method name for logging - * @param methodHandle optional bound MethodHandle - * @param argHolder scratch array for the argument - * @param eventName event name being read - * @param valueIn value reader - * @param interceptor optional interceptor + * @param method method to call + * @param methodName method name for logging + * @param methodHandle optional bound MethodHandle + * @param argHolder scratch array for the argument + * @param eventName event name being read + * @param valueIn value reader + * @param interceptor optional interceptor */ private static void invokeMethodWithOneLong(Object target, Object[] contextHolder, @NotNull Method method, String methodName, MethodHandle methodHandle, Object[] argHolder, CharSequence eventName, ValueIn valueIn, MethodReaderInterceptorReturns interceptor) { try { @@ -293,7 +293,7 @@ private static void updateContext(Object[] contextHolder, Object intercept) { * * @param method The method to be invoked. * @param target The object on which the method is to be invoked. - * @param args The arguments for the method. + * @param args The arguments for the method. * @return The result of the method invocation. * @throws InvocationTargetException if the method invocation fails. */ @@ -355,7 +355,7 @@ public static void logMessage(@NotNull CharSequence eventName, @NotNull ValueIn * Combine explicit metadata handlers with the general handler list. * * @param metadataHandlers handlers dedicated to metadata messages - * @param handlers general handler objects + * @param handlers general handler objects * @return merged array */ private Object[] addObjectsToMetaDataHandlers(Object[] metadataHandlers, @NotNull Object @NotNull [] handlers) { @@ -376,9 +376,9 @@ private Object[] addObjectsToMetaDataHandlers(Object[] metadataHandlers, @NotNul * on the first argument is supported. Interfaces implemented by each object are examined * to define these parselets. * - * @param wireParser The WireParser to be configured. + * @param wireParser The WireParser to be configured. * @param ignoreDefault If true, defaults are ignored. - * @param handlers The objects that provide the necessary information for configuring the parser. + * @param handlers The objects that provide the necessary information for configuring the parser. */ private void addParsersForComponents(WireParser wireParser, boolean ignoreDefault, @NotNull Object @NotNull [] handlers) { // Sets to keep track of method signatures and names that are already handled. @@ -411,17 +411,17 @@ private void addParsersForComponents(WireParser wireParser, boolean ignoreDefaul * The main focus is to ensure each method signature is only added once, and to properly handle methods * with varying numbers of arguments. * - * @param wireParser The WireParser to be configured. - * @param interfaces A set of interfaces that have already been processed. Used to avoid cyclic processing. - * @param handlerClass The class or interface to evaluate for methods. - * @param ignoreDefault If true, methods from default interfaces are ignored. - * @param methodNamesHandled A set of method names that have already been handled. + * @param wireParser The WireParser to be configured. + * @param interfaces A set of interfaces that have already been processed. Used to avoid cyclic processing. + * @param handlerClass The class or interface to evaluate for methods. + * @param ignoreDefault If true, methods from default interfaces are ignored. + * @param methodNamesHandled A set of method names that have already been handled. * @param methodsSignaturesHandled A set of method signatures that have already been handled. * @param methodFilterOnFirstArg Optional filter that can be applied on methods based on their first argument. - * @param handler The original object that the method might be invoked on. - * @param contextHolder The context in which the method will be invoked. - * @param contextSupplier Provides the current context. - * @param nextContextSupplier Provides the next context in which the method will be invoked. + * @param handler The original object that the method might be invoked on. + * @param contextHolder The context in which the method will be invoked. + * @param contextSupplier Provides the current context. + * @param nextContextSupplier Provides the next context in which the method will be invoked. */ private void addParsletsFor(WireParser wireParser, Set interfaces, Class handlerClass, boolean ignoreDefault, Set methodNamesHandled, Set methodsSignaturesHandled, MethodFilterOnFirstArg methodFilterOnFirstArg, Object handler, Object[] contextHolder, Supplier contextSupplier, Supplier nextContextSupplier) { if (!handlerClass.isInterface() || Jvm.dontChain(handlerClass)) { @@ -604,8 +604,8 @@ else if (target != null) * If the method has a MethodId annotation, the key will be based on the annotation's value, otherwise, it will be based * on the method's name's hash code. * - * @param method The method for which the key is being generated - * @param name The name of the method + * @param method The method for which the key is being generated + * @param name The name of the method * @return A MethodWireKey uniquely representing the method */ @NotNull @@ -661,8 +661,8 @@ else if (target != null) * Checks if the given object can be recycled. For collections, it clears the collection and returns the same instance. * If the object is an instance of Marshallable, it returns the same object; otherwise, it returns null. * - * @param The type of the object - * @param instance The object to check + * @param The type of the object + * @param instance The object to check * @return The original object if it can be recycled, otherwise null */ private T checkRecycle(T instance) { @@ -686,14 +686,14 @@ private T checkRecycle(T instance) { * If the filter determines that the method should be ignored based on its first argument, * the method will not be executed and subsequent arguments will be skipped. * - * @param wireParser The WireParser to which the method will be registered - * @param target The object on which the method should be invoked - * @param contextHolder The current context for method invocation - * @param contextSupplier Supplies the context for method invocation - * @param method The method to be registered - * @param parameterTypes The array of parameter types for the method - * @param methodFilterOnFirstArg The filter that decides if the method should be ignored based on its first argument - * @throws IllegalStateException If the VanillaMethodReader is closed + * @param wireParser The WireParser to which the method will be registered + * @param target The object on which the method should be invoked + * @param contextHolder The current context for method invocation + * @param contextSupplier Supplies the context for method invocation + * @param method The method to be registered + * @param parameterTypes The array of parameter types for the method + * @param methodFilterOnFirstArg The filter that decides if the method should be ignored based on its first argument + * @throws IllegalStateException If the VanillaMethodReader is closed */ @SuppressWarnings("unchecked") public void addParseletForMethod(WireParser wireParser, Object target, Object[] contextHolder, Supplier contextSupplier, @NotNull Method method, @NotNull Class[] parameterTypes, MethodFilterOnFirstArg methodFilterOnFirstArg) { @@ -763,7 +763,7 @@ else if (target != null) * @param target The object on which to invoke the method * @param method The method to invoke * @param args The arguments to pass to the method - * @return The result of the method invocation + * @return The result of the method invocation * @throws InvocationTargetRuntimeException if the invoked method itself throws an exception */ protected Object invoke(Object target, @NotNull Method method, Object[] args) throws InvocationTargetRuntimeException { diff --git a/src/main/java/net/openhft/chronicle/wire/VanillaMethodReaderBuilder.java b/src/main/java/net/openhft/chronicle/wire/VanillaMethodReaderBuilder.java index e4e804594b..e672992d59 100644 --- a/src/main/java/net/openhft/chronicle/wire/VanillaMethodReaderBuilder.java +++ b/src/main/java/net/openhft/chronicle/wire/VanillaMethodReaderBuilder.java @@ -141,6 +141,7 @@ private static String errorMsg(CharSequence s, MessageHistory history, long sour return msg.toString(); } + @Deprecated(/* to be removed in 2027 */) public WireParselet defaultParselet() { return defaultParselet; } @@ -151,11 +152,24 @@ public WireParselet defaultParselet() { * @param defaultParselet The new default parselet. * @return This builder for chaining. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public MethodReaderBuilder defaultParselet(WireParselet defaultParselet) { this.defaultParselet = defaultParselet; return this; } + /** + * Configures whether default values should be ignored when reading messages. + * + * @param ignore flag indicating whether to ignore defaults + * @return this builder for chaining + */ + @Deprecated(/* to be removed in 2027 */) + public VanillaMethodReaderBuilder ignoreDefaults(boolean ignore) { + this.ignoreDefaults = ignore; + return this; + } + /** * Sets the method reader interceptor that handles return values from method calls. * @@ -178,6 +192,7 @@ public MethodReaderBuilder exceptionHandlerOnUnknownMethod(ExceptionHandler exce * * @return The {@code wireType} of the reader. */ + @Deprecated(/* to be removed in 2027 */) public WireType wireType() { return wireType; } @@ -211,6 +226,7 @@ public VanillaMethodReaderBuilder scanning(boolean scanning) { * @param multipleNonMarshallableParamTypes Whether the reader should handle multiple non-marshallable parameter types. * @return This builder instance for chaining. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public VanillaMethodReaderBuilder multipleNonMarshallableParamTypes(Boolean multipleNonMarshallableParamTypes) { this.multipleNonMarshallableParamTypes = multipleNonMarshallableParamTypes; return this; diff --git a/src/main/java/net/openhft/chronicle/wire/VanillaMethodWriterBuilder.java b/src/main/java/net/openhft/chronicle/wire/VanillaMethodWriterBuilder.java index a70fb12892..656b2af009 100644 --- a/src/main/java/net/openhft/chronicle/wire/VanillaMethodWriterBuilder.java +++ b/src/main/java/net/openhft/chronicle/wire/VanillaMethodWriterBuilder.java @@ -121,6 +121,7 @@ public VanillaMethodWriterBuilder(@NotNull Class tClass, * @return The current instance of VanillaMethodWriterBuilder for chaining method calls. */ @NotNull + @Deprecated(/* to be removed in 2027 */) public MethodWriterBuilder classLoader(ClassLoader classLoader) { this.classLoader = classLoader; return this; @@ -188,6 +189,7 @@ public MethodWriterBuilder addInterface(Class additionalClass) { * @return this builder */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public MethodWriterBuilder disableThreadSafe(boolean theadSafe) { handlerSupplier.disableThreadSafe(theadSafe); return this; @@ -232,6 +234,7 @@ public WireType wireType() { * * @return this builder */ + @Deprecated(/* to be removed in 2027 */) public VanillaMethodWriterBuilder wireType(final WireType wireType) { this.wireType = wireType; return this; @@ -273,7 +276,7 @@ public T get() { "proxy method writers will be dropped in x.25."); } - @NotNull Class[] interfacesArr = interfaces.toArray(new Class[interfaces.size()]); + @NotNull Class[] interfacesArr = interfaces.toArray(new Class[0]); //noinspection unchecked return (T) Proxy.newProxyInstance(classLoader, interfacesArr, new CallSupplierInvocationHandler(this)); @@ -430,6 +433,7 @@ public MethodWriterBuilder metaData(final boolean metaData) { /** * @return pre-compiled proxy class if set */ + @Deprecated(/* to be removed in 2027 */) public Class proxyClass() { return proxyClass; } @@ -441,6 +445,7 @@ public Class proxyClass() { * @return The current instance of the {@link MethodWriterBuilder}, allowing chained method calls. * @throws IllegalArgumentException If the provided class is an interface. */ + @Deprecated(/* to be removed in 2027 */) public MethodWriterBuilder proxyClass(Class proxyClass) { // Check if the provided class is an interface. if (proxyClass.isInterface()) @@ -449,17 +454,6 @@ public MethodWriterBuilder proxyClass(Class proxyClass) { return this; } - /** - * Converts the first character of a given string to uppercase and the rest to lowercase. - * - * @param name The input string to be converted. - * @return The converted string with its first character in uppercase and the rest in lowercase. - */ - @NotNull - private String toFirstCapCase(@NotNull String name) { - return Character.toUpperCase(name.charAt(0)) + name.substring(1).toLowerCase(); - } - /** * The {@code CallSupplierInvocationHandler} class is an implementation of {@link InvocationHandler} * designed to act as a proxy for method calls. If the associated {@link UpdateInterceptor} returns diff --git a/src/main/java/net/openhft/chronicle/wire/VanillaWireParser.java b/src/main/java/net/openhft/chronicle/wire/VanillaWireParser.java index 45a862ca5b..80bf3d5488 100644 --- a/src/main/java/net/openhft/chronicle/wire/VanillaWireParser.java +++ b/src/main/java/net/openhft/chronicle/wire/VanillaWireParser.java @@ -22,6 +22,7 @@ * fields that are not explicitly registered and {@link #fieldNumberParselet} deals with * unmapped numeric identifiers. */ +@SuppressWarnings("deprecation") public class VanillaWireParser implements WireParser { // Map of field names to parselets. {@link CharSequenceComparator#INSTANCE} provides stable ordering and lookup semantics @@ -40,7 +41,7 @@ public class VanillaWireParser implements WireParser { private final StringBuilder lastEventName = new StringBuilder(128); // Called when a numeric field id is not mapped in {@link #numberedConsumer} - private FieldNumberParselet fieldNumberParselet; + private final FieldNumberParselet fieldNumberParselet; // Cache of the parselet associated with {@link #lastEventName} private WireParselet lastParslet = null; diff --git a/src/main/java/net/openhft/chronicle/wire/Wire.java b/src/main/java/net/openhft/chronicle/wire/Wire.java index 3755efd7c8..acc87977d7 100644 --- a/src/main/java/net/openhft/chronicle/wire/Wire.java +++ b/src/main/java/net/openhft/chronicle/wire/Wire.java @@ -3,13 +3,10 @@ */ package net.openhft.chronicle.wire; -import net.openhft.chronicle.bytes.Bytes; import net.openhft.chronicle.core.annotation.DontChain; import net.openhft.chronicle.core.annotation.SingleThreaded; import org.jetbrains.annotations.NotNull; -import java.io.IOException; - /** * Defines the standard interface for sequentially writing to and reading from a Bytes stream. * Implementations of this interface should ensure single-threaded access and avoid method chaining. @@ -41,16 +38,20 @@ static Wire newYamlWireOnHeap() { /** * Indicates whether tuples should be generated. * By default, this method returns the value of Wires.GENERATE_TUPLES + * * @return true if tuples should be generated, false otherwise. */ + @Deprecated(/* to be removed in 2027 */) default boolean generateTuples() { return Wires.GENERATE_TUPLES; } /** * Sets whether tuples should be generated. + * * @param generateTuples true to enable tuple generation, false to disable it. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default Wire generateTuples(boolean generateTuples) { return this; } diff --git a/src/main/java/net/openhft/chronicle/wire/WireCommon.java b/src/main/java/net/openhft/chronicle/wire/WireCommon.java index 7b408ea0f4..4dca8f9e04 100644 --- a/src/main/java/net/openhft/chronicle/wire/WireCommon.java +++ b/src/main/java/net/openhft/chronicle/wire/WireCommon.java @@ -12,6 +12,13 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +/** + * Common operations and configuration hooks shared by Chronicle Wire implementations. + *

    + * Implementations provide access to the underlying {@link Bytes}, reference value factories, + * class lookup and parent relationships and expose knobs such as padding, binary vs text mode and + * self describing message behaviour. + */ public interface WireCommon { /** @@ -40,6 +47,7 @@ public interface WireCommon { * * @return the current {@link Pauser} implementation being used for blocking operations */ + @Deprecated(/* to be removed in 2027 */) Pauser pauser(); /** @@ -102,6 +110,7 @@ default TwoLongValue newTwoLongReference() { * @return a new {@link IntArrayValues} */ @NotNull + @Deprecated(/* to be removed in 2027 */) IntArrayValues newIntArrayReference(); /** @@ -134,17 +143,44 @@ default boolean notCompleteIsNotPresent() { return true; } + /** + * Configure whether documents marked as NOT_COMPLETE should remain visible to readers. + * + * @param notCompleteArePresent true to expose incomplete messages, false to hide them + */ + @Deprecated(/* to be removed in 2027 */) default void notCompleteIsNotPresent(boolean notCompleteArePresent) { throw new UnsupportedOperationException(); } + /** + * Set the header number to write with the next document. + * + * @param headerNumber header to assign + * @return this wire for chaining + */ @NotNull WireOut headerNumber(long headerNumber); + /** + * Current header number in use for the wire stream. + * + * @return header number or zero when unset + */ long headerNumber(); + /** + * Enable or disable insertion of padding bytes between documents. + * + * @param usePadding true to align documents with padding + */ void usePadding(boolean usePadding); + /** + * Whether the wire currently uses padding to align documents. + * + * @return true if padding is enabled + */ boolean usePadding(); /** @@ -154,6 +190,7 @@ default void notCompleteIsNotPresent(boolean notCompleteArePresent) { * @return a new {@link BooleanValue}. */ @NotNull + @Deprecated(/* to be removed in 2027 */) BooleanValue newBooleanReference(); /** diff --git a/src/main/java/net/openhft/chronicle/wire/WireIn.java b/src/main/java/net/openhft/chronicle/wire/WireIn.java index baca30f77e..6120087968 100644 --- a/src/main/java/net/openhft/chronicle/wire/WireIn.java +++ b/src/main/java/net/openhft/chronicle/wire/WireIn.java @@ -159,6 +159,7 @@ default ValueIn readEventName(@NotNull StringBuilder name) { * @return the WireIn instance for method chaining. */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) WireIn readComment(@NotNull StringBuilder sb); /** @@ -207,6 +208,7 @@ default boolean isEmpty() { * @return the WireIn instance for method chaining. */ @NotNull + @Deprecated(/* to be removed in 2027 */) default WireIn readAlignTo(int alignment) { return this; } @@ -235,6 +237,7 @@ default boolean readDocument(@Nullable ReadMarshallable metaDataConsumer, * @return true if the document was successfully read from the given position, otherwise false. * @throws InvalidMarshallableException if there's an error during marshalling. */ + @Deprecated(/* to be removed in 2027 */) default boolean readDocument(long position, @Nullable ReadMarshallable metaDataConsumer, @Nullable ReadMarshallable dataConsumer) throws InvalidMarshallableException { @@ -247,6 +250,7 @@ default boolean readDocument(long position, * @param marshallable Data to be read in its raw form. * @throws InvalidMarshallableException if there's an error during marshalling. */ + @Deprecated(/* to be removed in 2027 */) default void rawReadData(@NotNull ReadMarshallable marshallable) throws InvalidMarshallableException { WireInternal.rawReadData(this, marshallable); } @@ -297,7 +301,6 @@ default boolean readDataHeader() throws EOFException { * * @param includeMetaData If true, metadata headers are included in the read attempt. * @return The type of header that was read. - * @throws EOFException if an end-of-file marker is encountered. */ @NotNull HeaderType readDataHeader(boolean includeMetaData) throws EOFException; diff --git a/src/main/java/net/openhft/chronicle/wire/WireInternal.java b/src/main/java/net/openhft/chronicle/wire/WireInternal.java index 6d59ef3055..15adefa033 100644 --- a/src/main/java/net/openhft/chronicle/wire/WireInternal.java +++ b/src/main/java/net/openhft/chronicle/wire/WireInternal.java @@ -34,7 +34,7 @@ * direct instances (as signified by the empty enum declaration). Instead, it serves as * a container for static members. */ -@SuppressWarnings({"rawtypes", "unchecked"}) +@SuppressWarnings({"rawtypes", "unchecked", "deprecation"}) public enum WireInternal { ; // none static final StringInterner INTERNER = new StringInterner(Jvm.getInteger("wire.interner.size", 4096)); @@ -42,10 +42,6 @@ public enum WireInternal { private static final int BYTES_SCOPED_INSTANCES_PER_THREAD = Jvm.getInteger("chronicle.wireInternal.pool.bytes.instancesPerThread", 2); // Thread-local storage for various utility instances. - static final ThreadLocal>> BYTES_TL = new ThreadLocal<>(); - static final ThreadLocal>> BYTES_F2S_TL = new ThreadLocal<>(); - static final ThreadLocal> BINARY_WIRE_TL = new ThreadLocal<>(); - static final ThreadLocal>> INTERNAL_BYTES_TL = new ThreadLocal<>(); static final ScopedThreadLocal BINARY_WIRE_SCOPED_TL = new ScopedThreadLocal<>( () -> new BinaryWire(Wires.unmonitoredDirectBytes()) .setOverrideSelfDescribing(true), @@ -399,8 +395,7 @@ protected static Throwable throwable(@NotNull ValueIn valueIn, boolean appendCur int first = 6; int last = Jvm.trimLast(first, stes2); // Loop to add each stack trace element from current thread's stack - for (int i = first; i <= last; i++) - stes.add(stes2[i]); + stes.addAll(Arrays.asList(stes2).subList(first, last + 1)); } // Set the final stack trace to the throwable @@ -412,19 +407,6 @@ protected static Throwable throwable(@NotNull ValueIn valueIn, boolean appendCur return throwable; } - /** - * Merges two strings with a space in between. If one of the strings is null, - * the other string is returned. If both are null, null is returned. - * - * @param a The first string. - * @param b The second string. - * @return The merged string or one of the strings if the other is null. - */ - @Nullable - static String merge(@Nullable String a, @Nullable String b) { - return a == null ? b : b == null ? a : a + " " + b; - } - /** * Attempts to intern an object if it's of a type that is internable * and is actually a string. Otherwise, converts the object to the given class. diff --git a/src/main/java/net/openhft/chronicle/wire/WireKey.java b/src/main/java/net/openhft/chronicle/wire/WireKey.java index b8326527cf..3a2a726627 100644 --- a/src/main/java/net/openhft/chronicle/wire/WireKey.java +++ b/src/main/java/net/openhft/chronicle/wire/WireKey.java @@ -26,6 +26,7 @@ public interface WireKey { * @return {@code true} if all codes are unique. * @throws AssertionError if two or more keys share the same code. */ + @Deprecated(/* to be removed in 2027 */) static boolean checkKeys(@NotNull WireKey[] keys) { @NotNull Map codes = new HashMap<>(); for (@NotNull WireKey key : keys) { @@ -45,7 +46,7 @@ static boolean checkKeys(@NotNull WireKey[] keys) { */ static int toCode(@NotNull CharSequence cs) { @NotNull String s = cs.toString(); - if (s.length() > 0 && Character.isDigit(s.charAt(0))) + if (!s.isEmpty() && Character.isDigit(s.charAt(0))) try { return Integer.parseInt(s); } catch (NumberFormatException faillback) { @@ -79,6 +80,7 @@ default int code() { * * @return the associated type. */ + @Deprecated(/* to be removed in 2027 */) default Type type() { @Nullable Object o = defaultValue(); return o == null ? Void.class : o.getClass(); diff --git a/src/main/java/net/openhft/chronicle/wire/WireMarshaller.java b/src/main/java/net/openhft/chronicle/wire/WireMarshaller.java index 71e1420ff0..f98a4259ad 100644 --- a/src/main/java/net/openhft/chronicle/wire/WireMarshaller.java +++ b/src/main/java/net/openhft/chronicle/wire/WireMarshaller.java @@ -64,6 +64,7 @@ public class WireMarshaller { try { isRecord = Jvm.getMethod(Class.class, "isRecord"); } catch (Exception ignored) { + isRecord = null; } } } @@ -86,8 +87,8 @@ protected WireMarshaller(@NotNull Class tClass, @NotNull FieldAccess[] fields * types receive a specialised marshaller that handles their field discovery * slightly differently, while all other classes use the generic variant. */ - public static final ClassLocal WIRE_MARSHALLER_CL = ClassLocal.withInitial - (tClass -> + public static final ClassLocal WIRE_MARSHALLER_CL = ClassLocal.withInitial( + tClass -> Throwable.class.isAssignableFrom(tClass) ? WireMarshaller.ofThrowable(tClass) : WireMarshaller.of(tClass) @@ -220,14 +221,13 @@ public static void getAllField(@NotNull Class clazz, @NotNull Map prevTypeParam * @param fieldNames Names of the fields to be excluded. * @return A new instance of the {@link WireMarshaller} with the specified fields excluded. */ + @Deprecated(/* to be removed in 2027 */) public WireMarshaller excludeFields(String... fieldNames) { Set fieldSet = new HashSet<>(Arrays.asList(fieldNames)); return new WireMarshaller<>(Stream.of(fields) @@ -427,6 +428,7 @@ public void writeMarshallable(T t, @NotNull WireOut out) throws InvalidMarshalla * @param t The object to write. * @param bytes The destination {@link Bytes} where the object representation will be written. */ + @Deprecated(/* to be removed in 2027 */) public void writeMarshallable(T t, Bytes bytes) { for (@NotNull FieldAccess field : fields) { try { @@ -904,7 +906,7 @@ abstract static class FieldAccess { final WireKey key; Comment commentAnnotation; - Boolean isLeaf; + final Boolean isLeaf; /** * Constructor initializing field with given value. @@ -930,7 +932,7 @@ abstract static class FieldAccess { try { commentAnnotation = Jvm.findAnnotation(field, Comment.class); } catch (NullPointerException ignore) { - + commentAnnotation = null; } } @@ -1489,7 +1491,7 @@ public void getAsBytes(Object o, @NotNull Bytes bytes) { * and to various sources, using unsafe operations for performance optimization. */ static class StringBuilderFieldAccess extends FieldAccess { - private StringBuilder defaultValue; + private final StringBuilder defaultValue; public StringBuilderFieldAccess(@NotNull Field field, @Nullable Object defaultObject) throws IllegalAccessException { super(field, true); @@ -2013,7 +2015,6 @@ static FieldAccess of(@NotNull Field field) { @Nullable final Supplier collectionSupplier; @NotNull final Class componentType; final Class type; - @Nullable Boolean isLeaf = null; type = field.getType(); if (type == List.class || type == Collection.class) collectionSupplier = ArrayList::new; @@ -2025,6 +2026,7 @@ else if (type == Set.class) collectionSupplier = null; componentType = extractClass(computeActualTypeArguments(Collection.class, field)[0]); + @Nullable Boolean isLeaf = null; if (componentType != Object.class) { isLeaf = !Throwable.class.isAssignableFrom(componentType) // Don't recurse into the same class @@ -2495,7 +2497,7 @@ protected void getValue(Object o, @NotNull ValueOut write, Object previous) { @Override protected void setValue(Object o, @NotNull ValueIn read, boolean overwrite) { String text = read.text(); - if (text == null || text.length() < 1) { + if (text == null || text.isEmpty()) { if (overwrite) text = INVALID_CHAR_STR; else @@ -2562,54 +2564,6 @@ protected void copy(Object from, Object to) { } } - /** - * The ByteIntConversionFieldAccess class extends IntConversionFieldAccess to provide specialized access - * and conversion between fields that are of type byte and their representation as int. - *

    - * This extension leverages unsafe operations to get and set the byte value directly from or to an object - * while converting to or from an int respectively. This helps in preserving the value of the byte as an - * unsigned integer representation. - */ - static class ByteIntConversionFieldAccess extends IntConversionFieldAccess { - public ByteIntConversionFieldAccess(@NotNull Field field, @NotNull LongConversion conversion) { - super(field, conversion); - } - - @Override - protected int getInt(Object o) { - return unsafeGetByte(o, offset) & 0xFF; - } - - @Override - protected void putInt(Object o, int i) { - unsafePutByte(o, offset, (byte) i); - } - } - - /** - * The ShortIntConversionFieldAccess class extends IntConversionFieldAccess to provide specialized access - * and conversion between fields that are of type short and their representation as int. - *

    - * This extension leverages unsafe operations to get and set the short value directly from or to an object - * while converting to or from an int respectively. This helps in preserving the value of the short as an - * unsigned integer representation. - */ - static class ShortIntConversionFieldAccess extends IntConversionFieldAccess { - public ShortIntConversionFieldAccess(@NotNull Field field, @NotNull LongConversion conversion) { - super(field, conversion); - } - - @Override - protected int getInt(Object o) { - return unsafeGetShort(o, offset) & 0xFFFF; - } - - @Override - protected void putInt(Object o, int i) { - unsafePutShort(o, offset, (short) i); - } - } - /** * A field access that provides a way to interact with a byte field as if it's a long, * by using a {@link LongConverter} for any necessary transformations. @@ -2810,89 +2764,6 @@ protected void setLong(Object o, long i) { } } - static class IntConversionFieldAccess extends FieldAccess { - @NotNull - private final LongConverter converter; - - IntConversionFieldAccess(@NotNull Field field, @NotNull LongConversion conversion) { - super(field); - this.converter = (LongConverter) ObjectUtils.newInstance(conversion.value()); - } - - @Override - protected void getValue(Object o, @NotNull ValueOut write, @Nullable Object previous) { - int anInt = getInt(o); - if (write.isBinary()) { - write.int32(anInt); - } else { - try (ScopedResource stlSb = Wires.acquireStringBuilderScoped()) { - StringBuilder sb = stlSb.get(); - converter.append(sb, anInt); - if (!write.isBinary() && sb.length() == 0) - write.text(""); - else - write.rawText(sb); - } - } - } - - /** - * A helper method to retrieve the integer from the object using the provided offset. - * - * @param o The object containing the field - * @return The retrieved integer value - */ - protected int getInt(Object o) { - return unsafeGetInt(o, offset); - } - - @Override - protected void setValue(Object o, @NotNull ValueIn read, boolean overwrite) { - long i; - if (read.isBinary()) { - i = read.int64(); - - } else { - try (ScopedResource stlSb = Wires.acquireStringBuilderScoped()) { - StringBuilder sb = stlSb.get(); - read.text(sb); - i = converter.parse(sb); - } - } - unsafePutLong(o, offset, i); - } - - /** - * A helper method to set the integer value on the object using the provided offset. - * - * @param o The object to set the value on - * @param i The integer value to set - */ - protected void putInt(Object o, int i) { - unsafePutInt(o, offset, i); - } - - @Override - public void getAsBytes(Object o, @NotNull Bytes bytes) { - try (ScopedResource stlSb = Wires.acquireStringBuilderScoped()) { - StringBuilder sb = stlSb.get(); - bytes.readUtf8(sb); - long i = converter.parse(sb); - bytes.writeLong(i); - } - } - - @Override - protected boolean sameValue(Object o, Object o2) { - return getInt(o) == getInt(o2); - } - - @Override - protected void copy(Object from, Object to) { - putInt(to, getInt(from)); - } - } - /** * The FloatFieldAccess class extends the FieldAccess class, providing specialized access * to float fields of an object. This class supports reading and writing float values, diff --git a/src/main/java/net/openhft/chronicle/wire/WireObjectInput.java b/src/main/java/net/openhft/chronicle/wire/WireObjectInput.java index 5a54cc9d60..3fdb565276 100644 --- a/src/main/java/net/openhft/chronicle/wire/WireObjectInput.java +++ b/src/main/java/net/openhft/chronicle/wire/WireObjectInput.java @@ -30,12 +30,12 @@ class WireObjectInput implements ObjectInput { */ @Nullable @Override - public Object readObject() throws ClassNotFoundException, IOException { + public Object readObject() { return wire.getValueIn().object(); } @Override - public int read() throws IOException { + public int read() { if (wire.bytes().readRemaining() <= 0) return -1; return wire.getValueIn().int8() & 0xFF; @@ -68,7 +68,7 @@ public int read(@NotNull byte[] b, int off, int len) throws IOException { * Skips up to {@code n} bytes and may rewind if negative. */ @Override - public long skip(long n) throws IOException { + public long skip(long n) { @NotNull final Bytes bytes = wire.bytes(); final long maxRewind = bytes.start() - bytes.readPosition(); long len = Math.max(maxRewind, Math.min(bytes.readRemaining(), n)); @@ -80,13 +80,13 @@ public long skip(long n) throws IOException { * Estimate of readable bytes. */ @Override - public int available() throws IOException { + public int available() { return (int) Math.min(Integer.MAX_VALUE, wire.bytes().readRemaining()); } /** No-op: lifecycle managed externally. */ @Override - public void close() throws IOException { + public void close() { } /** Fills the array or throws {@link EOFException}. */ @@ -97,13 +97,13 @@ public void readFully(byte[] b) throws IOException { /** Unsupported. */ @Override - public void readFully(byte[] b, int off, int len) throws IOException { + public void readFully(byte[] b, int off, int len) { throw new UnsupportedOperationException("TODO"); } /** Unsupported. */ @Override - public int skipBytes(int n) throws IOException { + public int skipBytes(int n) { throw new UnsupportedOperationException(); } diff --git a/src/main/java/net/openhft/chronicle/wire/WireObjectOutput.java b/src/main/java/net/openhft/chronicle/wire/WireObjectOutput.java index de601949be..d3613a1dd1 100644 --- a/src/main/java/net/openhft/chronicle/wire/WireObjectOutput.java +++ b/src/main/java/net/openhft/chronicle/wire/WireObjectOutput.java @@ -39,7 +39,7 @@ else if (obj instanceof List) } /** - * Writes one unsigned byte via {@link ValueOut#uint8(long)}. + * Writes one unsigned byte via . */ @Override public void write(int b) { @@ -78,7 +78,7 @@ public void close() { } /** - * Writes a boolean via {@link ValueOut#bool(boolean)}. + * Writes a boolean via . */ @Override public void writeBoolean(boolean v) { diff --git a/src/main/java/net/openhft/chronicle/wire/WireOut.java b/src/main/java/net/openhft/chronicle/wire/WireOut.java index d57b5d1780..579a59f138 100644 --- a/src/main/java/net/openhft/chronicle/wire/WireOut.java +++ b/src/main/java/net/openhft/chronicle/wire/WireOut.java @@ -85,6 +85,7 @@ default ValueOut writeEventId(int methodId) { * @param methodId The ID of the method representing the event. * @return An interface to further define the output for the written value. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default ValueOut writeEventId(String name, int methodId) { return write(new MethodWireKey(name, methodId)); } diff --git a/src/main/java/net/openhft/chronicle/wire/WireParser.java b/src/main/java/net/openhft/chronicle/wire/WireParser.java index 58483f80f3..32743952a8 100644 --- a/src/main/java/net/openhft/chronicle/wire/WireParser.java +++ b/src/main/java/net/openhft/chronicle/wire/WireParser.java @@ -84,6 +84,7 @@ static void skipReadable(long ignoreMethodId, WireIn wire) { * * @return the default consumer for unmatched field names. */ + @Deprecated(/* to be removed in 2027 */) WireParselet getDefaultConsumer(); /** diff --git a/src/main/java/net/openhft/chronicle/wire/WireToOutputStream.java b/src/main/java/net/openhft/chronicle/wire/WireToOutputStream.java index 91e75b067b..756120047b 100644 --- a/src/main/java/net/openhft/chronicle/wire/WireToOutputStream.java +++ b/src/main/java/net/openhft/chronicle/wire/WireToOutputStream.java @@ -19,6 +19,7 @@ * before flushing it to the actual OutputStream. The provided {@link OutputStream} is not * closed by this class */ +@Deprecated(/* to be removed in 2027, as it is only used in tests */) public class WireToOutputStream { // Internal, elastically-sized heap {@link Bytes} buffer that backs the {@link #wire}. Data is serialised into this buffer before being flushed diff --git a/src/main/java/net/openhft/chronicle/wire/WireType.java b/src/main/java/net/openhft/chronicle/wire/WireType.java index 120b3c3afe..ba127cb5c2 100644 --- a/src/main/java/net/openhft/chronicle/wire/WireType.java +++ b/src/main/java/net/openhft/chronicle/wire/WireType.java @@ -19,9 +19,9 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.Serializable; -import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.net.URL; +import java.nio.file.Files; import java.util.Collection; import java.util.Map; import java.util.Spliterator; @@ -52,13 +52,13 @@ public enum WireType implements Function, Wire>, LicenceCheck { * Uses binary documents and padding by default. */ TEXT { - private final boolean TEXT_AS_YAML = Jvm.getBoolean("wire.testAsYaml"); + private final boolean textAsYaml = Jvm.getBoolean("wire.testAsYaml"); @SuppressWarnings("deprecation") @NotNull @Override public Wire apply(@NotNull Bytes bytes) { - if (TEXT_AS_YAML) + if (textAsYaml) return YAML.apply(bytes); final TextWire wire = new TextWire(bytes).useBinaryDocuments(); wire.usePadding(true); @@ -83,7 +83,7 @@ public T fromString(Class tClass, @NotNull CharSequence cs) throws Invali bytes.appendUtf8(cs); @NotNull Wire wire = apply(bytes); wire.consumePadding(); - if (!TEXT_AS_YAML) + if (!textAsYaml) ((TextWire) wire).consumeDocumentStart(); return wire.getValueIn().object(tClass); } finally { @@ -384,6 +384,7 @@ public static WireType valueOf(@Nullable Wire wire) { * * @return A supplier that creates a new BinaryIntReference. */ + @Deprecated(/* to be removed in 2027 */) public Supplier newIntReference() { return BinaryIntReference::new; } @@ -393,6 +394,7 @@ public Supplier newIntReference() { * * @return A supplier that creates a new BinaryBooleanReference. */ + @Deprecated(/* to be removed in 2027 */) public Supplier newBooleanReference() { return BinaryBooleanReference::new; } @@ -449,7 +451,6 @@ public String asString(Object marshallable) { * objects to a byte buffer, e.g., WriteMarshallable, Map, Iterable, etc. * * @param marshallable The object to be converted to bytes. - * @return A Bytes buffer containing the serialized form of the object. * @throws InvalidMarshallableException If the object cannot be serialized properly. */ @NotNull @@ -481,6 +482,7 @@ else if (marshallable instanceof Serializable) * @throws ClassCastException if the object is not of type {@code T} */ @Nullable + @Deprecated(/* to be removed in 2027 */) public T fromString(@NotNull CharSequence cs) throws InvalidMarshallableException { return (T) fromString(/* Allow Marshallable tuples by not requesting Object */ null, cs); } @@ -570,7 +572,7 @@ public T fromFile(@NotNull Class expectedType, String filename) throws IO } //: MappedFile.readOnly(file).acquireBytesForRead(0); - Bytes bytes = Bytes.wrapForRead(readAsBytes(url == null ? new FileInputStream(file) : open(url))); + Bytes bytes = Bytes.wrapForRead(readAsBytes(url == null ? Files.newInputStream(file.toPath()) : open(url))); if (bytes.readRemaining() == 0) throw new IOException("File " + file + " was empty"); try { @@ -657,6 +659,7 @@ public boolean tryAdvance(@NotNull Consumer action) { * @throws IOException if the file cannot be written * @throws InvalidMarshallableException if encoding fails */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public void toFile(@NotNull String filename, WriteMarshallable marshallable) throws IOException, InvalidMarshallableException { String tempFilename = tempName(filename); try (ScopedResource> stlBytes = Wires.acquireBytesScoped()) { @@ -667,7 +670,9 @@ public void toFile(@NotNull String filename, WriteMarshallable marshallable) thr } @NotNull File file2 = new File(tempFilename); if (!file2.renameTo(new File(filename))) { - file2.delete(); + if (!file2.delete()) { + Jvm.warn().on(WireType.class, "Failed to delete temporary file " + tempFilename); + } throw new IOException("Failed to rename " + tempFilename + " to " + filename); } } @@ -718,6 +723,7 @@ String asHexString(Object marshallable) { * @throws InvalidMarshallableException if parsing fails */ @Nullable + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public Map asMap(@NotNull CharSequence cs) throws InvalidMarshallableException { try (ScopedResource> stlBytes = Wires.acquireBytesScoped()) { Bytes bytes = stlBytes.get(); diff --git a/src/main/java/net/openhft/chronicle/wire/WireTypeConverter.java b/src/main/java/net/openhft/chronicle/wire/WireTypeConverter.java index c543817c29..97384ae3e2 100644 --- a/src/main/java/net/openhft/chronicle/wire/WireTypeConverter.java +++ b/src/main/java/net/openhft/chronicle/wire/WireTypeConverter.java @@ -50,6 +50,7 @@ public CharSequence yamlToJson(CharSequence yaml) { * @param newClass the target {@link Class} object * @param oldTypeName the alternative or old type name string that should map to {@code newClass} */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public void addAlias(Class newClass, String oldTypeName) { delegate.addAlias(newClass, oldTypeName); } diff --git a/src/main/java/net/openhft/chronicle/wire/Wires.java b/src/main/java/net/openhft/chronicle/wire/Wires.java index f8f19ae8fe..99784712e6 100644 --- a/src/main/java/net/openhft/chronicle/wire/Wires.java +++ b/src/main/java/net/openhft/chronicle/wire/Wires.java @@ -7,7 +7,6 @@ import net.openhft.chronicle.core.Jvm; import net.openhft.chronicle.core.Maths; import net.openhft.chronicle.core.OS; -import net.openhft.chronicle.core.annotation.ForceInline; import net.openhft.chronicle.core.io.Closeable; import net.openhft.chronicle.core.io.*; import net.openhft.chronicle.core.pool.ClassAliasPool; @@ -55,7 +54,7 @@ * {@link StringBuilder} pools and {@link net.openhft.compiler.CachedCompiler} * instances. */ -@SuppressWarnings({"rawtypes", "unchecked"}) +@SuppressWarnings({"rawtypes", "unchecked", "deprecation"}) public enum Wires { ; // No specific enumeration values @@ -170,16 +169,22 @@ public enum Wires { // Used to ensure an untyped bytes warning is logged only once static volatile boolean warnedUntypedBytesOnce = false; + static boolean markUntypedBytesWarning() { + if (warnedUntypedBytesOnce) + return false; + warnedUntypedBytesOnce = true; + return true; + } + // Legacy thread-local {@link StringBuilder}. Prefer {@link #STRING_BUILDER_SCOPED_RESOURCE_POOL} - static ThreadLocal sb = ThreadLocal.withInitial(StringBuilder::new); + static final ThreadLocal sb = ThreadLocal.withInitial(StringBuilder::new); // Shared {@link net.openhft.compiler.CachedCompiler} for dynamic class generation static CachedCompiler CACHED_COMPILER = null; - /** - * Static initializer block for the Wires enum. It populates the list of - * class strategy functions and adds some default strategies for serialization. - * It also sets up wire aliases. + /* + * Static initializer block. It populates the list of class strategy functions and adds some + * default strategies for serialization. It also sets up wire aliases. */ static { Jvm.addToClassPath(Wires.class); @@ -208,6 +213,7 @@ public static void init() { * @param the type of the specified interface * @return a proxy of the specified interface that writes to the PrintStream in Yaml */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static T recordAsYaml(Class tClass, PrintStream ps) { MarshallableOut out = new StringConsumerMarshallableOut(s -> { if (!s.startsWith("---\n")) @@ -229,11 +235,14 @@ public static T recordAsYaml(Class tClass, PrintStream ps) { * @throws IOException is thrown if there's an error reading the file * @throws InvalidMarshallableException is thrown if the serialized data is invalid or corrupted */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static void replay(String file, Object obj) throws IOException, InvalidMarshallableException { Bytes bytes = BytesUtil.readFile(file); Wire wire = new YamlWire(bytes).useTextDocuments(); MethodReader readerObj = wire.methodReader(obj); while (readerObj.readOne()) { + // Intentionally empty; loop drains the reader. + continue; } bytes.releaseLast(); } @@ -269,6 +278,7 @@ public static String fromAlignedSizePrefixedBlobs(@NotNull Bytes bytes) { * @param abbrev if {@code true} long fields are abbreviated * @return textual dump of the blobs */ + @Deprecated(/* to be removed in 2027 */) public static String fromSizePrefixedBlobs(@NotNull Bytes bytes, boolean abbrev) { return WireDumper.of(bytes).asString(abbrev); } @@ -307,6 +317,7 @@ public static String fromSizePrefixedBlobs(@NotNull Bytes bytes, long positio * @param abbrev whether long content should be abbreviated * @return textual dump of the blobs */ + @Deprecated(/* to be removed in 2027 */) public static String fromSizePrefixedBlobs(@NotNull Bytes bytes, boolean padding, boolean abbrev) { return WireDumper.of(bytes, padding).asString(abbrev); } @@ -411,6 +422,7 @@ public static String fromSizePrefixedBlobs(@NotNull WireIn wireIn, boolean abbre * @return {@code output} containing the textual form */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static CharSequence asText(@NotNull WireIn wireIn, Bytes output) { ValidatableUtil.startValidateDisabled(); try { @@ -433,6 +445,7 @@ private static Wire newJsonWire(Bytes bytes) { /** * Copies the contents of {@code wireIn} into {@code output} using a binary wire. */ + @Deprecated(/* to be removed in 2027 */) public static Bytes asBinary(@NotNull WireIn wireIn, Bytes output) throws InvalidMarshallableException { return asType(wireIn, BinaryWire::new, output); } @@ -458,6 +471,7 @@ private static Bytes asType(@NotNull WireIn wireIn, Function wir /** * Converts {@code wireIn} to JSON and writes the result into {@code output}. */ + @Deprecated(/* to be removed in 2027 */) public static Bytes asJson(@NotNull WireIn wireIn, Bytes output) throws InvalidMarshallableException { return asType(wireIn, Wires::newJsonWire, output); } @@ -526,6 +540,7 @@ public static boolean isReadyMetaData(int len) { /** * Returns {@code true} if the header has a definite length value. */ + @Deprecated(/* to be removed in 2027 */) public static boolean isKnownLength(int len) { return (len & (META_DATA | LENGTH_MASK)) != UNKNOWN_LENGTH; } @@ -533,6 +548,7 @@ public static boolean isKnownLength(int len) { /** * Returns {@code true} if the header has not been initialised. */ + @Deprecated(/* to be removed in 2027 */) public static boolean isNotInitialized(int len) { return len == NOT_INITIALIZED; } @@ -559,6 +575,7 @@ public static int toIntU30(long l, @NotNull String error) { * @param position offset of the header * @return {@code true} if the lock was acquired */ + @Deprecated(/* to be removed in 2027 */) public static boolean acquireLock(@NotNull BytesStore store, long position) { return store.compareAndSwapInt(position, NOT_INITIALIZED, NOT_COMPLETE); } @@ -569,6 +586,7 @@ public static boolean acquireLock(@NotNull BytesStore store, long position * @param length the length to check * @return true if the length exceeds the maximum, false otherwise */ + @Deprecated(/* to be removed in 2027 */) public static boolean exceedsMaxLength(long length) { return length > LENGTH_MASK; } @@ -582,7 +600,7 @@ public static boolean exceedsMaxLength(long length) { * @return the position after writing the data * @throws InvalidMarshallableException if marshalling fails */ - @ForceInline + @Deprecated(/* to be removed in 2027 */) public static long writeData( @NotNull WireOut wireOut, @NotNull T writer) throws InvalidMarshallableException { @@ -598,7 +616,7 @@ public static long writeData( * @return the position in the bytes after reading * @throws InvalidMarshallableException if there's an issue during marshalling */ - @ForceInline + @Deprecated(/* to be removed in 2027 */) public static long readWire(@NotNull WireIn wireIn, long size, @NotNull ReadMarshallable readMarshallable) throws InvalidMarshallableException { @NotNull final Bytes bytes = wireIn.bytes(); final long limit0 = bytes.readLimit(); @@ -719,6 +737,7 @@ public static void writeMarshallable(@NotNull Object marshallable, @NotNull Wire * @param copy indicates if the previous state should be copied * @throws InvalidMarshallableException if there's an error during the marshalling process */ + @Deprecated(/* to be removed in 2027 */) public static void writeMarshallable(@NotNull Object marshallable, @NotNull WireOut wire, @NotNull Object previous, boolean copy) throws InvalidMarshallableException { assert marshallable.getClass() == previous.getClass(); WireMarshaller wm = WireMarshaller.WIRE_MARSHALLER_CL.get(marshallable.getClass()); @@ -842,6 +861,7 @@ public static List fieldInfos(@NotNull Class aClass) { * @param name Field name * @return Information about the field */ + @Deprecated(/* to be removed in 2027 */) public static FieldInfo fieldInfo(@NotNull Class aClass, String name) { return FIELD_INFOS.get(aClass).map.get(name); } @@ -926,6 +946,7 @@ public static void reset(@NotNull Object o) { * @param header The header with a potentially masked thread ID * @return The header without the masked thread ID */ + @Deprecated(/* to be removed in 2027 */) public static int removeMaskedTidFromHeader(final int header) { return header & INVERSE_TID_MASK; } @@ -1029,6 +1050,7 @@ private static String nameOf(E e) { * @return A Date object representing the read date */ @NotNull + @Deprecated(/* to be removed in 2027 */) public static E objectDate(ValueIn in, @Nullable E using) { // skip the field if it is there. in.wireIn().read(); @@ -1036,9 +1058,10 @@ public static E objectDate(ValueIn in, @Nullable E using) { if (using instanceof Date) { ((Date) using).setTime(time); return using; - } else + } else { return (E) new Date(time); } + } /** * Reads and validates an object from the given input. @@ -1415,7 +1438,10 @@ enum SerializeJavaLang implements Function, SerializationStrategy> { * @return A WireOut object, which represents the state after the write operation. */ public static WireOut writeDate(Date date, ValueOut out) { - final String format = SDF_2.format(date); + final String format; + synchronized (SDF_2) { + format = SDF_2.format(date); + } return out.writeString(format); } @@ -1430,7 +1456,7 @@ public static Date parseDate(ValueIn in) { final String text = in.text().trim(); // Check if the input string is empty. - if (text.length() < 1) { + if (text.isEmpty()) { throw new IORuntimeException("At least one character (e.g. '0') must be present in order to deserialize a Date object"); } final char firstChar = text.charAt(0); @@ -1502,6 +1528,7 @@ public static Date parseDate(ValueIn in) { * @param in The ValueIn object which contains the class name. * @return The Class object associated with the name. */ + @Deprecated(/* to be removed in 2027 */) private static Class forName(Class o, ValueIn in) { final StringBuilder sb0 = sb.get(); @@ -1554,7 +1581,7 @@ public SerializationStrategy apply(@NotNull Class aClass) { case "java.lang.Character": return ScalarStrategy.of(Character.class, (o, in) -> { @Nullable final String text = in.text(); - if (text == null || text.length() == 0) + if (text == null || text.isEmpty()) return null; return text.charAt(0); }); @@ -1885,6 +1912,8 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Exceptio break; case "usesSelfDescribingMessage": return Boolean.TRUE; + default: + break; } if (args == null || args.length == 0) { Class returnType = method.getReturnType(); diff --git a/src/main/java/net/openhft/chronicle/wire/WordsLongConverter.java b/src/main/java/net/openhft/chronicle/wire/WordsLongConverter.java index 066e691724..9867048b3f 100644 --- a/src/main/java/net/openhft/chronicle/wire/WordsLongConverter.java +++ b/src/main/java/net/openhft/chronicle/wire/WordsLongConverter.java @@ -7,12 +7,13 @@ import net.openhft.chronicle.core.io.IOTools; import java.io.IOException; -import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.regex.Pattern; -import java.util.ArrayList; -import java.util.List; + +import static java.nio.charset.StandardCharsets.ISO_8859_1; /** * The {@code WordsLongConverter} class implements the LongConverter interface. @@ -37,7 +38,7 @@ public class WordsLongConverter implements LongConverter { static { try { // Load the words from the resource file, ignoring comment lines. - String content = new String(IOTools.readFile(WordsLongConverter.class, "common-words.txt"), StandardCharsets.ISO_8859_1); + String content = new String(IOTools.readFile(WordsLongConverter.class, "common-words.txt"), ISO_8859_1); String[] lines = content.split("\\R"); List list = new ArrayList<>(); for (String line : lines) { diff --git a/src/main/java/net/openhft/chronicle/wire/WrappedDocumentContext.java b/src/main/java/net/openhft/chronicle/wire/WrappedDocumentContext.java index 010091d1a0..5307e0203e 100644 --- a/src/main/java/net/openhft/chronicle/wire/WrappedDocumentContext.java +++ b/src/main/java/net/openhft/chronicle/wire/WrappedDocumentContext.java @@ -11,6 +11,7 @@ * The purpose of this class is to wrap another DocumentContext and delegate the behavior to the wrapped instance. * This can be used as a base for any specialized versions of DocumentContext which need to extend the default behavior. */ +@Deprecated(/* to be removed in 2027, as it is only used in tests */) public abstract class WrappedDocumentContext implements DocumentContext { // The wrapped instance of DocumentContext. diff --git a/src/main/java/net/openhft/chronicle/wire/YamlLogging.java b/src/main/java/net/openhft/chronicle/wire/YamlLogging.java index 56d1599d63..fe9caba858 100644 --- a/src/main/java/net/openhft/chronicle/wire/YamlLogging.java +++ b/src/main/java/net/openhft/chronicle/wire/YamlLogging.java @@ -17,7 +17,8 @@ public enum YamlLogging { // The title for logging (can be changed during runtime). @NotNull - public static volatile String title = ""; + @Deprecated(/* to be removed in 2027 */) + public static String title = ""; // Flag indicating whether server writes should be shown. // TODO Doesn't show all writes. Use clientReads instead. @@ -53,6 +54,7 @@ public static void setAll(boolean flag) { * * @param level The {@link YamlLoggingLevel} determining whether to set or unset the logging flags. */ + @Deprecated(/* to be removed in 2027 */) public static void setAll(@NotNull YamlLoggingLevel level) { showServerReads = showServerWrites = clientWrites = clientReads = level.isSet(); } @@ -71,6 +73,7 @@ public static boolean showClientReads() { * * @param message The new message to be set. */ + @Deprecated(/* to be removed in 2027 */) public static void writeMessage(@NotNull String message) { writeMessage = message; } @@ -80,6 +83,7 @@ public static void writeMessage(@NotNull String message) { * * @param flag {@code true} to enable logging for server writes; {@code false} to disable. */ + @Deprecated(/* to be removed in 2027 */) public static void showServerWrites(boolean flag) { showServerWrites = flag; } @@ -89,6 +93,7 @@ public static void showServerWrites(boolean flag) { * * @return {@code true} if logging for client writes is enabled; {@code false} otherwise. */ + @Deprecated(/* to be removed in 2027 */) public static boolean showClientWrites() { return clientWrites; } @@ -99,6 +104,7 @@ public static boolean showClientWrites() { * @return The message currently associated with a write operation. */ @NotNull + @Deprecated(/* to be removed in 2027 */) public static String writeMessage() { return writeMessage; } @@ -108,6 +114,7 @@ public static String writeMessage() { * * @return {@code true} if heartbeat logging is enabled; {@code false} otherwise. */ + @Deprecated(/* to be removed in 2027 */) public static boolean showHeartBeats() { return showHeartBeats; } @@ -126,6 +133,7 @@ public static boolean showServerReads() { * * @param flag {@code true} to enable heartbeat logging; {@code false} to disable. */ + @Deprecated(/* to be removed in 2027 */) public static void showHeartBeats(boolean flag) { showHeartBeats = flag; } @@ -135,6 +143,7 @@ public static void showHeartBeats(boolean flag) { * * @param flag {@code true} to enable logging for client writes; {@code false} to disable. */ + @Deprecated(/* to be removed in 2027 */) public static void showClientWrites(boolean flag) { clientWrites = flag; } @@ -144,6 +153,7 @@ public static void showClientWrites(boolean flag) { * * @param flag {@code true} to enable logging for client reads; {@code false} to disable. */ + @Deprecated(/* to be removed in 2027 */) public static void showClientReads(boolean flag) { clientReads = flag; } @@ -162,6 +172,7 @@ public static boolean showServerWrites() { * * @param flag {@code true} to enable logging for server reads; {@code false} to disable. */ + @Deprecated(/* to be removed in 2027 */) public static void showServerReads(boolean flag) { showServerReads = flag; } @@ -170,6 +181,7 @@ public static void showServerReads(boolean flag) { * Enum representing the various logging levels for Yaml. * The levels include OFF (no logging), DEBUG_ONLY (logs only when in debug mode), and ON (always logs). */ + @Deprecated(/* to be removed in 2027 */) public enum YamlLoggingLevel { OFF { @Override diff --git a/src/main/java/net/openhft/chronicle/wire/YamlTokeniser.java b/src/main/java/net/openhft/chronicle/wire/YamlTokeniser.java index 5e01c1515c..f17cb1dafb 100644 --- a/src/main/java/net/openhft/chronicle/wire/YamlTokeniser.java +++ b/src/main/java/net/openhft/chronicle/wire/YamlTokeniser.java @@ -74,9 +74,6 @@ public class YamlTokeniser { // Flag to indicate if a sequence entry has been encountered boolean hasSequenceEntry; - // Position marker for the last key in a key-value pair - long lastKeyPosition = -1; - // The last token that was processed private YamlToken last = YamlToken.STREAM_START; @@ -114,7 +111,6 @@ void reset() { flowDepth = Integer.MAX_VALUE; blockQuote = 0; hasSequenceEntry = false; - lastKeyPosition = -1; pushed.clear(); last = YamlToken.STREAM_START; pushContext0(YamlToken.STREAM_START, NO_INDENT); @@ -231,7 +227,6 @@ YamlToken next0(int minIndent) { case '"': if (wouldChangeContext(minIndent, indent2)) return dontRead(); - lastKeyPosition = in.readPosition() - 1; readDoublyQuoted(); if (isFieldEnd()) return indent(YamlToken.MAPPING_START, YamlToken.MAPPING_KEY, YamlToken.TEXT, indent2); @@ -239,7 +234,6 @@ YamlToken next0(int minIndent) { case '\'': if (wouldChangeContext(minIndent, indent2)) return dontRead(); - lastKeyPosition = in.readPosition() - 1; readSinglyQuoted(); if (isFieldEnd()) return indent(YamlToken.MAPPING_START, YamlToken.MAPPING_KEY, YamlToken.TEXT, indent2); @@ -249,7 +243,6 @@ YamlToken next0(int minIndent) { case '?': { if (wouldChangeContext(minIndent, indent2)) return dontRead(); - lastKeyPosition = in.readPosition() - 1; YamlToken indentB = indent(YamlToken.MAPPING_START, YamlToken.MAPPING_KEY, YamlToken.STREAM_START, indent2); contextPush(YamlToken.MAPPING_KEY, indent2); return indentB; @@ -647,7 +640,6 @@ private YamlToken readText(int currentIndentLevel) { // If we've reached the end of a field, determine if this is a key in a mapping. if (isFieldEnd()) { - lastKeyPosition = pos; if (topContext().token != YamlToken.MAPPING_KEY) return indent(YamlToken.MAPPING_START, YamlToken.MAPPING_KEY, YamlToken.TEXT, currentIndentLevel); } @@ -818,20 +810,6 @@ private void contextPop() { freeContexts.add(context0); } - /** - * Drops contexts until the stack reaches the supplied {@code contextSize}. - */ - void revertToContext(int contextSize) { - pushed.clear(); // Clear the pushed tokens. - // Remove contexts until reaching the desired context size. - while (contextSize() > contextSize) { - YTContext context0 = contexts.remove(contextSize() - 1); - if (flowDepth == contextSize()) - flowDepth = Integer.MAX_VALUE; // Reset the flow depth if required. - freeContexts.add(context0); // Store the removed context for future reuse. - } - } - /** * Pushes a new parsing context. * Inserts an implicit {@link YamlToken#DIRECTIVES_END} @@ -972,6 +950,7 @@ private void consumeWhitespace() { * * @return the position of the start of the current line. */ + @Deprecated(/* to be removed in 2027 */) public long lineStart() { return lineStart; } @@ -999,6 +978,7 @@ public long blockStart() { * * @return the position of the end of the current block. */ + @Deprecated(/* to be removed in 2027 */) public long blockEnd() { return blockEnd; } diff --git a/src/main/java/net/openhft/chronicle/wire/YamlWire.java b/src/main/java/net/openhft/chronicle/wire/YamlWire.java index 346877f8ea..fc629508c3 100644 --- a/src/main/java/net/openhft/chronicle/wire/YamlWire.java +++ b/src/main/java/net/openhft/chronicle/wire/YamlWire.java @@ -37,7 +37,7 @@ * The YamlWire class extends YamlWireOut and utilizes a custom tokenizer to convert YAML tokens into byte sequences. * It provides utility methods to read from and write to both byte buffers and files. */ -@SuppressWarnings({"rawtypes", "unchecked", "this-escape"}) +@SuppressWarnings({"rawtypes", "unchecked", "this-escape", "deprecation"}) public class YamlWire extends YamlWireOut { // YAML-specific tag constants for representing special constructs. @@ -57,7 +57,7 @@ public class YamlWire extends YamlWireOut { private final Map anchorValues = new HashMap<>(); // Provides default ValueIn when a field is missing - private DefaultValueIn defaultValueIn; + private final DefaultValueIn defaultValueIn; // Context for writing YAML documents private WriteDocumentContext writeContext; @@ -79,7 +79,7 @@ public YamlWire() { /** * Constructor that initializes the YamlWire with provided bytes and a flag indicating the use of 8-bit. * - * @param bytes Bytes from which YamlWire is initialized + * @param bytes Bytes from which YamlWire is initialized * @param use8bit A boolean flag to indicate the use of 8-bit */ public YamlWire(@NotNull Bytes bytes, boolean use8bit) { @@ -106,6 +106,7 @@ public YamlWire(@NotNull Bytes bytes) { * @throws IOException If there's an error in reading the file */ @NotNull + @Deprecated(/* to be removed in 2027 */) public static YamlWire fromFile(String name) throws IOException { return new YamlWire(BytesUtil.readFile(name), true); } @@ -117,6 +118,7 @@ public static YamlWire fromFile(String name) throws IOException { * @return A new YamlWire instance initialized from the given string */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static YamlWire from(@NotNull String text) { return new YamlWire(Bytes.from(text)); } @@ -128,6 +130,7 @@ public static YamlWire from(@NotNull String text) { * @return The string representation of the wire's content. * @throws InvalidMarshallableException If the given wire's content cannot be marshalled. */ + @Deprecated(/* to be removed in 2027 */) public static String asText(@NotNull Wire wire) throws InvalidMarshallableException { long pos = wire.bytes().readPosition(); @NotNull Wire tw = Wire.newYamlWireOnHeap(); @@ -141,11 +144,11 @@ public static String asText(@NotNull Wire wire) throws InvalidMarshallableExcept * This method adheres to the YAML 1.2 specification for escaped characters * (see YAML Spec 1.2.2). * - * @param targetBuffer The appendable containing characters to be unescaped. + * @param targetBuffer The appendable containing characters to be unescaped. * @param blockQuoteChar The block quote character that determines the escaping scheme (' or "). - * @param An appendable that also implements CharSequence interface. + * @param An appendable that also implements CharSequence interface. */ - private static void unescape(@NotNull ACS targetBuffer, char blockQuoteChar) { + private static void unescape(@NotNull S targetBuffer, char blockQuoteChar) { int end = 0; int length = targetBuffer.length(); boolean skip = false; @@ -257,10 +260,10 @@ static void removeUnderscore(@NotNull StringBuilder s) { * as a date/time, based on the YAML specification. If none of these interpretations is successful, * it returns the original string content. * - * @param blockQuoteChar The block quote character (either ' or ") that initiated the string in YAML. + * @param blockQuoteChar The block quote character (either ' or ") that initiated the string in YAML. * @param inputTextBuilder The StringBuilder containing the string to be interpreted. * @return An Object which might be a Long, Double, Date, Time or the original String itself - * depending on successful interpretation. + * depending on successful interpretation. */ @Nullable static Object readNumberOrTextFrom(char blockQuoteChar, final @Nullable StringBuilder inputTextBuilder) { @@ -318,7 +321,7 @@ static Object readNumberOrTextFrom(char blockQuoteChar, final @Nullable StringBu *

  • If the first character of the string is not a number, decimal point, or a sign.
  • * * - * @param blockQuoteChar The block quote character (either ' or ") that initiated the string in YAML. + * @param blockQuoteChar The block quote character (either ' or ") that initiated the string in YAML. * @param inputTextBuilder The StringBuilder containing the string to check. * @return True if the string should be left unparsed, otherwise false. */ @@ -336,7 +339,7 @@ private static boolean leaveUnparsed(char blockQuoteChar, @Nullable StringBuilde * date-times with timezone offsets (ZonedDateTime). * If none of these interpretations is successful, a DateTimeParseException is thrown. * - * @param s The original StringBuilder containing the string to be parsed. + * @param s The original StringBuilder containing the string to be parsed. * @param ss The string equivalent of the StringBuilder 's'. * @return A TemporalAccessor which could be a LocalTime, LocalDate or ZonedDateTime based on the format. * @throws DateTimeParseException If the string cannot be parsed into any known date or time format. @@ -513,8 +516,9 @@ public String toString() { } finally { bytes.readLimit(l); } - } else + } else { return bytes.toString(); + } } @Override @@ -772,18 +776,18 @@ public boolean isNotEmptyAfterPadding() { } @Override - @SuppressWarnings("fallthrough") public void consumePadding() { while (true) { switch (yt.current()) { case COMMENT: String text = yt.text(); commentListener.accept(text); - // fall through + yt.next(); + continue; case DIRECTIVE: case DIRECTIVES_END: yt.next(); - break; + continue; default: return; } @@ -833,6 +837,7 @@ public ValueIn read(String keyName) { } // Next lines not covered by any tests } + YamlTokeniser.YTContext yc = yt.topContext(); int minIndent = yc.indent; // go through remaining keys @@ -870,6 +875,7 @@ private void initRereadWire() { * * @return A string representation of the current parsing context. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public String dumpContext() { ValidatableUtil.startValidateDisabled(); try { @@ -938,6 +944,7 @@ public void clear() { * Consumes and skips the start of a YAML document, e.g., '---'. * For specific keywords (like "!!data" and "!!meta-data"), the cursor position remains unchanged. */ + @Deprecated(/* to be removed in 2027 */) protected void consumeDocumentStart() { // Check if there are more than 4 bytes left to read if (bytes.readRemaining() > 4) { @@ -1001,37 +1008,6 @@ public LongArrayValues newLongArrayReference() { return new TextIntArrayReference(); } - /** - * Reads a YAML map and deserializes it into a Java Map, converting values to the specified type. - * - * @param valueType The class type to which map values should be converted. - * @return A Java Map representing the YAML map. - */ - @NotNull - private Map readMap(Class valueType) { - Map map = new LinkedHashMap(); - if (yt.current() == YamlToken.MAPPING_START) { - while (yt.next() == YamlToken.MAPPING_KEY) { - if (yt.next() == YamlToken.TEXT) { - String key = yt.text(); - Object o; - if (yt.next() == YamlToken.TEXT) { - // Convert the text to the specified type - o = ObjectUtils.convertTo(valueType, yt.text()); - } else { - throw new UnsupportedOperationException(yt.toString()); - } - map.put(key, o); - } else { - throw new UnsupportedOperationException(yt.toString()); - } - } - } else { - throw new UnsupportedOperationException(yt.toString()); - } - return map; - } - @Override public void startEvent() { consumePadding(); @@ -1041,6 +1017,8 @@ public void startEvent() { return; case NONE: return; + default: + break; } throw new UnsupportedOperationException(yt.toString()); } @@ -1228,8 +1206,6 @@ public E object(@Nullable E using, @Nullable Class clazz, boole @Override public BracketType getBracketType() { switch (yt.current()) { - default: - throw new UnsupportedOperationException(yt.toString()); case DIRECTIVES_END: case TAG: case COMMENT: @@ -1246,12 +1222,15 @@ public BracketType getBracketType() { case TEXT: case LITERAL: return BracketType.NONE; + default: + throw new UnsupportedOperationException(yt.toString()); } } /** * Extracts the text from the current token and appends it to a StringBuilder. * Handles various YAML tokens like TEXT, LITERAL, and TAG. + * * @return StringBuilder containing the text. */ @Nullable @@ -1314,6 +1293,8 @@ StringBuilder textTo0(@NotNull StringBuilder destinationBuilder) { } throw new UnsupportedOperationException(yt.toString()); + default: + break; } return destinationBuilder; } @@ -1411,6 +1392,7 @@ public WireIn skipValue() { /** * Reads the length of a marshallable. + * * @return The length of the marshallable. */ protected long readLengthMarshallable() { @@ -1425,6 +1407,7 @@ protected long readLengthMarshallable() { /** * Consumes any token type based on its indentation level. + * * @param minIndent Minimum indentation level to consume. */ protected void consumeAny(int minIndent) { @@ -1741,10 +1724,10 @@ public boolean sequence(@NotNull T t, @NotNull BiConsumer tReade /** * Reads a sequence of items from the YAML token stream and populates the provided list. * - * @param list The list to populate with the sequence items. - * @param buffer Temporary storage used during sequence processing. + * @param list The list to populate with the sequence items. + * @param buffer Temporary storage used during sequence processing. * @param bufferAdd Supplier function to add items to the buffer. - * @param reader0 The reader that processes each item in the sequence. + * @param reader0 The reader that processes each item in the sequence. * @return true if the sequence was successfully read, false otherwise. * @throws InvalidMarshallableException If there's a problem with marshalling. */ @@ -1824,11 +1807,14 @@ public boolean hasNextSequenceItem() { // Allows scalar value to be converted into singleton array case TEXT: return true; + default: + break; } return false; } @Override + @Deprecated(/* to be removed in 2027 */) public T applyToMarshallable(@NotNull Function marshallableReader) { throw new UnsupportedOperationException(yt.toString()); } @@ -1872,8 +1858,7 @@ public Object typePrefixOrObject(Class tClass) { consumePadding(); switch (yt.current()) { case TAG: { - Class type = typePrefix(); - return type; + return typePrefix(); } default: return null; @@ -2000,6 +1985,7 @@ public Object marshallable(@NotNull Object object, @NotNull SerializationStrateg * @throws IORuntimeException If there's an error in the YAML format or during demarshalling. */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public Demarshallable demarshallable(@NotNull Class clazz) { consumePadding(); switch (yt.current()) { @@ -2050,12 +2036,12 @@ public T typedMarshallable() throws InvalidMarshallableException { /** * Reads a YAML map and populates a Java map with the given key and value types. * - * @param kClass The class type of the keys. - * @param vClass The class type of the values. + * @param kClass The class type of the keys. + * @param vClass The class type of the values. * @param usingMap An optional pre-existing map to populate. * @return The populated map. * @throws InvalidMarshallableException If there's a problem with marshalling. - * @throws IORuntimeException If there's an error in the YAML format or during parsing. + * @throws IORuntimeException If there's an error in the YAML format or during parsing. */ @Nullable private Map map(@NotNull final Class kClass, @@ -2085,13 +2071,13 @@ private Map map(@NotNull final Class kClass, /** * Parses a typed map based on specific YAML tags. * - * @param kClazz The class type for map keys. - * @param vClass The class type for map values. - * @param usingMap The map to populate based on the YAML data. + * @param kClazz The class type for map keys. + * @param vClass The class type for map values. + * @param usingMap The map to populate based on the YAML data. * @param targetBuffer A StringBuilder instance used for temporary string operations. * @return Populated map from the YAML data or null. * @throws InvalidMarshallableException If there's a problem with marshalling. - * @throws IORuntimeException If an unexpected YAML structure or tag is encountered. + * @throws IORuntimeException If an unexpected YAML structure or tag is encountered. */ @Nullable private Map typedMap(@NotNull Class kClazz, @NotNull Class vClass, @NotNull Map usingMap, @NotNull StringBuilder targetBuffer) throws InvalidMarshallableException { @@ -2102,7 +2088,7 @@ private Map typedMap(@NotNull Class kClazz, @NotNull Class vC text(); return null; // Return null to indicate absence of a value. - // If the current token indicates a sequence map... + // If the current token indicates a sequence map... } else if (SEQ_MAP.contentEquals(targetBuffer)) { consumePadding(); @@ -2300,8 +2286,8 @@ public Object objectWithInferredType(Object using, @NotNull SerializationStrateg * If a YAML ANCHOR is encountered, it's mapped to the parsed object for potential future ALIAS references. * * @param reusableInstance The object to potentially reuse when reading. Might be null. - * @param strategy The serialization strategy to employ while reading the object. - * @param defaultType Expected type of the object to be read. If null, the method will attempt to infer the type. + * @param strategy The serialization strategy to employ while reading the object. + * @param defaultType Expected type of the object to be read. If null, the method will attempt to infer the type. * @return The read object, possibly of the expected type. Might be null if the YAML token is NONE. * @throws InvalidMarshallableException if any error occurs while parsing or constructing the object. */ @@ -2446,7 +2432,7 @@ private Object readSequence(Class clazz) { * and extract each item, casting them to the specified class if provided. * * @param clazz The class type to which each item should be casted, can be null. - * @param list The target collection to be populated. + * @param list The target collection to be populated. */ private void readCollection(@Nullable Class clazz, @NotNull Collection list) { sequence(list, (l, v) -> { diff --git a/src/main/java/net/openhft/chronicle/wire/YamlWireOut.java b/src/main/java/net/openhft/chronicle/wire/YamlWireOut.java index c7d266f404..28e334d67d 100644 --- a/src/main/java/net/openhft/chronicle/wire/YamlWireOut.java +++ b/src/main/java/net/openhft/chronicle/wire/YamlWireOut.java @@ -90,6 +90,7 @@ protected YamlWireOut(@NotNull Bytes bytes, boolean use8bit) { * * @return True if timestamps should be added, otherwise false. */ + @Deprecated(/* to be removed in 2027 */) public boolean addTimeStamps() { return addTimeStamps; } @@ -411,6 +412,7 @@ public void append(@NotNull CharSequence cs, int offset, int length) { * @param o The object to be serialized. * @throws InvalidMarshallableException if an error occurs during serialization. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public void writeObject(Object o) throws InvalidMarshallableException { if (o instanceof Iterable) { for (Object o2 : (Iterable) o) { @@ -1491,7 +1493,7 @@ public T marshallable(@NotNull Serializable object) throws InvalidMarshallableEx @Nullable BytesStore popSep = null; if (wasLeaf) { leaf = false; - } else if (seps.size() > 0) { + } else if (!seps.isEmpty()) { popSep = seps.get(seps.size() - 1); popState(); newLine(); @@ -1568,6 +1570,7 @@ public T map(@NotNull final Map map) throws InvalidMarshallableException { /** * Sets the separator to denote the end of a field. */ + @Deprecated(/* to be removed in 2027 */) protected void endField() { sep = END_FIELD; } diff --git a/src/main/java/net/openhft/chronicle/wire/converter/package-info.java b/src/main/java/net/openhft/chronicle/wire/converter/package-info.java new file mode 100644 index 0000000000..1bd8c7c998 --- /dev/null +++ b/src/main/java/net/openhft/chronicle/wire/converter/package-info.java @@ -0,0 +1,11 @@ +/* + * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 + */ +/** + * Converters for mapping Chronicle Wire values to textual representations. + * + *

    These helpers encode and decode identifiers, timestamps, symbols, and other + * numeric values so they can be serialized compactly while remaining human + * readable in text wires and logs. + */ +package net.openhft.chronicle.wire.converter; diff --git a/src/main/java/net/openhft/chronicle/wire/domestic/AutoTailers.java b/src/main/java/net/openhft/chronicle/wire/domestic/AutoTailers.java index d2e0b3b8fc..04b6e18ce4 100644 --- a/src/main/java/net/openhft/chronicle/wire/domestic/AutoTailers.java +++ b/src/main/java/net/openhft/chronicle/wire/domestic/AutoTailers.java @@ -40,6 +40,7 @@ public interface CloseableEventHandler extends EventHandler, AutoCloseable { void close(); } + @Deprecated(/* to be removed in 2027 */) public static long replayOnto(@NotNull final MarshallableIn tailer, @NotNull final ExcerptListener excerptListener) throws InvalidMarshallableException { requireNonNull(tailer); @@ -49,6 +50,7 @@ public static long replayOnto(@NotNull final MarshallableIn tailer, } @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static CloseableRunnable createRunnable(@NotNull final Supplier tailerSupplier, @NotNull final ExcerptListener excerptListener, @NotNull final Supplier pauserSupplier) { @@ -60,6 +62,7 @@ public static CloseableRunnable createRunnable(@NotNull final Supplier tailerSupplier, @NotNull final ExcerptListener excerptListener) { requireNonNull(tailerSupplier); diff --git a/src/main/java/net/openhft/chronicle/wire/domestic/InternalWire.java b/src/main/java/net/openhft/chronicle/wire/domestic/InternalWire.java index 2b4de7e969..a5e41ac137 100644 --- a/src/main/java/net/openhft/chronicle/wire/domestic/InternalWire.java +++ b/src/main/java/net/openhft/chronicle/wire/domestic/InternalWire.java @@ -3,6 +3,13 @@ */ package net.openhft.chronicle.wire.domestic; +/** + * Internal hook used by Chronicle Wire implementations to adjust their state around header + * processing. + *

    + * Implementations may use {@link #forceNotInsideHeader()} when a nested operation must be treated + * as outside any current header scope. + */ public interface InternalWire { void forceNotInsideHeader(); } diff --git a/src/main/java/net/openhft/chronicle/wire/domestic/extractor/DocumentExtractor.java b/src/main/java/net/openhft/chronicle/wire/domestic/extractor/DocumentExtractor.java index 6ddab7b279..a59fdfb4b3 100644 --- a/src/main/java/net/openhft/chronicle/wire/domestic/extractor/DocumentExtractor.java +++ b/src/main/java/net/openhft/chronicle/wire/domestic/extractor/DocumentExtractor.java @@ -50,6 +50,7 @@ public interface DocumentExtractor { * @return a new mapped DocumentExtractor * @throws NullPointerException if the provided {@code mapper} is {@code null} */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default DocumentExtractor map(@NotNull final Function mapper) { requireNonNull(mapper); return (wire, index) -> { @@ -71,6 +72,7 @@ default DocumentExtractor map(@NotNull final Function mapper) { requireNonNull(mapper); return (wire, index) -> { @@ -91,6 +93,7 @@ default ToLongDocumentExtractor mapToLong(@NotNull final ToLongFunction filter(@NotNull final Predicate predicate) { requireNonNull(predicate); return (wire, index) -> { @@ -130,6 +133,7 @@ interface Builder extends net.openhft.chronicle.core.util.Builder withReusing(@NotNull Supplier supplier); /** @@ -141,6 +145,7 @@ interface Builder extends net.openhft.chronicle.core.util.Builder withThreadConfinedReuse(); /** @@ -159,6 +164,7 @@ interface Builder extends net.openhft.chronicle.core.util.Builder interface type * @return this Builder */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) @NotNull Builder withMethod(@NotNull final Class interfaceType, @NotNull final BiConsumer methodReference); @@ -172,6 +178,7 @@ interface Builder extends net.openhft.chronicle.core.util.Builder element type * @return a new Builder */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) static Builder builder(@NotNull final Class elementType) { requireNonNull(elementType); return new DocumentExtractorBuilder<>(elementType); diff --git a/src/main/java/net/openhft/chronicle/wire/domestic/extractor/ToDoubleDocumentExtractor.java b/src/main/java/net/openhft/chronicle/wire/domestic/extractor/ToDoubleDocumentExtractor.java index 54e3fef1e7..7161ca3b5d 100644 --- a/src/main/java/net/openhft/chronicle/wire/domestic/extractor/ToDoubleDocumentExtractor.java +++ b/src/main/java/net/openhft/chronicle/wire/domestic/extractor/ToDoubleDocumentExtractor.java @@ -21,6 +21,7 @@ * methods for transformations and mapping to different object types after extraction. */ @FunctionalInterface +@Deprecated(/* to be removed in 2027 */) public interface ToDoubleDocumentExtractor { /** diff --git a/src/main/java/net/openhft/chronicle/wire/domestic/extractor/ToLongDocumentExtractor.java b/src/main/java/net/openhft/chronicle/wire/domestic/extractor/ToLongDocumentExtractor.java index 61062fd4bb..98109ec566 100644 --- a/src/main/java/net/openhft/chronicle/wire/domestic/extractor/ToLongDocumentExtractor.java +++ b/src/main/java/net/openhft/chronicle/wire/domestic/extractor/ToLongDocumentExtractor.java @@ -48,6 +48,7 @@ public interface ToLongDocumentExtractor { * @return a new mapped ToLongDocumentExtractor * @throws NullPointerException if the provided {@code mapper} is {@code null} */ + @Deprecated(/* to be removed in 2027 */) default ToLongDocumentExtractor map(@NotNull final LongUnaryOperator mapper) { requireNonNull(mapper); return (wire, index) -> { @@ -69,6 +70,7 @@ default ToLongDocumentExtractor map(@NotNull final LongUnaryOperator mapper) { * @return a new mapped DocumentExtractor * @throws NullPointerException if the provided {@code mapper} is {@code null} */ + @Deprecated(/* to be removed in 2027 */) default DocumentExtractor mapToObj(@NotNull final LongFunction mapper) { requireNonNull(mapper); return (wire, index) -> { @@ -90,6 +92,7 @@ default DocumentExtractor mapToObj(@NotNull final LongFunction { @@ -110,6 +113,7 @@ default ToDoubleDocumentExtractor mapToDouble(@NotNull final LongToDoubleFunctio * @return a ToLongDocumentExtractor consisting of the elements of this ToLongDocumentExtractor that match * @throws NullPointerException if the provided {@code predicate} is {@code null} */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default ToLongDocumentExtractor filter(@NotNull final LongPredicate predicate) { requireNonNull(predicate); return (wire, index) -> { @@ -131,6 +135,7 @@ default ToLongDocumentExtractor filter(@NotNull final LongPredicate predicate) { * * @return a ToLongDocumentExtractor that returns the index */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) static ToLongDocumentExtractor extractingIndex() { return (wire, index) -> index; } diff --git a/src/main/java/net/openhft/chronicle/wire/domestic/extractor/package-info.java b/src/main/java/net/openhft/chronicle/wire/domestic/extractor/package-info.java new file mode 100644 index 0000000000..4523b37e8f --- /dev/null +++ b/src/main/java/net/openhft/chronicle/wire/domestic/extractor/package-info.java @@ -0,0 +1,10 @@ +/* + * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 + */ +/** + * Document extractors for pulling typed values from Chronicle Wire streams. + * + *

    Utilities here traverse documents and project them into primitive-friendly + * forms for analysis, metrics, or stream processing. + */ +package net.openhft.chronicle.wire.domestic.extractor; diff --git a/src/main/java/net/openhft/chronicle/wire/domestic/package-info.java b/src/main/java/net/openhft/chronicle/wire/domestic/package-info.java index 88c8d1ec5f..59ea6308fe 100644 --- a/src/main/java/net/openhft/chronicle/wire/domestic/package-info.java +++ b/src/main/java/net/openhft/chronicle/wire/domestic/package-info.java @@ -1,4 +1,20 @@ /* * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 */ +/** + * This package and any and all sub-packages contains strictly internal classes for this Chronicle + * library. + * Internal classes shall never be used directly. + *

    + * Specifically, the following actions (including, but not limited to) are not allowed + * on internal classes and packages: + *

      + *
    • Casting to
    • + *
    • Reflection of any kind
    • + *
    • Explicit serialise/deserialize
    • + *
    + *

    + * The classes in this package and any sub-package are subject to changes at any time for any + * reason. + */ package net.openhft.chronicle.wire.domestic; diff --git a/src/main/java/net/openhft/chronicle/wire/domestic/reduction/ConcurrentCollectors.java b/src/main/java/net/openhft/chronicle/wire/domestic/reduction/ConcurrentCollectors.java index db279d6e71..23428950c3 100644 --- a/src/main/java/net/openhft/chronicle/wire/domestic/reduction/ConcurrentCollectors.java +++ b/src/main/java/net/openhft/chronicle/wire/domestic/reduction/ConcurrentCollectors.java @@ -38,6 +38,7 @@ private ConcurrentCollectors() { * {@code List}, in encounter order */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static Collector> toConcurrentList() { // Creates a synchronized list for concurrent access and sets up accumulation and combination operations. @@ -64,6 +65,7 @@ private ConcurrentCollectors() { * {@code Set} */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static Collector> toConcurrentSet() { // Collects elements into a synchronized map and then retrieves the key set. @@ -79,7 +81,7 @@ private ConcurrentCollectors() { * input elements under a specified {@code BinaryOperator} using the * provided identity. *

    - * Note: The {@code reducing()} collectors are most useful when used in a + * Note: The {@code reducing()} collectors are most useful when used in a * multi-level reduction, downstream of {@code groupingBy} or * {@code partitioningBy}. * @@ -90,10 +92,11 @@ private ConcurrentCollectors() { * @return a {@code Collector} which implements the reduction operation * @see Collectors#reducing(Object, BinaryOperator) */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static Collector reducingConcurrent(final T identity, @NotNull final BinaryOperator op) { - // Ensure the binary operator is not null. + // Ensure the binary operator is not null. requireNonNull(op); // Set up a concurrent reduction using an AtomicReference as the accumulator. @@ -127,6 +130,7 @@ private ConcurrentCollectors() { * @see Collectors#reducing(BinaryOperator) */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static Collector> reducingConcurrent(@NotNull final BinaryOperator op) { requireNonNull(op); @@ -206,6 +210,7 @@ private ConcurrentCollectors() { * @param value type * @return a merger that will replace values */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static BinaryOperator replacingMerger() { return (u, v) -> v; } @@ -226,6 +231,7 @@ public static BinaryOperator retainingMerger() { * @param value type * @return a merger that will throw an Exception if duplicate keys are detected */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static BinaryOperator throwingMerger() { return (u, v) -> { throw new IllegalStateException(String.format("Duplicate value for %s", u)); diff --git a/src/main/java/net/openhft/chronicle/wire/domestic/reduction/README.adoc b/src/main/java/net/openhft/chronicle/wire/domestic/reduction/README.adoc index ec4b391886..4759e2b7a1 100644 --- a/src/main/java/net/openhft/chronicle/wire/domestic/reduction/README.adoc +++ b/src/main/java/net/openhft/chronicle/wire/domestic/reduction/README.adoc @@ -1,10 +1,12 @@ = Chronicle Reductions Per Minborg -:css-signature: demo +:sectnums: :toc: macro -:toclevels: 3 :icons: font -:sectnums: +:lang: en-GB +:toclevels: 3 +:css-signature: demo +:source-highlighter: rouge toc::[] diff --git a/src/main/java/net/openhft/chronicle/wire/domestic/reduction/Reduction.java b/src/main/java/net/openhft/chronicle/wire/domestic/reduction/Reduction.java index 0cd7fe0ecd..b1b9d838d7 100644 --- a/src/main/java/net/openhft/chronicle/wire/domestic/reduction/Reduction.java +++ b/src/main/java/net/openhft/chronicle/wire/domestic/reduction/Reduction.java @@ -9,7 +9,6 @@ import net.openhft.chronicle.wire.MarshallableIn; import net.openhft.chronicle.wire.Wire; import net.openhft.chronicle.wire.domestic.extractor.DocumentExtractor; -import net.openhft.chronicle.wire.domestic.extractor.ToDoubleDocumentExtractor; import net.openhft.chronicle.wire.domestic.extractor.ToLongDocumentExtractor; import net.openhft.chronicle.wire.internal.reduction.ReductionUtil; import org.jetbrains.annotations.NotNull; @@ -24,6 +23,7 @@ * It provides a means to consume excerpts from a given wire and apply reductions on them. * The implementations of this interface should be thread-safe, especially if they are referenced as an {@link ExcerptListener}. */ +@SuppressWarnings({"deprecation", "removal"}) public interface Reduction extends ExcerptListener { /** @@ -43,6 +43,7 @@ public interface Reduction extends ExcerptListener { * @return Reduction view. */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) T reduction(); /** @@ -58,6 +59,7 @@ public interface Reduction extends ExcerptListener { * @return the last index seen or -1 if no index was seen * @throws NullPointerException if the provided {@code tailer} is {@code null} */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) default long accept(@NotNull final MarshallableIn tailer) throws InvalidMarshallableException { requireNonNull(tailer); return ReductionUtil.accept(tailer, this); @@ -77,6 +79,7 @@ default long accept(@NotNull final MarshallableIn tailer) throws InvalidMarshall * @see LongReductionBuilder * @see DoubleReductionBuilder */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) static ReductionBuilder of(@NotNull final DocumentExtractor extractor) { requireNonNull(extractor); return new ReductionUtil.VanillaReductionBuilder<>(extractor); @@ -108,7 +111,8 @@ static LongReductionBuilder ofLong(@NotNull final ToLongDocumentExtractor extrac * @see #of(DocumentExtractor) * @see #ofLong(ToLongDocumentExtractor) */ - static DoubleReductionBuilder ofDouble(@NotNull final ToDoubleDocumentExtractor extractor) { + @SuppressWarnings({"deprecation", "removal"}) + static DoubleReductionBuilder ofDouble(@NotNull final net.openhft.chronicle.wire.domestic.extractor.ToDoubleDocumentExtractor extractor) { requireNonNull(extractor); return new ReductionUtil.VanillaDoubleReductionBuilder(extractor); } @@ -117,6 +121,7 @@ static DoubleReductionBuilder ofDouble(@NotNull final ToDoubleDocumentExtractor * ReductionBuilder is an interface that defines the contract for creating new Reductions using a specific collector. * Implementations of this interface should cater to the specific type of element being reduced. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) interface ReductionBuilder { /** @@ -130,6 +135,7 @@ interface ReductionBuilder { * @return a new Reduction of type R * @throws NullPointerException if the provided {@code collector} is {@code null} */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) Reduction collecting(@NotNull final Collector collector); } diff --git a/src/main/java/net/openhft/chronicle/wire/domestic/reduction/Reductions.java b/src/main/java/net/openhft/chronicle/wire/domestic/reduction/Reductions.java index 2e2c8dc3ae..1be73d030c 100644 --- a/src/main/java/net/openhft/chronicle/wire/domestic/reduction/Reductions.java +++ b/src/main/java/net/openhft/chronicle/wire/domestic/reduction/Reductions.java @@ -5,7 +5,6 @@ import net.openhft.chronicle.wire.SelfDescribingMarshallable; import net.openhft.chronicle.wire.Wire; -import net.openhft.chronicle.wire.domestic.extractor.ToDoubleDocumentExtractor; import net.openhft.chronicle.wire.domestic.extractor.ToLongDocumentExtractor; import org.jetbrains.annotations.NotNull; @@ -25,6 +24,7 @@ * It provides static methods to create various types of Reductions, offering functionalities * related to longs, doubles, and counting excerpts. */ +@SuppressWarnings({"deprecation", "removal"}) public final class Reductions { // Suppresses default constructor, ensuring non-instantiability. @@ -46,6 +46,7 @@ private Reductions() { * @return a new Reduction reducing long values * @throws NullPointerException if any objects provided are {@code null}. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static Reduction reducingLong(@NotNull final ToLongDocumentExtractor extractor, final long identity, @NotNull final LongBinaryOperator accumulator) { @@ -73,7 +74,9 @@ public static Reduction reducingLong(@NotNull final ToLongDocument * @return a new Reduction reducing double values * @throws NullPointerException if any objects provided are {@code null}. */ - public static Reduction reducingDouble(@NotNull final ToDoubleDocumentExtractor extractor, + @Deprecated(/* to be removed in 2027 */) + @SuppressWarnings({"deprecation", "removal"}) + public static Reduction reducingDouble(@NotNull final net.openhft.chronicle.wire.domestic.extractor.ToDoubleDocumentExtractor extractor, final double identity, @NotNull final DoubleBinaryOperator accumulator) { requireNonNull(extractor); @@ -94,6 +97,7 @@ public static Reduction reducingDouble(@NotNull final ToDoubleDo * * @return a new Reduction counting excerpts */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static Reduction counting() { return Reduction.ofLong( (wire, index) -> 1L) @@ -110,6 +114,7 @@ public static Reduction counting() { * This is an example of a public class with configurable properties that can be * referenced in a YAML configuration file. */ + @Deprecated(/* to be removed in 2027 */) public static final class Counting extends SelfDescribingMarshallable implements Reduction { // An atomic field updater to provide thread-safe updates to the counter diff --git a/src/main/java/net/openhft/chronicle/wire/domestic/reduction/package-info.java b/src/main/java/net/openhft/chronicle/wire/domestic/reduction/package-info.java new file mode 100644 index 0000000000..cde9b0e675 --- /dev/null +++ b/src/main/java/net/openhft/chronicle/wire/domestic/reduction/package-info.java @@ -0,0 +1,10 @@ +/* + * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 + */ +/** + * Reduction helpers for Chronicle Wire document streams. + * + *

    Collectors and utilities here fold documents into aggregated results while + * respecting the threading and allocation constraints of Chronicle pipelines. + */ +package net.openhft.chronicle.wire.domestic.reduction; diff --git a/src/main/java/net/openhft/chronicle/wire/domestic/stream/README.adoc b/src/main/java/net/openhft/chronicle/wire/domestic/stream/README.adoc index 47f6bcd850..689574e08f 100644 --- a/src/main/java/net/openhft/chronicle/wire/domestic/stream/README.adoc +++ b/src/main/java/net/openhft/chronicle/wire/domestic/stream/README.adoc @@ -1,10 +1,12 @@ = Chronicle Stream Bridge Per Minborg -:css-signature: demo +:sectnums: :toc: macro -:toclevels: 3 :icons: font -:sectnums: +:lang: en-GB +:toclevels: 3 +:css-signature: demo +:source-highlighter: rouge toc::[] diff --git a/src/main/java/net/openhft/chronicle/wire/domestic/stream/Streams.java b/src/main/java/net/openhft/chronicle/wire/domestic/stream/Streams.java index 6aa390afda..8da16ff815 100644 --- a/src/main/java/net/openhft/chronicle/wire/domestic/stream/Streams.java +++ b/src/main/java/net/openhft/chronicle/wire/domestic/stream/Streams.java @@ -5,7 +5,6 @@ import net.openhft.chronicle.wire.MarshallableIn; import net.openhft.chronicle.wire.domestic.extractor.DocumentExtractor; -import net.openhft.chronicle.wire.domestic.extractor.ToDoubleDocumentExtractor; import net.openhft.chronicle.wire.domestic.extractor.ToLongDocumentExtractor; import net.openhft.chronicle.wire.internal.stream.StreamsUtil; import org.jetbrains.annotations.NotNull; @@ -29,6 +28,7 @@ * Generally, these objects will create underlying objects and should not be used in JVMs running * deterministic low-latency code. Instead, they are suitable for convenient off-line analysis of queue content. */ +@SuppressWarnings({"deprecation", "removal"}) public final class Streams { // Suppresses default constructor, ensuring non-instantiability. @@ -53,6 +53,7 @@ private Streams() { * @throws NullPointerException if any of the provided parameters are {@code null} */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static Stream of(@NotNull final MarshallableIn documentProvider, @NotNull final DocumentExtractor extractor) { requireNonNull(documentProvider); @@ -77,6 +78,7 @@ public static Stream of(@NotNull final MarshallableIn documentProvider, * @throws NullPointerException if any of the provided parameters are {@code null} */ @NotNull + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static LongStream ofLong(@NotNull final MarshallableIn documentProvider, @NotNull final ToLongDocumentExtractor extractor) { requireNonNull(documentProvider); @@ -101,8 +103,9 @@ public static LongStream ofLong(@NotNull final MarshallableIn documentProvider, * @throws NullPointerException if any of the provided parameters are {@code null} */ @NotNull + @Deprecated(/* to be removed in 2027 */) public static DoubleStream ofDouble(@NotNull final MarshallableIn documentProvider, - @NotNull final ToDoubleDocumentExtractor extractor) { + @NotNull final net.openhft.chronicle.wire.domestic.extractor.ToDoubleDocumentExtractor extractor) { requireNonNull(documentProvider); requireNonNull(extractor); return StreamSupport.doubleStream(spliteratorOfDouble(documentProvider, extractor), false); @@ -181,7 +184,7 @@ public static Spliterator.OfLong spliteratorOfLong(@NotNull final MarshallableIn */ @NotNull public static Spliterator.OfDouble spliteratorOfDouble(@NotNull final MarshallableIn documentProvider, - @NotNull final ToDoubleDocumentExtractor extractor) { + @NotNull final net.openhft.chronicle.wire.domestic.extractor.ToDoubleDocumentExtractor extractor) { requireNonNull(documentProvider); requireNonNull(extractor); return new StreamsUtil.VanillaSpliteratorOfDouble(iteratorOfDouble(documentProvider, extractor)); @@ -248,7 +251,7 @@ public static PrimitiveIterator.OfLong iteratorOfLong(@NotNull final Marshallabl */ @NotNull public static PrimitiveIterator.OfDouble iteratorOfDouble(@NotNull final MarshallableIn documentProvider, - @NotNull final ToDoubleDocumentExtractor extractor) { + @NotNull final net.openhft.chronicle.wire.domestic.extractor.ToDoubleDocumentExtractor extractor) { requireNonNull(documentProvider); requireNonNull(extractor); diff --git a/src/main/java/net/openhft/chronicle/wire/domestic/stream/package-info.java b/src/main/java/net/openhft/chronicle/wire/domestic/stream/package-info.java new file mode 100644 index 0000000000..4e2c11a631 --- /dev/null +++ b/src/main/java/net/openhft/chronicle/wire/domestic/stream/package-info.java @@ -0,0 +1,4 @@ +/* + * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 + */ +package net.openhft.chronicle.wire.domestic.stream; diff --git a/src/main/java/net/openhft/chronicle/wire/internal/FileMarshallableOut.java b/src/main/java/net/openhft/chronicle/wire/internal/FileMarshallableOut.java index a35a4b73e4..cba6ed1906 100644 --- a/src/main/java/net/openhft/chronicle/wire/internal/FileMarshallableOut.java +++ b/src/main/java/net/openhft/chronicle/wire/internal/FileMarshallableOut.java @@ -11,7 +11,9 @@ import java.io.FileOutputStream; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.net.URL; +import java.net.URLDecoder; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; @@ -23,11 +25,12 @@ * The class is designed to handle output operations to a file represented by a URL and manages * the lifecycle of the associated Wire data structure. */ +@Deprecated(/* to be removed in 2027, as it is only used in tests */) public class FileMarshallableOut implements MarshallableOut { private final URL url; // The URL pointing to the file being written to private final FMOOptions options = new FMOOptions(); // Options for controlling file output behavior - private Wire wire; // The underlying Wire data structure managing the data + private final Wire wire; // The underlying Wire data structure managing the data // DocumentContextHolder for managing document context lifecycle and output operations private final DocumentContextHolder dcHolder = new DocumentContextHolder() { @@ -81,6 +84,7 @@ public FileMarshallableOut(MarshallableOutBuilder builder, WireType wireType) th // If there's a query in the URL, parse and set the options final String query = url.getQuery(); + options.append = query != null && parseAppendFlag(query); if (query != null) { QueryWire queryWire = new QueryWire(Bytes.from(query)); options.readMarshallable(queryWire); @@ -116,4 +120,26 @@ public void rollbackIfNotComplete() { static class FMOOptions extends SelfDescribingMarshallable { boolean append; // Indicates if data should be appended to the existing file } + + private static boolean parseAppendFlag(String query) { + for (String pair : query.split("&")) { + if (pair.isEmpty()) + continue; + int equals = pair.indexOf('='); + String rawKey = equals >= 0 ? pair.substring(0, equals) : pair; + String rawValue = equals >= 0 ? pair.substring(equals + 1) : ""; + if ("append".equalsIgnoreCase(decodeComponent(rawKey))) { + return Boolean.parseBoolean(decodeComponent(rawValue)); + } + } + return false; + } + + private static String decodeComponent(String value) { + try { + return URLDecoder.decode(value, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new IORuntimeException(e); + } + } } diff --git a/src/main/java/net/openhft/chronicle/wire/internal/FromStringInterner.java b/src/main/java/net/openhft/chronicle/wire/internal/FromStringInterner.java index 569d1414af..8acc41f136 100644 --- a/src/main/java/net/openhft/chronicle/wire/internal/FromStringInterner.java +++ b/src/main/java/net/openhft/chronicle/wire/internal/FromStringInterner.java @@ -18,6 +18,7 @@ * but doesn't ensure the same object is returned on subsequent calls or across threads. *

    * Note: While it's not strictly thread-safe, it's expected to still produce correct results. + * * @author peter.lawrey */ @SuppressWarnings("unchecked") @@ -37,7 +38,7 @@ public abstract class FromStringInterner { * Constructor initializes the entries array and calculates mask and shift values. * * @param capacity The desired capacity of the interner. - * @throws IllegalArgumentException + * @throws IllegalArgumentException if the requested capacity is too small. */ @SuppressWarnings("rawtypes") protected FromStringInterner(int capacity) throws IllegalArgumentException { @@ -52,7 +53,9 @@ protected FromStringInterner(int capacity) throws IllegalArgumentException { * * @param s The string to be interned. * @return The interned representation. - * @throws IllegalArgumentException, IORuntimeException, BufferUnderflowException + * @throws IllegalArgumentException if the string cannot be interned. + * @throws IORuntimeException if the backing storage encounters an IO issue. + * @throws BufferUnderflowException if insufficient data is available while reading. */ public T intern(@NotNull String s) throws IllegalArgumentException, IORuntimeException, BufferUnderflowException { @@ -86,7 +89,7 @@ public T intern(@NotNull String s) * * @param s The input string. * @return The value representation. - * @throws IORuntimeException + * @throws IORuntimeException if the value cannot be created. */ @NotNull protected abstract T getValue(String s) throws IORuntimeException; diff --git a/src/main/java/net/openhft/chronicle/wire/internal/HTTPMarshallableOut.java b/src/main/java/net/openhft/chronicle/wire/internal/HTTPMarshallableOut.java index fad05d69c4..af8894b94f 100644 --- a/src/main/java/net/openhft/chronicle/wire/internal/HTTPMarshallableOut.java +++ b/src/main/java/net/openhft/chronicle/wire/internal/HTTPMarshallableOut.java @@ -23,7 +23,7 @@ * The class encapsulates a {@link Wire} which holds the serialized representation. On closure of a document context, * the serialized content is posted to the given URL. */ -@SuppressWarnings("this-escape") +@SuppressWarnings({"this-escape", "deprecation"}) public class HTTPMarshallableOut implements MarshallableOut { // The target URL to which serialized data is posted diff --git a/src/main/java/net/openhft/chronicle/wire/internal/InternalAutoTailers.java b/src/main/java/net/openhft/chronicle/wire/internal/InternalAutoTailers.java index 2b9b9bd412..8a01cd8fd7 100644 --- a/src/main/java/net/openhft/chronicle/wire/internal/InternalAutoTailers.java +++ b/src/main/java/net/openhft/chronicle/wire/internal/InternalAutoTailers.java @@ -17,6 +17,12 @@ import static net.openhft.chronicle.core.util.ObjectUtils.requireNonNull; +/** + * Internal utilities for building auto tailing pollers over {@link MarshallableIn} sources. + *

    + * Provides runnable and event handler driven pollers that repeatedly apply a reduction function to + * tailed excerpts while managing pausing and clean shutdown. + */ public final class InternalAutoTailers { private InternalAutoTailers() { @@ -26,6 +32,10 @@ public static final class RunnablePoller extends AbstractPoller implements AutoT private final Pauser pauser; + /** + * Runnable poller that continuously tails a {@link MarshallableIn} source using a supplied + * {@link Pauser} between reads. + */ public RunnablePoller(@NotNull final Supplier tailerSupplier, @NotNull final ExcerptListener excerptListener, @NotNull final Supplier pauserSupplier) { @@ -50,6 +60,9 @@ public void run() { public static final class EventHandlerPoller extends AbstractPoller implements AutoTailers.CloseableEventHandler { + /** + * Event handler variant suitable for Chronicle Threads event loops. + */ public EventHandlerPoller(@NotNull final Supplier tailerSupplier, @NotNull final ExcerptListener excerptListener) { super(tailerSupplier, excerptListener); @@ -72,6 +85,9 @@ private abstract static class AbstractPoller implements AutoCloseable { private final Runnable closer; private volatile boolean running = true; + /** + * Base poller that wires together the tailer, listener and close handling. + */ protected AbstractPoller(@NotNull final Supplier tailerSupplier, @NotNull final ExcerptListener excerptListener) { requireNonNull(tailerSupplier); diff --git a/src/main/java/net/openhft/chronicle/wire/internal/StringConsumerMarshallableOut.java b/src/main/java/net/openhft/chronicle/wire/internal/StringConsumerMarshallableOut.java index 6a0d88117c..474d4efcdc 100644 --- a/src/main/java/net/openhft/chronicle/wire/internal/StringConsumerMarshallableOut.java +++ b/src/main/java/net/openhft/chronicle/wire/internal/StringConsumerMarshallableOut.java @@ -10,18 +10,19 @@ /** * An implementation of {@link MarshallableOut} that serializes {@link Marshallable} objects and forwards - * the serialized string representation to a provided {@link Consumer}. + * the serialized string representation to a provided {@link Consumer} for strings. *

    * The class encapsulates a {@link Wire} to hold the serialized representation. Upon closing of a document context, * the serialized content is converted to a string and passed to the given string consumer. */ +@Deprecated(/* to be removed in 2027, as it is only used in tests */) public class StringConsumerMarshallableOut implements MarshallableOut { // Consumer to process the serialized string representation - private Consumer stringConsumer; + private final Consumer stringConsumer; // Wire object responsible for serialization - private Wire wire; + private final Wire wire; // Document context holder for managing the wire and forwarding the serialized content to the stringConsumer private final DocumentContextHolder dcHolder = new DocumentContextHolder() { diff --git a/src/main/java/net/openhft/chronicle/wire/internal/VanillaFieldInfo.java b/src/main/java/net/openhft/chronicle/wire/internal/VanillaFieldInfo.java index 89ab6fe83d..d7826686ac 100644 --- a/src/main/java/net/openhft/chronicle/wire/internal/VanillaFieldInfo.java +++ b/src/main/java/net/openhft/chronicle/wire/internal/VanillaFieldInfo.java @@ -16,6 +16,12 @@ import java.lang.reflect.Type; import java.util.Objects; +/** + * Reflection based {@link FieldInfo} implementation that uses standard {@link Field} access. + *

    + * Responsible for reading and writing field values, handling primitive special cases and reporting + * generic type information for collection like fields. + */ @SuppressWarnings("rawtypes") public class VanillaFieldInfo extends AbstractFieldInfo implements FieldInfo { @@ -126,6 +132,9 @@ public void set(Object object, double value) throws IllegalArgumentException { } } + /** + * Lazily resolve and return the reflective {@link Field}, enabling access checks as needed. + */ public Field getField() throws NoSuchFieldException { if (field == null) { field = parent.getDeclaredField(name); @@ -134,6 +143,12 @@ public Field getField() throws NoSuchFieldException { return field; } + /** + * Return the erased class of the {@code index}th generic parameter for the field. + *

    + * Only supports fields declared with concrete generic arguments; callers should guard for + * {@link ClassCastException} when the argument is not a {@link Class}. + */ @Override public Class genericType(int index) { ParameterizedType genericType = (ParameterizedType) field.getGenericType(); diff --git a/src/main/java/net/openhft/chronicle/wire/internal/extractor/DocumentExtractorBuilder.java b/src/main/java/net/openhft/chronicle/wire/internal/extractor/DocumentExtractorBuilder.java index 1514367c82..67d25830c1 100644 --- a/src/main/java/net/openhft/chronicle/wire/internal/extractor/DocumentExtractorBuilder.java +++ b/src/main/java/net/openhft/chronicle/wire/internal/extractor/DocumentExtractorBuilder.java @@ -16,6 +16,7 @@ * Responsible for building and configuring document extractors for a specified type {@code E}. * This class provides flexibility in the extraction process, enabling efficient document extraction. */ +@Deprecated(/* to be removed in 2027, as it is only used in tests */) public final class DocumentExtractorBuilder implements DocumentExtractor.Builder { // Represents the type of element to be extracted. @@ -48,6 +49,7 @@ public DocumentExtractor.Builder withReusing(@NotNull Supplier s @NotNull @Override + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public DocumentExtractor.Builder withThreadConfinedReuse() { threadConfinedReuse = true; return this; @@ -105,6 +107,7 @@ Supplier guardedSupplier() { /** * A supplier backed by a ThreadLocal instance, ensuring separate values for each thread. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) static final class ThreadLocalSupplier implements Supplier { // ThreadLocal instance to provide thread-specific values. @@ -115,6 +118,7 @@ static final class ThreadLocalSupplier implements Supplier { * * @param supplier The supplier to initialize the thread-local with. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public ThreadLocalSupplier(@NotNull final Supplier supplier) { this.threadLocal = ThreadLocal.withInitial(supplier); } @@ -128,6 +132,7 @@ public E get() { /** * A supplier that ensures its use is confined to a single thread, providing thread safety. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) static final class ThreadConfinedSupplier implements Supplier { // Utility to assert that the current thread is the one this supplier is confined to. @@ -141,6 +146,7 @@ static final class ThreadConfinedSupplier implements Supplier { * * @param supplier The supplier to provide the delegate object. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public ThreadConfinedSupplier(@NotNull final Supplier supplier) { // Eagerly create the reuse object this.delegate = requireNonNull(supplier.get()); @@ -156,6 +162,7 @@ public E get() { /** * Represents a reference to a method for extracting data. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) private static final class MethodRef { // Type of interface the method belongs to. @@ -171,6 +178,7 @@ private static final class MethodRef { * @param methodReference The actual method reference for extraction. */ @SuppressWarnings("unchecked") + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public MethodRef(@NotNull final Class interfaceType, @NotNull final BiConsumer methodReference) { this.interfaceType = interfaceType; diff --git a/src/main/java/net/openhft/chronicle/wire/internal/extractor/DocumentExtractorUtil.java b/src/main/java/net/openhft/chronicle/wire/internal/extractor/DocumentExtractorUtil.java index b821db58eb..c72d49a9c6 100644 --- a/src/main/java/net/openhft/chronicle/wire/internal/extractor/DocumentExtractorUtil.java +++ b/src/main/java/net/openhft/chronicle/wire/internal/extractor/DocumentExtractorUtil.java @@ -21,6 +21,7 @@ * The class serves as a hub for constructing specific types of document extractors using * various parameters such as method references, suppliers, and type specifications. */ +@Deprecated(/* to be removed in 2027, as it is only used in tests */) public final class DocumentExtractorUtil { // Suppresses default constructor, ensuring non-instantiability. @@ -119,6 +120,7 @@ MethodNameAndMessageType methodOf(@NotNull final Class type, * * @param The type of the message associated with the method. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static final class MethodNameAndMessageType { private final String name; private final Class messageType; @@ -129,6 +131,7 @@ public static final class MethodNameAndMessageType { * @param name The name of the method. * @param messageType The type of the message associated with the method. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public MethodNameAndMessageType(@NotNull final String name, @NotNull final Class messageType) { this.name = name; diff --git a/src/main/java/net/openhft/chronicle/wire/internal/extractor/package-info.java b/src/main/java/net/openhft/chronicle/wire/internal/extractor/package-info.java new file mode 100644 index 0000000000..d8d0b7678b --- /dev/null +++ b/src/main/java/net/openhft/chronicle/wire/internal/extractor/package-info.java @@ -0,0 +1,10 @@ +/* + * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 + */ +/** + * Internal support for Chronicle Wire document extractors. + * + *

    Builders and utilities in this package assemble and configure extractor + * pipelines used by the public {@code domestic.extractor} APIs. + */ +package net.openhft.chronicle.wire.internal.extractor; diff --git a/src/main/java/net/openhft/chronicle/wire/internal/fieldinfo/UnsafeFieldInfo.java b/src/main/java/net/openhft/chronicle/wire/internal/fieldinfo/UnsafeFieldInfo.java index 806e5512bb..d8b0d03e13 100644 --- a/src/main/java/net/openhft/chronicle/wire/internal/fieldinfo/UnsafeFieldInfo.java +++ b/src/main/java/net/openhft/chronicle/wire/internal/fieldinfo/UnsafeFieldInfo.java @@ -10,6 +10,12 @@ import java.lang.reflect.Field; +/** + * {@link VanillaFieldInfo} specialisation that uses {@link UnsafeMemory} to access field values by + * cached offset. + *

    + * Intended for hot paths where reflective access would otherwise be a bottleneck. + */ @SuppressWarnings("deprecation" /* The parent class will either be moved to internal or cease to exist in x.26 */) class UnsafeFieldInfo extends VanillaFieldInfo { // Offset value to indicate that it hasn't been set yet. diff --git a/src/main/java/net/openhft/chronicle/wire/internal/fieldinfo/package-info.java b/src/main/java/net/openhft/chronicle/wire/internal/fieldinfo/package-info.java new file mode 100644 index 0000000000..cf8df441c0 --- /dev/null +++ b/src/main/java/net/openhft/chronicle/wire/internal/fieldinfo/package-info.java @@ -0,0 +1,10 @@ +/* + * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 + */ +/** + * Lightweight field metadata used by Chronicle Wire reflection utilities. + * + *

    These classes capture offsets, accessors, and type information to read and + * write fields efficiently, including Unsafe-backed access where required. + */ +package net.openhft.chronicle.wire.internal.fieldinfo; diff --git a/src/main/java/net/openhft/chronicle/wire/internal/package-info.java b/src/main/java/net/openhft/chronicle/wire/internal/package-info.java index bf0dcac09d..c6c5df7b22 100644 --- a/src/main/java/net/openhft/chronicle/wire/internal/package-info.java +++ b/src/main/java/net/openhft/chronicle/wire/internal/package-info.java @@ -1,4 +1,20 @@ /* * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 */ +/** + * This package and any and all sub-packages contains strictly internal classes for this Chronicle + * library. + * Internal classes shall never be used directly. + *

    + * Specifically, the following actions (including, but not limited to) are not allowed + * on internal classes and packages: + *

      + *
    • Casting to
    • + *
    • Reflection of any kind
    • + *
    • Explicit serialise/deserialize
    • + *
    + *

    + * The classes in this package and any sub-package are subject to changes at any time for any + * reason. + */ package net.openhft.chronicle.wire.internal; diff --git a/src/main/java/net/openhft/chronicle/wire/internal/reduction/ReductionUtil.java b/src/main/java/net/openhft/chronicle/wire/internal/reduction/ReductionUtil.java index b00954b80c..cc6808b486 100644 --- a/src/main/java/net/openhft/chronicle/wire/internal/reduction/ReductionUtil.java +++ b/src/main/java/net/openhft/chronicle/wire/internal/reduction/ReductionUtil.java @@ -11,7 +11,6 @@ import net.openhft.chronicle.wire.MarshallableIn; import net.openhft.chronicle.wire.Wire; import net.openhft.chronicle.wire.domestic.extractor.DocumentExtractor; -import net.openhft.chronicle.wire.domestic.extractor.ToDoubleDocumentExtractor; import net.openhft.chronicle.wire.domestic.extractor.ToLongDocumentExtractor; import net.openhft.chronicle.wire.domestic.reduction.Reduction; import org.jetbrains.annotations.NotNull; @@ -26,6 +25,7 @@ * It offers functionalities to work with marshallable objects and listeners to read excerpts * from documents and perform various reduction operations on them. */ +@SuppressWarnings({"deprecation", "removal"}) public final class ReductionUtil { // Suppresses default constructor, ensuring non-instantiability. @@ -68,6 +68,7 @@ public static long accept(@NotNull final MarshallableIn tailer, * @param Intermediate accumulation type of the collector. * @param Result type of the reduction. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static final class CollectorReduction implements Reduction { // Extracts elements of type E from a wire. @@ -130,6 +131,7 @@ public long accept(@NotNull final MarshallableIn tailer) throws InvalidMarshalla * * @param Intermediate accumulation type. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static final class LongSupplierReduction implements Reduction { // Extracts long values from a wire. @@ -192,10 +194,11 @@ public long accept(@NotNull final MarshallableIn tailer) throws InvalidMarshalla * * @param Intermediate accumulation type. */ + @Deprecated(/* to be removed in 2027 */) public static final class DoubleSupplierReduction implements Reduction { // Extracts double values from a wire. - private final ToDoubleDocumentExtractor extractor; + private final net.openhft.chronicle.wire.domestic.extractor.ToDoubleDocumentExtractor extractor; // The accumulator to accumulate double values. private final ObjDoubleConsumer accumulator; @@ -215,7 +218,8 @@ public static final class DoubleSupplierReduction implements Reduction supplier, @NotNull final ObjDoubleConsumer accumulator, @NotNull final ToDoubleFunction finisher) { @@ -306,11 +310,12 @@ public Reduction reducing(@NotNull final Supplier supplier, } } + @Deprecated(/* to be removed in 2027 */) public static final class VanillaDoubleReductionBuilder implements Reduction.DoubleReductionBuilder { - private final ToDoubleDocumentExtractor extractor; + private final net.openhft.chronicle.wire.domestic.extractor.ToDoubleDocumentExtractor extractor; - public VanillaDoubleReductionBuilder(@NotNull final ToDoubleDocumentExtractor extractor) { + public VanillaDoubleReductionBuilder(@NotNull final net.openhft.chronicle.wire.domestic.extractor.ToDoubleDocumentExtractor extractor) { this.extractor = extractor; } diff --git a/src/main/java/net/openhft/chronicle/wire/internal/reduction/package-info.java b/src/main/java/net/openhft/chronicle/wire/internal/reduction/package-info.java new file mode 100644 index 0000000000..e67c59fb9f --- /dev/null +++ b/src/main/java/net/openhft/chronicle/wire/internal/reduction/package-info.java @@ -0,0 +1,4 @@ +/* + * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 + */ +package net.openhft.chronicle.wire.internal.reduction; diff --git a/src/main/java/net/openhft/chronicle/wire/internal/stream/StreamsUtil.java b/src/main/java/net/openhft/chronicle/wire/internal/stream/StreamsUtil.java index 76fa7155a0..66bdbe305d 100644 --- a/src/main/java/net/openhft/chronicle/wire/internal/stream/StreamsUtil.java +++ b/src/main/java/net/openhft/chronicle/wire/internal/stream/StreamsUtil.java @@ -7,7 +7,6 @@ import net.openhft.chronicle.wire.MarshallableIn; import net.openhft.chronicle.wire.Wire; import net.openhft.chronicle.wire.domestic.extractor.DocumentExtractor; -import net.openhft.chronicle.wire.domestic.extractor.ToDoubleDocumentExtractor; import net.openhft.chronicle.wire.domestic.extractor.ToLongDocumentExtractor; import org.jetbrains.annotations.NotNull; @@ -23,6 +22,7 @@ * A utility class to provide additional functionality and support for streams. * This class is not meant to be instantiated. */ +@SuppressWarnings({"deprecation", "removal"}) public final class StreamsUtil { private static final int BATCH_UNIT_INCREASE = 1 << 10; // Increment size for batch unit @@ -38,6 +38,7 @@ private StreamsUtil() { * * @param the type of elements returned by this spliterator. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static final class VanillaSpliterator implements Spliterator { private final Iterator iterator; // The iterator this spliterator works on @@ -105,6 +106,7 @@ public int characteristics() { * providing basic spliterator functionalities for long elements. */ @SuppressWarnings("overloads") + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public static final class VanillaSpliteratorOfLong extends AbstractPrimitiveSpliterator implements Spliterator.OfLong { @@ -140,6 +142,7 @@ protected OfLong split(int n) { * providing basic spliterator functionalities for double elements. */ @SuppressWarnings("overloads") + @Deprecated(/* to be removed in 2027 */) public static final class VanillaSpliteratorOfDouble extends AbstractPrimitiveSpliterator implements Spliterator.OfDouble { @@ -305,13 +308,11 @@ public boolean hasNext() { if (next != null) { return true; } - long lastIndex = -1; for (; ; ) { try (final DocumentContext dc = tailer.readingDocument()) { final Wire wire = dc.wire(); if (dc.isPresent() && wire != null) { - lastIndex = dc.index(); - next = extractor.extract(wire, lastIndex); + next = extractor.extract(wire, dc.index()); if (next != null) { return true; } @@ -370,13 +371,11 @@ public boolean hasNext() { if (next != Long.MIN_VALUE) { return true; } - long lastIndex = -1; for (; ; ) { try (final DocumentContext dc = tailer.readingDocument()) { final Wire wire = dc.wire(); if (dc.isPresent() && wire != null) { - lastIndex = dc.index(); - next = extractor.extractAsLong(wire, lastIndex); + next = extractor.extractAsLong(wire, dc.index()); if (next != Long.MIN_VALUE) { return true; } @@ -403,7 +402,7 @@ public long nextLong() { /** * Represents an iterator that extracts documents containing double values from a {@link MarshallableIn} - * stream using a {@link ToDoubleDocumentExtractor}. This iterator traverses the underlying data source + * stream using a {@link net.openhft.chronicle.wire.domestic.extractor.ToDoubleDocumentExtractor}. This iterator traverses the underlying data source * and uses the extractor to transform each document into a double value. */ public static final class ExcerptIteratorOfDouble implements PrimitiveIterator.OfDouble { @@ -412,7 +411,7 @@ public static final class ExcerptIteratorOfDouble implements PrimitiveIterator.O private final MarshallableIn tailer; // The extractor used to transform the raw document into a double value - private final ToDoubleDocumentExtractor extractor; + private final net.openhft.chronicle.wire.domestic.extractor.ToDoubleDocumentExtractor extractor; // Sentinel value indicating the absence of a next item. If 'next' equals this value, // then the next item is yet to be determined. @@ -425,7 +424,7 @@ public static final class ExcerptIteratorOfDouble implements PrimitiveIterator.O * @param extractor The extractor used to transform the raw document into a double value. */ public ExcerptIteratorOfDouble(@NotNull final MarshallableIn tailer, - @NotNull final ToDoubleDocumentExtractor extractor) { + @NotNull final net.openhft.chronicle.wire.domestic.extractor.ToDoubleDocumentExtractor extractor) { this.tailer = tailer; this.extractor = extractor; } @@ -435,13 +434,11 @@ public boolean hasNext() { if (Double.isNaN(next)) { return true; } - long lastIndex = -1; for (; ; ) { try (final DocumentContext dc = tailer.readingDocument()) { final Wire wire = dc.wire(); if (dc.isPresent() && wire != null) { - lastIndex = dc.index(); - next = extractor.extractAsDouble(wire, lastIndex); + next = extractor.extractAsDouble(wire, dc.index()); if (!Double.isNaN(next)) { return true; } diff --git a/src/main/java/net/openhft/chronicle/wire/internal/stream/package-info.java b/src/main/java/net/openhft/chronicle/wire/internal/stream/package-info.java new file mode 100644 index 0000000000..ca37cdaf3f --- /dev/null +++ b/src/main/java/net/openhft/chronicle/wire/internal/stream/package-info.java @@ -0,0 +1,4 @@ +/* + * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 + */ +package net.openhft.chronicle.wire.internal.stream; diff --git a/src/main/java/net/openhft/chronicle/wire/package-info.java b/src/main/java/net/openhft/chronicle/wire/package-info.java new file mode 100644 index 0000000000..035378826d --- /dev/null +++ b/src/main/java/net/openhft/chronicle/wire/package-info.java @@ -0,0 +1,11 @@ +/* + * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 + */ +/** + * Core Chronicle Wire APIs for binary and text serialization. + * + *

    This package defines wire types, document contexts, marshalling contracts, + * and utility classes used to encode structured data with low allocation across + * Chronicle libraries and applications. + */ +package net.openhft.chronicle.wire; diff --git a/src/main/java/net/openhft/chronicle/wire/utils/JavaSourceCodeFormatter.java b/src/main/java/net/openhft/chronicle/wire/utils/JavaSourceCodeFormatter.java index c13ebdc54d..ce606c842c 100644 --- a/src/main/java/net/openhft/chronicle/wire/utils/JavaSourceCodeFormatter.java +++ b/src/main/java/net/openhft/chronicle/wire/utils/JavaSourceCodeFormatter.java @@ -31,6 +31,7 @@ public JavaSourceCodeFormatter() { * * @param indent Initial indentation level. */ + @Deprecated(/* to be removed in 2027 */) public JavaSourceCodeFormatter(int indent) { super(INDENT_SPACES, indent); } diff --git a/src/main/java/net/openhft/chronicle/wire/utils/SourceCodeFormatter.java b/src/main/java/net/openhft/chronicle/wire/utils/SourceCodeFormatter.java index 7685022aa0..569f58b309 100644 --- a/src/main/java/net/openhft/chronicle/wire/utils/SourceCodeFormatter.java +++ b/src/main/java/net/openhft/chronicle/wire/utils/SourceCodeFormatter.java @@ -114,6 +114,7 @@ public SourceCodeFormatter append(char c) { * * @param len The new length for the formatted string. */ + @Deprecated(/* to be removed in 2027 */) public void setLength(int len) { formattedCode.setLength(len); } @@ -166,6 +167,7 @@ public SourceCodeFormatter append(long i) { * @param d The double value to append. * @return The current SourceCodeFormatter instance. */ + @Deprecated(/* to be removed in 2027, as it is only used in tests */) public SourceCodeFormatter append(double d) { formattedCode.append(d); return this; @@ -186,12 +188,13 @@ public SourceCodeFormatter append(boolean flag) { * Appends the provided object's string representation to the formatted string. * The object should have a meaningful string representation for this operation to be effective. * - * @param The type of the object to be appended. - * @param stringable The object whose string representation will be appended. + * @param The type of the object to be appended. + * @param value The object whose string representation will be appended. * @return The current SourceCodeFormatter instance. */ - public SourceCodeFormatter append(Stringable stringable) { - formattedCode.append(stringable); + @Deprecated(/* to be removed in 2027, as it is only used in tests */) + public SourceCodeFormatter append(T value) { + formattedCode.append(value); return this; } diff --git a/src/main/java/net/openhft/chronicle/wire/utils/package-info.java b/src/main/java/net/openhft/chronicle/wire/utils/package-info.java new file mode 100644 index 0000000000..3fd304d9af --- /dev/null +++ b/src/main/java/net/openhft/chronicle/wire/utils/package-info.java @@ -0,0 +1,11 @@ +/* + * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 + */ +/** + * Supporting utilities for Chronicle Wire tooling and diagnostics. + * + *

    This package includes configuration loaders, method reader state helpers, + * record history tracking, and source code formatters used by tests and build + * tools. + */ +package net.openhft.chronicle.wire.utils; diff --git a/src/test/java/net/openhft/chronicle/wire/AbstractFieldTest.java b/src/test/java/net/openhft/chronicle/wire/AbstractFieldTest.java index 809b1cc9d2..8d58a37b84 100644 --- a/src/test/java/net/openhft/chronicle/wire/AbstractFieldTest.java +++ b/src/test/java/net/openhft/chronicle/wire/AbstractFieldTest.java @@ -81,7 +81,7 @@ static class MSDMHolder2 extends SelfDescribingMarshallable { // Custom Marshallable class for testing purposes. static class MySelfDescribingMarshallable extends SelfDescribingMarshallable { - String text; + final String text; MySelfDescribingMarshallable(String s) { text = s; diff --git a/src/test/java/net/openhft/chronicle/wire/AbstractMarshallableCfgTest.java b/src/test/java/net/openhft/chronicle/wire/AbstractMarshallableCfgTest.java index 8bed5dff78..dfe0af4f82 100644 --- a/src/test/java/net/openhft/chronicle/wire/AbstractMarshallableCfgTest.java +++ b/src/test/java/net/openhft/chronicle/wire/AbstractMarshallableCfgTest.java @@ -15,8 +15,8 @@ public class AbstractMarshallableCfgTest extends WireTestCommon{ static class MyAMC extends AbstractMarshallableCfg { - NestedAMC nestedAMC = new NestedAMC(); // Configuration nested inside MyAMC - NestedSDM nestedSDM = new NestedSDM(); // Self-describing data nested inside MyAMC + final NestedAMC nestedAMC = new NestedAMC(); // Configuration nested inside MyAMC + final NestedSDM nestedSDM = new NestedSDM(); // Self-describing data nested inside MyAMC } // Define a nested configuration class that also extends AbstractMarshallableCfg @@ -27,7 +27,7 @@ static class NestedAMC extends AbstractMarshallableCfg { // Define a nested self-describing data class static class NestedSDM extends SelfDescribingMarshallable { - Bytes bytes = Bytes.elasticHeapByteBuffer(); + final Bytes bytes = Bytes.elasticHeapByteBuffer(); double amt = 1.0; } diff --git a/src/test/java/net/openhft/chronicle/wire/AbstractTimestampLongConverterJLBHBenchmark.java b/src/test/java/net/openhft/chronicle/wire/AbstractTimestampLongConverterJLBHBenchmark.java index 4a85d70cae..8329cee2c8 100644 --- a/src/test/java/net/openhft/chronicle/wire/AbstractTimestampLongConverterJLBHBenchmark.java +++ b/src/test/java/net/openhft/chronicle/wire/AbstractTimestampLongConverterJLBHBenchmark.java @@ -9,6 +9,7 @@ import net.openhft.chronicle.jlbh.JLBHTask; import net.openhft.chronicle.jlbh.TeamCityHelper; +@SuppressWarnings({"deprecation", "removal"}) public class AbstractTimestampLongConverterJLBHBenchmark implements JLBHTask { // Constants for testing diff --git a/src/test/java/net/openhft/chronicle/wire/AbstractUntypedFieldTest.java b/src/test/java/net/openhft/chronicle/wire/AbstractUntypedFieldTest.java index 3878a96f48..c091b9552e 100644 --- a/src/test/java/net/openhft/chronicle/wire/AbstractUntypedFieldTest.java +++ b/src/test/java/net/openhft/chronicle/wire/AbstractUntypedFieldTest.java @@ -36,8 +36,7 @@ void beforeEach() { @ParameterizedTest @MethodSource("provideWire") void typedFieldsShouldBeNonNull(Function, Wire> wireConstruction) { - final Bytes bytes = Bytes.from("" + - "!net.openhft.chronicle.wire.AbstractUntypedFieldShouldBeNull$Holder {\n" + + final Bytes bytes = Bytes.from("!net.openhft.chronicle.wire.AbstractUntypedFieldShouldBeNull$Holder {\n" + " a: !AImpl {\n" + " }\n" + "}"); @@ -87,7 +86,7 @@ void missingAliasesShouldLogWarnings(Function, Wire> wireConstruct } // Abstract base class for testing - static abstract class A { + abstract static class A { } // Implementation of the abstract base class diff --git a/src/test/java/net/openhft/chronicle/wire/BinaryWire2Test.java b/src/test/java/net/openhft/chronicle/wire/BinaryWire2Test.java index d8232bb487..304d95ce0b 100644 --- a/src/test/java/net/openhft/chronicle/wire/BinaryWire2Test.java +++ b/src/test/java/net/openhft/chronicle/wire/BinaryWire2Test.java @@ -27,7 +27,7 @@ import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; -@SuppressWarnings({"rawtypes","try"}) +@SuppressWarnings({"rawtypes", "try", "deprecation", "removal"}) @RunWith(value = Parameterized.class) public class BinaryWire2Test extends WireTestCommon { private final boolean usePadding; @@ -321,8 +321,7 @@ public void testSequence() { @NotNull Wire wire = createWire(); writeMessage(wire); - assertEquals("" + - "--- !!meta-data #binary\n" + + assertEquals("--- !!meta-data #binary\n" + "csp: //path/service\n" + "tid: 123456789\n" + "# position: 32, header: 0\n" + @@ -341,8 +340,7 @@ public void testSequence() { @NotNull Wire twire = WireType.TEXT.apply(allocateElasticOnHeap()); writeMessage(twire); - assertEquals("" + - "--- !!meta-data\n" + + assertEquals("--- !!meta-data\n" + "csp: //path/service\n" + "tid: 123456789\n" + "# position: 40, header: 0\n" + @@ -389,8 +387,7 @@ public void testSequenceContext() { writeMessageContext(wire); // Expected binary hex representation of the written data - assertEquals("" + - "1c 00 00 40 # msg-length\n" + + assertEquals("1c 00 00 40 # msg-length\n" + "c3 63 73 70 # csp:\n" + "ee 2f 2f 70 61 74 68 2f 73 65 72 76 69 63 65 # //path/service\n" + "c3 74 69 64 # tid:\n" + @@ -414,8 +411,7 @@ public void testSequenceContext() { writeMessageContext(twire); // Expected textual representation of the written data - assertEquals("" + - "--- !!meta-data\n" + + assertEquals("--- !!meta-data\n" + "csp: //path/service\n" + "tid: 123456789\n" + "# position: 39, header: 0\n" + @@ -541,8 +537,7 @@ public void fieldAfterNullContext() { } // Validate the serialized format of the entire wire content, including metadata and data - assertEquals("" + - "--- !!meta-data #binary\n" + + assertEquals("--- !!meta-data #binary\n" + "tid: 1234567890\n" + "# position: 1X, header: 0\n" + "--- !!data #binary\n" + @@ -763,8 +758,7 @@ public void testByteArray() { wire.writeDocument(false, w -> w.write("four").object(thirtytwo)); final String expected = usePadding ? - "" + - "--- !!data #binary\n" + + "--- !!data #binary\n" + "nothing: !byte[] \"\"\n" + "# position: 24, header: 1\n" + "--- !!data #binary\n" + @@ -772,8 +766,7 @@ public void testByteArray() { "# position: 44, header: 2\n" + "--- !!data #binary\n" + "four: !byte[] \"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\a\\b\\t\\n\\v\\f\\r\\x0E\\x0F\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1A\\e\\x1C\\x1D\\x1E\\x1F \"\n" : - "" + - "--- !!data #binary\n" + + "--- !!data #binary\n" + "nothing: !byte[] \"\"\n" + "# position: 23, header: 1\n" + "--- !!data #binary\n" + @@ -804,8 +797,8 @@ public void testObjectKeys() { "? { MyField: parent }: {\n" + " ? !net.openhft.chronicle.wire.MyMarshallable { MyField: key1 }: value1,\n" + " ? !net.openhft.chronicle.wire.MyMarshallable { MyField: key2 }: value2\n" + - "}\n" - , Wires.fromSizePrefixedBlobs(wire.bytes())); + "}\n", + Wires.fromSizePrefixedBlobs(wire.bytes())); // Read the document from the wire and check the values wire.readDocument(null, w -> { @@ -890,8 +883,7 @@ private void doTestUnicodeReadAndWrite() { // "e4 bd a0 e5 a5 bd c5 76 61 6c 75 65 0f\n", bytes.toHexString()); // Ensure that the wire's content matches the expected format with the Chinese characters - assertEquals("" + - "--- !!data #binary\n" + + assertEquals("--- !!data #binary\n" + "data: !!UpdateEvent {\n" + " mm: \"\\u4F60\\u597D\",\n" + " value: 15\n" + @@ -923,7 +915,7 @@ public void testWriteMap() { wire.bytes().releaseLast(); // Release the resources } -// This test is designed to check if the wire correctly reads a Bytes object from a marshallable representation. + // This test is designed to check if the wire correctly reads a Bytes object from a marshallable representation. @Test public void testreadBytes() { // Create a new BinaryWire with heap allocated storage diff --git a/src/test/java/net/openhft/chronicle/wire/BinaryWireNumbersTest.java b/src/test/java/net/openhft/chronicle/wire/BinaryWireNumbersTest.java index 103e5ddd3d..4d4c113a33 100644 --- a/src/test/java/net/openhft/chronicle/wire/BinaryWireNumbersTest.java +++ b/src/test/java/net/openhft/chronicle/wire/BinaryWireNumbersTest.java @@ -16,6 +16,7 @@ import static org.junit.Assert.assertEquals; @RunWith(value = Parameterized.class) +@SuppressWarnings({"deprecation", "removal"}) public class BinaryWireNumbersTest extends WireTestCommon { private static final float VAL1 = 12345678901234567.0f; private static int counter = 0; diff --git a/src/test/java/net/openhft/chronicle/wire/BinaryWirePerfTest.java b/src/test/java/net/openhft/chronicle/wire/BinaryWirePerfTest.java index aede55a590..97c2388e3d 100644 --- a/src/test/java/net/openhft/chronicle/wire/BinaryWirePerfTest.java +++ b/src/test/java/net/openhft/chronicle/wire/BinaryWirePerfTest.java @@ -26,7 +26,7 @@ public class BinaryWirePerfTest extends WireTestCommon { private final boolean numericField; private final boolean fieldLess; @NotNull - private + private final Bytes bytes = allocateElasticOnHeap(); // Constructor for parameterized test diff --git a/src/test/java/net/openhft/chronicle/wire/BinaryWireReadWithLengthTest.java b/src/test/java/net/openhft/chronicle/wire/BinaryWireReadWithLengthTest.java index d94d1b8d30..987d48fa2b 100644 --- a/src/test/java/net/openhft/chronicle/wire/BinaryWireReadWithLengthTest.java +++ b/src/test/java/net/openhft/chronicle/wire/BinaryWireReadWithLengthTest.java @@ -6,6 +6,7 @@ import net.openhft.chronicle.bytes.Bytes; import org.junit.Test; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** @@ -89,6 +90,6 @@ public void copyMessagesIndividually() { source.copyOne(textWire); String first = textWire.bytes().toString(); - assertTrue(first.length() > 0); + assertFalse(first.isEmpty()); } } diff --git a/src/test/java/net/openhft/chronicle/wire/BinaryWireStringInternerTest.java b/src/test/java/net/openhft/chronicle/wire/BinaryWireStringInternerTest.java index 5ea10c315a..0ee0e96f76 100644 --- a/src/test/java/net/openhft/chronicle/wire/BinaryWireStringInternerTest.java +++ b/src/test/java/net/openhft/chronicle/wire/BinaryWireStringInternerTest.java @@ -64,7 +64,7 @@ public void threadDump() { // Prepares test data before the test runs @Before - public void createTestData() throws Exception { + public void createTestData() { // Populate testData with random strings for (int i = 0; i < DATA_SET_SIZE; i++) { testData[i] = makeString(random.nextInt(250) + 32, random); @@ -167,19 +167,17 @@ public void multipleThreadsSharingBinaryWireShouldCauseProblems() throws Excepti // Runnable class to read/write from/to BinaryWire private static final class BinaryTextReaderWriter implements Runnable { - private final Supplier binaryWireSupplier; private final ThreadLocal wire; private final Random random = new Random(System.nanoTime()); private final Consumer exceptionConsumer; private BinaryTextReaderWriter(final Consumer exceptionConsumer, - final Supplier binaryWireSupplier) throws IOException { + final Supplier binaryWireSupplier) { this.exceptionConsumer = exceptionConsumer; - this.binaryWireSupplier = binaryWireSupplier; // Each thread gets its own BinaryWire instance wire = ThreadLocal.withInitial( - this.binaryWireSupplier); + binaryWireSupplier); } @Override diff --git a/src/test/java/net/openhft/chronicle/wire/BinaryWireTest.java b/src/test/java/net/openhft/chronicle/wire/BinaryWireTest.java index 4af4f10948..1037a8cb0c 100644 --- a/src/test/java/net/openhft/chronicle/wire/BinaryWireTest.java +++ b/src/test/java/net/openhft/chronicle/wire/BinaryWireTest.java @@ -38,6 +38,7 @@ import static org.junit.Assume.assumeFalse; @RunWith(value = Parameterized.class) +@SuppressWarnings({"deprecation", "removal"}) public class BinaryWireTest extends WireTestCommon { private final int testId; @@ -46,8 +47,7 @@ public class BinaryWireTest extends WireTestCommon { private final boolean fieldLess; private final int compressedSize; @NotNull - private - Bytes bytes = new HexDumpBytes(); + private final Bytes bytes = new HexDumpBytes(); // Constructor for initializing parameters of the test public BinaryWireTest(int testId, boolean fixed, boolean numericField, boolean fieldLess, int compressedSize) { @@ -88,24 +88,19 @@ public void testWrite() { wire.write(); // Check the expected wire output against actual wire representation - checkWire(wire, "" + - "c0 # :\n" + + checkWire(wire, "c0 # :\n" + "c0 # :\n" + "c0 # :\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "c0 # :\n" + "c0 # :\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "c0 # :\n" + "c0 # :\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "c0 # :\n" + "c0 # :\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "c0 # :\n" + "c0 # :\n", "", @@ -164,24 +159,19 @@ public void testWrite1() { wire.write(BWKey.field3); // Check the expected wire output against actual wire representation - checkWire(wire, "" + - "c6 66 69 65 6c 64 31 # field1:\n" + + checkWire(wire, "c6 66 69 65 6c 64 31 # field1:\n" + "c6 66 69 65 6c 64 32 # field2:\n" + "c6 66 69 65 6c 64 33 # field3:\n", - "" + - "c6 66 69 65 6c 64 31 # field1:\n" + + "c6 66 69 65 6c 64 31 # field1:\n" + "c6 66 69 65 6c 64 32 # field2:\n" + "c6 66 69 65 6c 64 33 # field3:\n", - "" + - "c6 66 69 65 6c 64 31 # field1:\n" + + "c6 66 69 65 6c 64 31 # field1:\n" + "c6 66 69 65 6c 64 32 # field2:\n" + "c6 66 69 65 6c 64 33 # field3:\n", - "" + - "ba 01 # 1\n" + + "ba 01 # 1\n" + "ba 02 # 2\n" + "ba 03 # 3\n", - "" + - "ba 01 # 1\n" + + "ba 01 # 1\n" + "ba 02 # 2\n" + "ba 03 # 3\n", "", @@ -220,33 +210,28 @@ public void testWrite2() { wire.write(() -> name); // Check the wire's byte representation against expected values - checkWire(wire, "" + - "c5 48 65 6c 6c 6f # Hello:\n" + + checkWire(wire, "c5 48 65 6c 6c 6f # Hello:\n" + "c5 57 6f 72 6c 64 # World:\n" + "b7 35 4c 6f 6e 67 20 66 69 65 6c 64 20 6e 61 6d # Long field name which is more than 32 characters, Bye:\n" + "65 20 77 68 69 63 68 20 69 73 20 6d 6f 72 65 20\n" + "74 68 61 6e 20 33 32 20 63 68 61 72 61 63 74 65\n" + "72 73 2c 20 42 79 65\n", - "" + - "c5 48 65 6c 6c 6f # Hello:\n" + + "c5 48 65 6c 6c 6f # Hello:\n" + "c5 57 6f 72 6c 64 # World:\n" + "b7 35 4c 6f 6e 67 20 66 69 65 6c 64 20 6e 61 6d # Long field name which is more than 32 characters, Bye:\n" + "65 20 77 68 69 63 68 20 69 73 20 6d 6f 72 65 20\n" + "74 68 61 6e 20 33 32 20 63 68 61 72 61 63 74 65\n" + "72 73 2c 20 42 79 65\n", - "" + - "c5 48 65 6c 6c 6f # Hello:\n" + + "c5 48 65 6c 6c 6f # Hello:\n" + "c5 57 6f 72 6c 64 # World:\n" + "b7 35 4c 6f 6e 67 20 66 69 65 6c 64 20 6e 61 6d # Long field name which is more than 32 characters, Bye:\n" + "65 20 77 68 69 63 68 20 69 73 20 6d 6f 72 65 20\n" + "74 68 61 6e 20 33 32 20 63 68 61 72 61 63 74 65\n" + "72 73 2c 20 42 79 65\n", - "" + - "ba b2 d1 98 21 # 69609650\n" + + "ba b2 d1 98 21 # 69609650\n" + "ba f2 d6 f8 27 # 83766130\n" + "ba b4 cd fd e5 83 00 # -1019176629\n", - "" + - "ba b2 d1 98 21 # 69609650\n" + + "ba b2 d1 98 21 # 69609650\n" + "ba f2 d6 f8 27 # 83766130\n" + "ba b4 cd fd e5 83 00 # -1019176629\n", "", @@ -348,47 +333,40 @@ public void int8() { wire.write(() -> "Test").int8((byte) 3); // Checking the wire's current byte representation - checkWire(wire, "" + - "c0 # :\n" + + checkWire(wire, "c0 # :\n" + "a1 01 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a1 02 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a1 01 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a1 02 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a4 01 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a4 02 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a4 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a1 01 # 1\n" + "ba 01 # 1\n" + "a1 02 # 2\n" + "ba b2 f1 9e 01 # 2603186\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a4 01 # 1\n" + "ba 01 # 1\n" + "a4 02 # 2\n" + "ba b2 f1 9e 01 # 2603186\n" + "a4 03 # 3\n", - "" + - "a1 01 # 1\n" + + "a1 01 # 1\n" + "a1 02 # 2\n" + "a1 03 # 3\n", - "" + - "a4 01 # 1\n" + + "a4 01 # 1\n" + "a4 02 # 2\n" + "a4 03 # 3\n" ); @@ -467,47 +445,40 @@ public void int16() { wire.write(() -> "Test").int16((short) 3); // Validate the Wire content against different representations. - checkWire(wire, "" + - "c0 # :\n" + + checkWire(wire, "c0 # :\n" + "a1 01 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a1 02 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a1 01 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a1 02 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a5 01 00 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a5 02 00 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a5 03 00 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a1 01 # 1\n" + "ba 01 # 1\n" + "a1 02 # 2\n" + "ba b2 f1 9e 01 # 2603186\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a5 01 00 # 1\n" + "ba 01 # 1\n" + "a5 02 00 # 2\n" + "ba b2 f1 9e 01 # 2603186\n" + "a5 03 00 # 3\n", - "" + - "a1 01 # 1\n" + + "a1 01 # 1\n" + "a1 02 # 2\n" + "a1 03 # 3\n", - "" + - "a5 01 00 # 1\n" + + "a5 01 00 # 1\n" + "a5 02 00 # 2\n" + "a5 03 00 # 3\n"); checkAsText123(wire, fixed ? "!short " : ""); @@ -538,47 +509,40 @@ public void uint8() { wire.write(() -> "Test").uint8(3); // Validate the content of the Wire against multiple representations. - checkWire(wire, "" + - "c0 # :\n" + + checkWire(wire, "c0 # :\n" + "a1 01 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a1 02 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a1 01 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a1 02 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a1 01 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a1 02 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a1 01 # 1\n" + "ba 01 # 1\n" + "a1 02 # 2\n" + "ba b2 f1 9e 01 # 2603186\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a1 01 # 1\n" + "ba 01 # 1\n" + "a1 02 # 2\n" + "ba b2 f1 9e 01 # 2603186\n" + "a1 03 # 3\n", - "" + - "a1 01 # 1\n" + + "a1 01 # 1\n" + "a1 02 # 2\n" + "a1 03 # 3\n", - "" + - "a1 01 # 1\n" + + "a1 01 # 1\n" + "a1 02 # 2\n" + "a1 03 # 3\n"); // Check the textual representation of the Wire. @@ -610,47 +574,40 @@ public void uint16() { wire.write(() -> "Test").uint16(3); // Check the serialized format of the wire against expected values - checkWire(wire, "" + - "c0 # :\n" + + checkWire(wire, "c0 # :\n" + "a1 01 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a1 02 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a1 01 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a1 02 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a2 01 00 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a2 02 00 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a2 03 00 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a1 01 # 1\n" + "ba 01 # 1\n" + "a1 02 # 2\n" + "ba b2 f1 9e 01 # 2603186\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a2 01 00 # 1\n" + "ba 01 # 1\n" + "a2 02 00 # 2\n" + "ba b2 f1 9e 01 # 2603186\n" + "a2 03 00 # 3\n", - "" + - "a1 01 # 1\n" + + "a1 01 # 1\n" + "a1 02 # 2\n" + "a1 03 # 3\n", - "" + - "a2 01 00 # 1\n" + + "a2 01 00 # 1\n" + "a2 02 00 # 2\n" + "a2 03 00 # 3\n"); @@ -684,47 +641,40 @@ public void uint32() { wire.write(() -> "Test").uint32(3); // Check the serialized format of the wire against expected values - checkWire(wire, "" + - "c0 # :\n" + + checkWire(wire, "c0 # :\n" + "a1 01 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a1 02 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a1 01 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a1 02 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a3 01 00 00 00 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a3 02 00 00 00 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a3 03 00 00 00 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a1 01 # 1\n" + "ba 01 # 1\n" + "a1 02 # 2\n" + "ba b2 f1 9e 01 # 2603186\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a3 01 00 00 00 # 1\n" + "ba 01 # 1\n" + "a3 02 00 00 00 # 2\n" + "ba b2 f1 9e 01 # 2603186\n" + "a3 03 00 00 00 # 3\n", - "" + - "a1 01 # 1\n" + + "a1 01 # 1\n" + "a1 02 # 2\n" + "a1 03 # 3\n", - "" + - "a3 01 00 00 00 # 1\n" + + "a3 01 00 00 00 # 1\n" + "a3 02 00 00 00 # 2\n" + "a3 03 00 00 00 # 3\n"); @@ -756,47 +706,40 @@ public void int32() { wire.write(() -> "Test").int32(3); // Check the binary format of the written values - checkWire(wire, "" + - "c0 # :\n" + + checkWire(wire, "c0 # :\n" + "a1 01 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a1 02 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a1 01 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a1 02 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a6 01 00 00 00 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a6 02 00 00 00 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a6 03 00 00 00 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a1 01 # 1\n" + "ba 01 # 1\n" + "a1 02 # 2\n" + "ba b2 f1 9e 01 # 2603186\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a6 01 00 00 00 # 1\n" + "ba 01 # 1\n" + "a6 02 00 00 00 # 2\n" + "ba b2 f1 9e 01 # 2603186\n" + "a6 03 00 00 00 # 3\n", - "" + - "a1 01 # 1\n" + + "a1 01 # 1\n" + "a1 02 # 2\n" + "a1 03 # 3\n", - "" + - "a6 01 00 00 00 # 1\n" + + "a6 01 00 00 00 # 1\n" + "a6 02 00 00 00 # 2\n" + "a6 03 00 00 00 # 3\n"); checkAsText123(wire); @@ -824,47 +767,40 @@ public void int64() { wire.write(() -> "Test").int64(3); // Check the binary format of the written values - checkWire(wire, "" + - "c0 # :\n" + + checkWire(wire, "c0 # :\n" + "a1 01 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a1 02 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a1 01 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a1 02 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a7 01 00 00 00 00 00 00 00 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a7 02 00 00 00 00 00 00 00 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a7 03 00 00 00 00 00 00 00 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a1 01 # 1\n" + "ba 01 # 1\n" + "a1 02 # 2\n" + "ba b2 f1 9e 01 # 2603186\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a7 01 00 00 00 00 00 00 00 # 1\n" + "ba 01 # 1\n" + "a7 02 00 00 00 00 00 00 00 # 2\n" + "ba b2 f1 9e 01 # 2603186\n" + "a7 03 00 00 00 00 00 00 00 # 3\n", - "" + - "a1 01 # 1\n" + + "a1 01 # 1\n" + "a1 02 # 2\n" + "a1 03 # 3\n", - "" + - "a7 01 00 00 00 00 00 00 00 # 1\n" + + "a7 01 00 00 00 00 00 00 00 # 1\n" + "a7 02 00 00 00 00 00 00 00 # 2\n" + "a7 03 00 00 00 00 00 00 00 # 3\n"); checkAsText123(wire, ""); @@ -921,47 +857,40 @@ public void float64() { wire.write(() -> "Test").float64(3); // Check Wire contents against predefined representations - checkWire(wire, "" + - "c0 # :\n" + + checkWire(wire, "c0 # :\n" + "a1 01 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a1 02 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a1 01 # 1\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "a1 02 # 2\n" + "c4 54 65 73 74 # Test:\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "91 00 00 00 00 00 00 f0 3f # 1.0\n" + "c6 66 69 65 6c 64 31 # field1:\n" + "91 00 00 00 00 00 00 00 40 # 2.0\n" + "c4 54 65 73 74 # Test:\n" + "91 00 00 00 00 00 00 08 40 # 3.0\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "a1 01 # 1\n" + "ba 01 # 1\n" + "a1 02 # 2\n" + "ba b2 f1 9e 01 # 2603186\n" + "a1 03 # 3\n", - "" + - "c0 # :\n" + + "c0 # :\n" + "91 00 00 00 00 00 00 f0 3f # 1.0\n" + "ba 01 # 1\n" + "91 00 00 00 00 00 00 00 40 # 2.0\n" + "ba b2 f1 9e 01 # 2603186\n" + "91 00 00 00 00 00 00 08 40 # 3.0\n", - "" + - "a1 01 # 1\n" + + "a1 01 # 1\n" + "a1 02 # 2\n" + "a1 03 # 3\n", - "" + - "91 00 00 00 00 00 00 f0 3f # 1.0\n" + + "91 00 00 00 00 00 00 f0 3f # 1.0\n" + "91 00 00 00 00 00 00 00 40 # 2.0\n" + "91 00 00 00 00 00 00 08 40 # 3.0\n"); @@ -1140,8 +1069,7 @@ public void testTime() { // An assertion for byte representation, it seems to be related to some internal functionality // (the details of which would depend on the context in which this test is used) if (testId <= 4) { - assertEquals("" + - "c0 # :\n" + + assertEquals("c0 # :\n" + "b2 0c 31 32 3a 35 34 3a 30 34 2e 36 31 32 # 12:54:04.612\n" + "c0 # :\n" + "b2 12 32 33 3a 35 39 3a 35 39 2e 39 39 39 39 39 # 23:59:59.999999999\n" + @@ -1149,8 +1077,7 @@ public void testTime() { "b2 05 30 30 3a 30 30 # 00:00\n", bytes.toHexString()); } else { - assertEquals("" + - "b2 0c 31 32 3a 35 34 3a 30 34 2e 36 31 32 # 12:54:04.612\n" + + assertEquals("b2 0c 31 32 3a 35 34 3a 30 34 2e 36 31 32 # 12:54:04.612\n" + "b2 12 32 33 3a 35 39 3a 35 39 2e 39 39 39 39 39 # 23:59:59.999999999\n" + "39 39 39 39 b2 05 30 30 3a 30 30 # 00:00\n", bytes.toHexString()); @@ -1267,7 +1194,7 @@ public void testWriteMarshallable() { // BinaryWire.SPEC = 18; // Create a new wire instance. - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); // Initialize a MyTypesCustom instance (mtA) with specific values. @NotNull MyTypesCustom mtA = new MyTypesCustom(); @@ -1297,8 +1224,7 @@ public void testWriteMarshallable() { // Check the wire content against expected values. checkWire(wire, // Expected representation 1 - "" + - "c1 41 # A:\n" + + "c1 41 # A:\n" + "82 3f 00 00 00 # MyTypesCustom\n" + "c6 42 5f 46 4c 41 47 # B_FLAG:\n" + "b1 # true\n" + @@ -1327,8 +1253,7 @@ public void testWriteMarshallable() { "c4 54 45 58 54 # TEXT:\n" + "e7 42 79 65 20 6e 6f 77 # Bye now\n", // Expected representation 2 - "" + - "c1 41 # A:\n" + + "c1 41 # A:\n" + "82 3f 00 00 00 # MyTypesCustom\n" + "c6 42 5f 46 4c 41 47 # B_FLAG:\n" + "b1 # true\n" + @@ -1357,8 +1282,7 @@ public void testWriteMarshallable() { "c4 54 45 58 54 # TEXT:\n" + "e7 42 79 65 20 6e 6f 77 # Bye now\n", // Expected representation 3 - "" + - "c1 41 # A:\n" + + "c1 41 # A:\n" + "82 4b 00 00 00 # MyTypesCustom\n" + "c6 42 5f 46 4c 41 47 # B_FLAG:\n" + "b1 # true\n" + @@ -1387,8 +1311,7 @@ public void testWriteMarshallable() { "c4 54 45 58 54 # TEXT:\n" + "e7 42 79 65 20 6e 6f 77 # Bye now\n", // Expected representation 4 - "" + - "ba 41 # 65\n" + + "ba 41 # 65\n" + "82 27 00 00 00 # MyTypesCustom\n" + "ba 00 # 0\n" + "b1 # true\n" + @@ -1417,8 +1340,7 @@ public void testWriteMarshallable() { "ba 05 # 5\n" + "e7 42 79 65 20 6e 6f 77 # Bye now\n", // Expected representation 5 - "" + - "ba 41 # 65\n" + + "ba 41 # 65\n" + "82 33 00 00 00 # MyTypesCustom\n" + "ba 00 # 0\n" + "b1 # true\n" + @@ -1447,8 +1369,7 @@ public void testWriteMarshallable() { "ba 05 # 5\n" + "e7 42 79 65 20 6e 6f 77 # Bye now\n", // Expected representation 6 - "" + - "82 1b 00 00 00 # MyTypesCustom\n" + + "82 1b 00 00 00 # MyTypesCustom\n" + "b1 # true\n" + "a5 39 30 # 12345\n" + "94 80 ad 4b # 1234560/1e4\n" + @@ -1463,8 +1384,7 @@ public void testWriteMarshallable() { "a6 9e 2e a4 f8 # -123457890\n" + "e7 42 79 65 20 6e 6f 77 # Bye now\n", // Expected representation 7 - "" + - "82 27 00 00 00 # MyTypesCustom\n" + + "82 27 00 00 00 # MyTypesCustom\n" + "b1 # true\n" + "a5 39 30 # 12345\n" + "91 77 be 9f 1a 2f dd 5e 40 # 123.456\n" + @@ -1586,7 +1506,7 @@ public void testArrays2() { } @Test - public void testUsingEvents() throws Exception { + public void testUsingEvents() { // Creating a wire instance with binary format final Wire w = WireType.BINARY.apply(Bytes.allocateElasticOnHeap()); w.usePadding(true); @@ -1626,7 +1546,7 @@ public void testUsingEvents() throws Exception { @Test public void testSortedSet() { // Creating a wire instance and a sorted set of strings - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); @NotNull SortedSet set = new TreeSet<>(); set.add("one"); set.add("two"); @@ -1644,7 +1564,7 @@ public void testSortedSet() { @Test public void testSortedMap() { // Creating a wire instance and a sorted map - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); @NotNull SortedMap set = new TreeMap<>(); set.put("one", 1L); set.put("two", 2L); @@ -1701,7 +1621,7 @@ public void readsComment() { } // Reading using a method reader and processing the DTO - final MethodReader reader = wire.methodReader((IDTO) dto -> sb.append("dto: " + dto + "\n")); + final MethodReader reader = wire.methodReader((IDTO) dto -> sb.append("dto: ").append(dto).append("\n")); assertTrue(reader.readOne()); assertFalse(reader.readOne()); assertEquals("one\n" + @@ -1785,7 +1705,7 @@ interface IDTO { // A basic DTO class extending the self-describing marshallable class static class DTO extends SelfDescribingMarshallable { - String text; + final String text; DTO(String text) { this.text = text; @@ -1793,6 +1713,6 @@ static class DTO extends SelfDescribingMarshallable { } // A simple class representing a Circle - private class Circle implements Marshallable { + private static class Circle implements Marshallable { } } diff --git a/src/test/java/net/openhft/chronicle/wire/BinaryWireWithMappedBytesTest.java b/src/test/java/net/openhft/chronicle/wire/BinaryWireWithMappedBytesTest.java index 0700f33de0..8f09f8595e 100644 --- a/src/test/java/net/openhft/chronicle/wire/BinaryWireWithMappedBytesTest.java +++ b/src/test/java/net/openhft/chronicle/wire/BinaryWireWithMappedBytesTest.java @@ -23,6 +23,7 @@ /** * This class tests the behavior of BinaryWire with mapped bytes. */ +@SuppressWarnings({"deprecation", "removal"}) public class BinaryWireWithMappedBytesTest extends WireTestCommon { // Defines if the MappedFile should retain its contents diff --git a/src/test/java/net/openhft/chronicle/wire/CSVBytesMarshallableTest.java b/src/test/java/net/openhft/chronicle/wire/CSVBytesMarshallableTest.java index 0d4cc55da8..63057eb5be 100644 --- a/src/test/java/net/openhft/chronicle/wire/CSVBytesMarshallableTest.java +++ b/src/test/java/net/openhft/chronicle/wire/CSVBytesMarshallableTest.java @@ -14,10 +14,11 @@ import static net.openhft.chronicle.wire.Wires.acquireStringBuilderScoped; import static org.junit.Assert.assertEquals; +@SuppressWarnings({"deprecation", "removal"}) public class CSVBytesMarshallableTest extends WireTestCommon { // Bytes representing raw data for the tests - private Bytes bytes = Bytes.from( + private final Bytes bytes = Bytes.from( "1.09029,1.090305,EURUSD,2,1,EBS\n" + "1.50935,1.50936,GBPUSD,5,1,RTRS\n" + "1.0906,1.09065,EURCHF,3,1,EBS\n"); @@ -90,18 +91,15 @@ private void doTest(@NotNull WireType wt, boolean binary) { fxPrice.writeMarshallable(out); } - // System.out.println(); - // System.out.println(wt); - // System.out.println(binary ? bytes2.toHexString() : bytes2.toString()); - bytes2.releaseLast(); } } + /** * Class representing a foreign exchange price. * Implements the BytesMarshallable interface to support reading and writing of its values from/to bytes. */ -@SuppressWarnings("rawtypes") +@SuppressWarnings({"rawtypes", "deprecation", "removal"}) class FXPrice implements BytesMarshallable { // Fields to store price data and related attributes private double bidprice; @@ -109,9 +107,7 @@ class FXPrice implements BytesMarshallable { //enum private CcyPair pair; private int size; - private byte level; private String exchangeName; - private transient double midPrice; /** * Reads the object's data from bytes. @@ -124,9 +120,9 @@ public void readMarshallable(@NotNull BytesIn bytes) { offerprice = bytes.parseDouble(); pair = parseEnum(bytes, CcyPair.INTERNER); size = Maths.toInt32(bytes.parseLong()); - level = Maths.toInt8(bytes.parseLong()); + byte level = Maths.toInt8(bytes.parseLong()); exchangeName = bytes.parseUtf8(StopCharTesters.COMMA_STOP); - midPrice = (bidprice + offerprice) / 2; + double midPrice = (bidprice + offerprice) / 2; } /** @@ -146,7 +142,7 @@ public void writeMarshallable(@NotNull BytesOut bytes) { /** * Helper method to parse an enum from bytes using an interner. * - * @param bytes Source bytes + * @param bytes Source bytes * @param interner The enum interner to use for parsing * @return Parsed enum value */ @@ -158,11 +154,14 @@ private > T parseEnum(@NotNull BytesIn bytes, @NotNull Enum } } } + /** * Class representing a foreign exchange price. * Implements the Marshallable interface to support reading and writing of its values using the Wire format. */ +@SuppressWarnings({"deprecation", "removal"}) class FXPrice2 implements Marshallable { + public transient double midPrice; // Fields to store price data and related attributes private double bidprice; private double offerprice; @@ -171,7 +170,6 @@ class FXPrice2 implements Marshallable { private int size; private byte level; private String exchangeName; - public transient double midPrice; /** * Reads the object's data using the Wire format. diff --git a/src/test/java/net/openhft/chronicle/wire/CSVWireTest.java b/src/test/java/net/openhft/chronicle/wire/CSVWireTest.java index 244ef37cd9..645faf5d1b 100644 --- a/src/test/java/net/openhft/chronicle/wire/CSVWireTest.java +++ b/src/test/java/net/openhft/chronicle/wire/CSVWireTest.java @@ -10,6 +10,7 @@ import static org.junit.Assert.*; // CSVWireTest class extends from WireTestCommon and tests functionality related to CSV-based wire processing. +@SuppressWarnings({"deprecation", "removal"}) public class CSVWireTest extends WireTestCommon { // Test parsing a CSV string into a wire and reading its contents. diff --git a/src/test/java/net/openhft/chronicle/wire/ChronicleBitSetTest.java b/src/test/java/net/openhft/chronicle/wire/ChronicleBitSetTest.java index 53d45e10a4..a43a4c10d9 100644 --- a/src/test/java/net/openhft/chronicle/wire/ChronicleBitSetTest.java +++ b/src/test/java/net/openhft/chronicle/wire/ChronicleBitSetTest.java @@ -10,7 +10,6 @@ import org.jetbrains.annotations.NotNull; import org.junit.Assert; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -35,13 +34,6 @@ public class ChronicleBitSetTest extends WireTestCommon { private final ChronicleBitSet emptyBS127; private final ChronicleBitSet emptyBS128; - // Capture a snapshot of all threads before test execution - @Override - @Before - public void threadDump() { - super.threadDump(); - } - @SuppressWarnings("this-escape") public ChronicleBitSetTest(Class clazz) { assumeTrue(Jvm.is64bit()); @@ -52,10 +44,6 @@ public ChronicleBitSetTest(Class clazz) { emptyBS128 = createBitSet(128); } - // Helper method to assume certain conditions for the test - private void assumeTrue(boolean bit) { - } - // Test data provider @NotNull @Parameterized.Parameters(name = "{0}") @@ -67,6 +55,17 @@ public static Collection data() { }); } + // Capture a snapshot of all threads before test execution + @Override + @Before + public void threadDump() { + super.threadDump(); + } + + // Helper method to assume certain conditions for the test + private void assumeTrue(boolean bit) { + } + // Cleanup resources after test @Override protected void preAfter() { @@ -129,7 +128,7 @@ private void check(boolean condition, String diagnostic) { // Check if the ChronicleBitSet is empty private void checkEmpty(ChronicleBitSet s) { check(s.isEmpty(), "isEmpty"); - check(s.length() == 0, "length"); + check(s.isEmpty(), "length"); check(s.cardinality() == 0, "cardinality"); // Comparing with different empty ChronicleBitSets check(s.equals(emptyBS0), "equals"); @@ -300,14 +299,14 @@ public void testSetGetClearFlip() { Iterator setBitIterator = history.iterator(); while (setBitIterator.hasNext()) { Integer setBit = setBitIterator.next(); - testSet.clear(setBit.intValue()); + testSet.clear(setBit); } // Verify they were cleared for (int x = 0; x < highestPossibleSetBit; x++) if (testSet.get(x)) failCount++; - if (testSet.length() != 0) + if (!testSet.isEmpty()) failCount++; // Set them with set(int, boolean) @@ -334,7 +333,7 @@ public void testSetGetClearFlip() { for (int x = 0; x < highestPossibleSetBit; x++) if (testSet.get(x)) failCount++; - if (testSet.length() != 0) + if (!testSet.isEmpty()) failCount++; // Flip them on @@ -361,7 +360,7 @@ public void testSetGetClearFlip() { for (int x = 0; x < highestPossibleSetBit; x++) if (testSet.get(x)) failCount++; - if (testSet.length() != 0) + if (!testSet.isEmpty()) failCount++; checkSanity(testSet); @@ -445,8 +444,6 @@ public void testAnd() { @Test public void testAnd2() { - int failCount = 0; - // Test the AND operation that clears the last word of the bitset ChronicleBitSet b4 = makeSet(2, 127); assertEquals("{2, 127}", b4.toString()); @@ -455,6 +452,7 @@ public void testAnd2() { b4.and(b4a); assertEquals("{2}", b4.toString()); checkSanity(b4); + int failCount = 0; final ChronicleBitSet bs2 = makeSet(2); if (!(b4.equals(bs2))) { failCount++; @@ -616,11 +614,11 @@ public void testLength() { int rangeEnd = rangeStart + generator.nextInt(100); b1.flip(rangeStart); b1.flip(rangeStart); - if (b1.length() != 0) + if (!b1.isEmpty()) failCount++; b1.flip(rangeStart, rangeEnd); b1.flip(rangeStart, rangeEnd); - if (b1.length() != 0) + if (!b1.isEmpty()) failCount++; } checkSanity(b1); @@ -812,45 +810,6 @@ public void testFlip() { assertEquals(0, failCount); } -/* @Test - public void testGet() { - int failCount = 0; - - for (int i = 0; i < 1000; i++) { - ChronicleBitSet b1 = createBitSet(); - - // Make a fairly random ChronicleBitSet - int numberOfSetBits = generator.nextInt(100) + 1; - int highestPossibleSetBit = generator.nextInt(1000) + 1; - - for (int x = 0; x < numberOfSetBits; x++) - b1.set(generator.nextInt(highestPossibleSetBit)); - - // Get a new set from a random range - int rangeStart = generator.nextInt(100); - int rangeEnd = rangeStart + generator.nextInt(100); - - ChronicleBitSet b2 = b1.get(rangeStart, rangeEnd); - - ChronicleBitSet b3 = createBitSet(); - for (int x = rangeStart; x < rangeEnd; x++) - b3.set(x - rangeStart, b1.get(x)); - - // Verify their equality - if (!b2.equals(b3)) { - System.out.println("start=" + rangeStart); - System.out.println("end=" + rangeEnd); - System.out.println(b1); - System.out.println(b2); - System.out.println(b3); - failCount++; - } - checkEquality(b2, b3); - } - - assertEquals(0, failCount); - }*/ - @Test public void testIntersects() { int failCount = 0; @@ -1145,6 +1104,7 @@ public void testLogicalIdentities() { /** * Clone the provided ChronicleBitSet using its size. + * * @param b1 the ChronicleBitSet to clone. * @return the cloned ChronicleBitSet. */ @@ -1154,7 +1114,8 @@ private ChronicleBitSet cloneBitSet(ChronicleBitSet b1) { /** * Clone the provided ChronicleBitSet with the given size. - * @param b1 the ChronicleBitSet to clone. + * + * @param b1 the ChronicleBitSet to clone. * @param size the size for the new cloned ChronicleBitSet. * @return the cloned ChronicleBitSet. */ @@ -1169,6 +1130,7 @@ private ChronicleBitSet cloneBitSet(ChronicleBitSet b1, int size) { /** * Create a new ChronicleBitSet with default size of 1024. + * * @return the new ChronicleBitSet. */ private ChronicleBitSet createBitSet() { @@ -1179,6 +1141,7 @@ private ChronicleBitSet createBitSet() { /** * Create a new ChronicleBitSet with the specified size. + * * @param bits the size for the new ChronicleBitSet. * @return the new ChronicleBitSet. */ @@ -1193,7 +1156,8 @@ private ChronicleBitSet createBitSet(long bits) { /** * Create a ChronicleBitSet using the provided Wire and size. * This method uses reflection to instantiate the ChronicleBitSet. - * @param w the Wire for the new ChronicleBitSet. + * + * @param w the Wire for the new ChronicleBitSet. * @param size the size for the new ChronicleBitSet. * @return the new ChronicleBitSet. */ diff --git a/src/test/java/net/openhft/chronicle/wire/ClassAliasPoolTest.java b/src/test/java/net/openhft/chronicle/wire/ClassAliasPoolTest.java index 852296f199..41e6784956 100644 --- a/src/test/java/net/openhft/chronicle/wire/ClassAliasPoolTest.java +++ b/src/test/java/net/openhft/chronicle/wire/ClassAliasPoolTest.java @@ -46,7 +46,7 @@ public boolean matches(Object argument) { @Override public void appendTo(StringBuffer buffer) { - buffer.append("charSequence(\"" + text + "\")"); + buffer.append("charSequence(\"").append(text).append("\")"); } }); return null; diff --git a/src/test/java/net/openhft/chronicle/wire/CopyTest.java b/src/test/java/net/openhft/chronicle/wire/CopyTest.java index a208ecafcf..7234f7eae1 100644 --- a/src/test/java/net/openhft/chronicle/wire/CopyTest.java +++ b/src/test/java/net/openhft/chronicle/wire/CopyTest.java @@ -23,7 +23,7 @@ public class CopyTest extends WireTestCommon { private final WireType from, to; // Determines if the test uses the type information while copying - private boolean withType; + private final boolean withType; // Constructor to initialize wire types and whether the test runs with type information public CopyTest(WireType from, WireType to, boolean withType) { diff --git a/src/test/java/net/openhft/chronicle/wire/DMNestedClass.java b/src/test/java/net/openhft/chronicle/wire/DMNestedClass.java index 2874bd34da..1fa358f25c 100644 --- a/src/test/java/net/openhft/chronicle/wire/DMNestedClass.java +++ b/src/test/java/net/openhft/chronicle/wire/DMNestedClass.java @@ -3,11 +3,14 @@ */ package net.openhft.chronicle.wire; +import net.openhft.chronicle.core.annotation.UsedViaReflection; + /** * This class acts as a nested data structure * which is self-describing, enabling simplified marshalling and unmarshalling * while interacting with byte streams or while serialization. */ +@UsedViaReflection class DMNestedClass extends SelfDescribingMarshallable { // A string attribute to hold textual data within the instance of DMNestedClass. diff --git a/src/test/java/net/openhft/chronicle/wire/DMOuterClass.java b/src/test/java/net/openhft/chronicle/wire/DMOuterClass.java index 0a8bc0ebd8..1a763ab779 100644 --- a/src/test/java/net/openhft/chronicle/wire/DMOuterClass.java +++ b/src/test/java/net/openhft/chronicle/wire/DMOuterClass.java @@ -3,6 +3,7 @@ */ package net.openhft.chronicle.wire; +import net.openhft.chronicle.core.annotation.UsedViaReflection; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -17,6 +18,7 @@ * This outer class also holds instances of a nested class, and demonstrates * the handling of various data types and structures. */ +@UsedViaReflection class DMOuterClass extends SelfDescribingMarshallable { // String attribute to store textual data in an instance of DMOuterClass. diff --git a/src/test/java/net/openhft/chronicle/wire/DefaultMarshallerTest.java b/src/test/java/net/openhft/chronicle/wire/DefaultMarshallerTest.java index d4da3c7d9f..c804cd13ae 100644 --- a/src/test/java/net/openhft/chronicle/wire/DefaultMarshallerTest.java +++ b/src/test/java/net/openhft/chronicle/wire/DefaultMarshallerTest.java @@ -110,7 +110,7 @@ public void testDeserialize() { enum NestedEnum { ONE, TWO, - THREE; + THREE } // Defining a class with an embedded array diff --git a/src/test/java/net/openhft/chronicle/wire/DefaultValueInCoverageTest.java b/src/test/java/net/openhft/chronicle/wire/DefaultValueInCoverageTest.java index b55ada6638..83501d3aae 100644 --- a/src/test/java/net/openhft/chronicle/wire/DefaultValueInCoverageTest.java +++ b/src/test/java/net/openhft/chronicle/wire/DefaultValueInCoverageTest.java @@ -3,16 +3,17 @@ */ package net.openhft.chronicle.wire; -import net.openhft.chronicle.bytes.*; +import net.openhft.chronicle.bytes.Bytes; +import net.openhft.chronicle.bytes.PointerBytesStore; import net.openhft.chronicle.bytes.ref.BinaryLongArrayReference; import net.openhft.chronicle.core.io.InvalidMarshallableException; import org.junit.Test; -import java.nio.charset.StandardCharsets; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; +import static java.nio.charset.StandardCharsets.ISO_8859_1; import static org.junit.Assert.*; public class DefaultValueInCoverageTest extends WireTestCommon { @@ -28,7 +29,7 @@ public void handlesBytesPointerAndBooleanBranches() { assertEquals(0, pointer.safeLimit()); Bytes direct = Bytes.allocateDirect(32); - direct.write("hi".getBytes(StandardCharsets.ISO_8859_1)); + direct.write("hi".getBytes(ISO_8859_1)); valueIn.defaultValue = direct.bytesStore(); valueIn.bytesSet(pointer); assertTrue("pointer should point at direct store", pointer.safeLimit() >= 2); @@ -61,7 +62,7 @@ public void suppliesDefaultValuesAcrossReaders() throws InvalidMarshallableExcep valueIn.bytes(sink); byte[] out = new byte[(int) sink.readRemaining()]; sink.read(out); - assertArrayEquals("data".getBytes(StandardCharsets.ISO_8859_1), out); + assertArrayEquals("data".getBytes(ISO_8859_1), out); data.releaseLast(); sink.releaseLast(); } @@ -77,7 +78,7 @@ public void sequenceAndMarshallableDelegatesInvocations() { assertSame(valueIn, seen.get()); AtomicReference> marshallable = new AtomicReference<>(); - valueIn.bytes((ReadBytesMarshallable) bytesIn -> marshallable.set(bytesIn.bytesForRead())); + valueIn.bytes(bytesIn -> marshallable.set(bytesIn.bytesForRead())); // Identity of the returned Bytes view is not guaranteed; verify emptiness instead assertNotNull(marshallable.get()); assertEquals(0L, marshallable.get().readRemaining()); diff --git a/src/test/java/net/openhft/chronicle/wire/DocumentContextLifecycleTest.java b/src/test/java/net/openhft/chronicle/wire/DocumentContextLifecycleTest.java index 618b6fa9e4..2e7690a545 100644 --- a/src/test/java/net/openhft/chronicle/wire/DocumentContextLifecycleTest.java +++ b/src/test/java/net/openhft/chronicle/wire/DocumentContextLifecycleTest.java @@ -62,4 +62,27 @@ public void textUseTextDocumentsLifecycle() { } assertTrue(w.writingIsComplete()); } + + @Test + public void rollbackKeepsDocumentAvailableForNextRead() { + Wire w = WireType.BINARY.apply(Bytes.allocateElasticOnHeap(256)); + try (DocumentContext dc = w.writingDocument()) { + dc.wire().write("item").text("value"); + } + + try (DocumentContext dc = w.readingDocument()) { + assertTrue(dc.isPresent()); + dc.rollbackOnClose(); + } + + try (DocumentContext dc = w.readingDocument()) { + assertTrue("document should still be present after rollback", dc.isPresent()); + assertEquals("value", dc.wire().read("item").text()); + } + + try (DocumentContext dc = w.readingDocument()) { + assertFalse(dc.isPresent()); + } + w.bytes().releaseLast(); + } } diff --git a/src/test/java/net/openhft/chronicle/wire/DoubleTest.java b/src/test/java/net/openhft/chronicle/wire/DoubleTest.java index b90b967764..741017e95f 100644 --- a/src/test/java/net/openhft/chronicle/wire/DoubleTest.java +++ b/src/test/java/net/openhft/chronicle/wire/DoubleTest.java @@ -20,21 +20,15 @@ // Class to test the serialization and deserialization of double values. public class DoubleTest extends WireTestCommon { - // DTO representing two double values. - private static class TwoDoubleDto extends SelfDescribingMarshallable { - double price; - double qty; - } - @Before public void hasDirect() { assumeFalse(Jvm.maxDirectMemory() == 0); } /** - * relates to https://github.com/OpenHFT/Chronicle-Wire/issues/299 Fixed case where a serializable 'double' value sometimes has trailing zero + * relates to https://github.com/OpenHFT/Chronicle-Wire/issues/299 Fixed case where a serialisable 'double' value sometimes has a trailing zero. */ - // Test the serialization format of two double values without trailing zeros. + // Test the serialisation format of two double values without trailing zeros. @Test public void testParsingForTwoDoubles() { CLASS_ALIASES.addAlias(TwoDoubleDto.class); @@ -69,4 +63,10 @@ public void testManyDoubles() { } bytes.releaseLast(); } + + // DTO representing two double values. + private static class TwoDoubleDto extends SelfDescribingMarshallable { + double price; + double qty; + } } diff --git a/src/test/java/net/openhft/chronicle/wire/EgMain.java b/src/test/java/net/openhft/chronicle/wire/EgMain.java index 83af870e8a..0b6d810954 100644 --- a/src/test/java/net/openhft/chronicle/wire/EgMain.java +++ b/src/test/java/net/openhft/chronicle/wire/EgMain.java @@ -8,26 +8,17 @@ // Main class illustrating event time serialization and performance measurement of time provision. public class EgMain { - // Nested class representing an event with a timestamp. - static class Event extends SelfDescribingMarshallable { - // Convert the long timestamp to nano-time format. - @LongConversion(NanoTimestampLongConverter.class) - long time; - } - - private static long time; - public static void main(String[] args) { // Create a time provider for a specific host ID. DistributedUniqueTimeProvider tp = DistributedUniqueTimeProvider.forHostId(28); Event e = new Event(); e.time = tp.currentTimeNanos(); - // Sample serialized format of the event. -/* -!net.openhft.chronicle.wire.EgMain$Event { - time: 2021-12-28T14:07:02.954100128 -} -*/ + // Sample serialised format of the event. + /* + !net.openhft.chronicle.wire.EgMain$Event { + time: 2021-12-28T14:07:02.954100128 + } + */ String str = e.toString(); Event e2 = Marshallable.fromString(str); System.out.println(e2); @@ -36,10 +27,18 @@ public static void main(String[] args) { for (int t = 0; t < 3; t++) { long start = System.nanoTime(); int runs = 10000000; + long time; for (int i = 0; i < runs; i++) time = tp.currentTimeNanos(); long delay = (System.nanoTime() - start) / runs; System.out.println(delay); } } + + // Nested class representing an event with a timestamp. + static class Event extends SelfDescribingMarshallable { + // Convert the long timestamp to nano-time format. + @LongConversion(NanoTimestampLongConverter.class) + long time; + } } diff --git a/src/test/java/net/openhft/chronicle/wire/ElasticByteBufferTest.java b/src/test/java/net/openhft/chronicle/wire/ElasticByteBufferTest.java index 3622210e65..d42d11289a 100644 --- a/src/test/java/net/openhft/chronicle/wire/ElasticByteBufferTest.java +++ b/src/test/java/net/openhft/chronicle/wire/ElasticByteBufferTest.java @@ -11,12 +11,19 @@ import org.junit.Test; import java.nio.ByteBuffer; +import java.util.Arrays; import static org.junit.Assume.assumeFalse; // Test class focusing on the functionality of elastic byte buffers with wire operations. public class ElasticByteBufferTest extends WireTestCommon { + private static String repeat(char ch, int length) { + char[] data = new char[length]; + Arrays.fill(data, ch); + return new String(data); + } + @Test public void testElasticByteBufferWithWire() { assumeFalse(Jvm.maxDirectMemory() == 0); @@ -45,4 +52,36 @@ public void testElasticByteBufferWithWire() { byteBufferBytes.releaseLast(); } + + @Test + public void directElasticBufferResizesWhenCapacityIsExceeded() { + assumeFalse(Jvm.maxDirectMemory() == 0); + + for (boolean padding : new boolean[]{true, false}) { + Bytes directBytes = Bytes.allocateElasticDirect(32); + try { + Wire wire = WireType.BINARY.apply(directBytes); + wire.usePadding(padding); + + long initialCapacity = directBytes.realCapacity(); + String largeValue = repeat('x', (int) initialCapacity + 64); + + try (DocumentContext context = wire.writingDocument(false)) { + context.wire().write("payload").text(largeValue); + } + + Assert.assertTrue("buffer should grow when payload exceeds initial capacity", + directBytes.realCapacity() >= initialCapacity); + + directBytes.readPositionRemaining(0, directBytes.writePosition()); + try (DocumentContext context = wire.readingDocument()) { + Assert.assertTrue(context.isPresent()); + Assert.assertEquals("padding=" + padding, largeValue, + context.wire().read("payload").text()); + } + } finally { + directBytes.releaseLast(); + } + } + } } diff --git a/src/test/java/net/openhft/chronicle/wire/ElasticBytesCapacityTest.java b/src/test/java/net/openhft/chronicle/wire/ElasticBytesCapacityTest.java index 34b276cb38..ed43e05679 100644 --- a/src/test/java/net/openhft/chronicle/wire/ElasticBytesCapacityTest.java +++ b/src/test/java/net/openhft/chronicle/wire/ElasticBytesCapacityTest.java @@ -49,7 +49,7 @@ private void assertElasticGrowthPreservesState(Bytes bytes) { long writePosition = bytes.writePosition(); long readPosition = bytes.readPosition(); long readLimit = bytes.readLimit(); - long writeLimit = bytes.writeLimit(); + final long writeLimit = bytes.writeLimit(); bytes.readPositionRemaining(0, writePosition); assertEquals("read view should span written payload", writePosition, bytes.readLimit()); diff --git a/src/test/java/net/openhft/chronicle/wire/EmbeddedBytesMarshallableTest.java b/src/test/java/net/openhft/chronicle/wire/EmbeddedBytesMarshallableTest.java index 462cf1f2b6..13e2b6e1ae 100644 --- a/src/test/java/net/openhft/chronicle/wire/EmbeddedBytesMarshallableTest.java +++ b/src/test/java/net/openhft/chronicle/wire/EmbeddedBytesMarshallableTest.java @@ -173,9 +173,9 @@ static class EBM extends SelfDescribingTriviallyCopyable { transient int c0, c1, c3; @LongConversion(Base85LongConverter.class) long number; - Bytes a = Bytes.forFieldGroup(this, "a"); - Bytes b = Bytes.forFieldGroup(this, "b"); - Bytes c = Bytes.forFieldGroup(this, "c"); + final Bytes a = Bytes.forFieldGroup(this, "a"); + final Bytes b = Bytes.forFieldGroup(this, "b"); + final Bytes c = Bytes.forFieldGroup(this, "c"); // Required overrides for the SelfDescribingTriviallyCopyable class to describe its serialization format. @Override diff --git a/src/test/java/net/openhft/chronicle/wire/EnumSetMarshallingTest.java b/src/test/java/net/openhft/chronicle/wire/EnumSetMarshallingTest.java index 16837a3919..ba4d485a79 100644 --- a/src/test/java/net/openhft/chronicle/wire/EnumSetMarshallingTest.java +++ b/src/test/java/net/openhft/chronicle/wire/EnumSetMarshallingTest.java @@ -9,10 +9,7 @@ import org.junit.Test; import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.List; +import java.util.*; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; @@ -160,8 +157,8 @@ public void shouldAllowMultipleInstancesInObjectGraph() { * Container class with two lists containing EnumSet instances. */ private static final class Container extends SelfDescribingMarshallable { - private List f1 = new ArrayList<>(Arrays.asList(new Foo(EnumSet.allOf(Thread.State.class)))); - private List f2 = new ArrayList<>(Arrays.asList(new Foo(EnumSet.noneOf(Thread.State.class)))); + private final List f1 = new ArrayList<>(Collections.singletonList(new Foo(EnumSet.allOf(Thread.State.class)))); + private final List f2 = new ArrayList<>(Collections.singletonList(new Foo(EnumSet.noneOf(Thread.State.class)))); } /** diff --git a/src/test/java/net/openhft/chronicle/wire/EnumTest.java b/src/test/java/net/openhft/chronicle/wire/EnumTest.java index a969b13731..ea5a4f4785 100644 --- a/src/test/java/net/openhft/chronicle/wire/EnumTest.java +++ b/src/test/java/net/openhft/chronicle/wire/EnumTest.java @@ -6,7 +6,6 @@ import net.openhft.chronicle.bytes.Bytes; import net.openhft.chronicle.core.Jvm; import net.openhft.chronicle.core.io.IORuntimeException; -import net.openhft.chronicle.core.util.ReadResolvable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.junit.Assert; diff --git a/src/test/java/net/openhft/chronicle/wire/EscapeCharsTest.java b/src/test/java/net/openhft/chronicle/wire/EscapeCharsTest.java index 9a59b8c750..eabe21e628 100644 --- a/src/test/java/net/openhft/chronicle/wire/EscapeCharsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/EscapeCharsTest.java @@ -25,8 +25,6 @@ */ @RunWith(value = Parameterized.class) public class EscapeCharsTest extends WireTestCommon { - @NotNull - private final String chs; private final Future future; // Override the threadDump from WireTestCommon to use the parent implementation @@ -43,7 +41,6 @@ public void threadDump() { * @param future Represents the result of an asynchronous computation */ public EscapeCharsTest(@NotNull String chs, Future future) { - this.chs = chs; this.future = future; } diff --git a/src/test/java/net/openhft/chronicle/wire/FIX42Test.java b/src/test/java/net/openhft/chronicle/wire/FIX42Test.java index d955006bfb..f6ee2f92fe 100644 --- a/src/test/java/net/openhft/chronicle/wire/FIX42Test.java +++ b/src/test/java/net/openhft/chronicle/wire/FIX42Test.java @@ -50,7 +50,6 @@ 00000020 F1 3F ·? */ - import net.openhft.chronicle.bytes.Bytes; import org.jetbrains.annotations.NotNull; import org.junit.Test; @@ -83,8 +82,7 @@ public class FIX42Test extends WireTestCommon { // Elastic byte buffer for writing and reading data @SuppressWarnings("rawtypes") @NotNull - private - Bytes bytes = allocateElasticOnHeap(); + private final Bytes bytes = allocateElasticOnHeap(); // Constructor to initialize the test parameters public FIX42Test(int testId, boolean fixed, boolean numericField, boolean fieldLess, String dump) { @@ -99,48 +97,41 @@ public FIX42Test(int testId, boolean fixed, boolean numericField, boolean fieldL @Parameterized.Parameters(name = "{0}") public static Collection combinations() { // Various dump strings representing different binary data scenarios - String dump_1 = "" + - "Symbol: EURUSD\n" + + String textDump1 = "Symbol: EURUSD\n" + "NoMDEntries: 2\n" + "MDEntryType: 52\n" + "MDEntryPx: 1.1187\n" + "MDEntryType: 53\n" + "MDEntryPx: 1.1179\n"; - String dump0 = "" + - "00000000 c6 53 79 6d 62 6f 6c e6 45 55 52 55 53 44 cb 4e ·Symbol· EURUSD·N\n" + + String dump0 = "00000000 c6 53 79 6d 62 6f 6c e6 45 55 52 55 53 44 cb 4e ·Symbol· EURUSD·N\n" + "00000010 6f 4d 44 45 6e 74 72 69 65 73 a1 02 cb 4d 44 45 oMDEntri es···MDE\n" + "00000020 6e 74 72 79 54 79 70 65 a1 34 c9 4d 44 45 6e 74 ntryType ·4·MDEnt\n" + "00000030 72 79 50 78 94 b3 57 cb 4d 44 45 6e 74 72 79 54 ryPx··W· MDEntryT\n" + "00000040 79 70 65 a1 35 c9 4d 44 45 6e 74 72 79 50 78 94 ype·5·MD EntryPx·\n" + "00000050 ab 57 ·W \n"; - String dump1 = "" + - "00000000 c6 53 79 6d 62 6f 6c e6 45 55 52 55 53 44 cb 4e ·Symbol· EURUSD·N\n" + + String dump1 = "00000000 c6 53 79 6d 62 6f 6c e6 45 55 52 55 53 44 cb 4e ·Symbol· EURUSD·N\n" + "00000010 6f 4d 44 45 6e 74 72 69 65 73 a6 02 00 00 00 cb oMDEntri es······\n" + "00000020 4d 44 45 6e 74 72 79 54 79 70 65 a1 34 c9 4d 44 MDEntryT ype·4·MD\n" + "00000030 45 6e 74 72 79 50 78 91 2e 90 a0 f8 31 e6 f1 3f EntryPx· .···1··?\n" + "00000040 cb 4d 44 45 6e 74 72 79 54 79 70 65 a1 35 c9 4d ·MDEntry Type·5·M\n" + "00000050 44 45 6e 74 72 79 50 78 91 a5 2c 43 1c eb e2 f1 DEntryPx ··,C····\n" + "00000060 3f ? \n"; - String dump2 = "" + - "00000000 ba 37 e6 45 55 52 55 53 44 ba 8c 02 a1 02 ba 8d ·7·EURUS D·······\n" + + String dump2 = "00000000 ba 37 e6 45 55 52 55 53 44 ba 8c 02 a1 02 ba 8d ·7·EURUS D·······\n" + "00000010 02 a1 34 ba 8e 02 94 b3 57 ba 8d 02 a1 35 ba 8e ··4····· W····5··\n" + "00000020 02 94 ab 57 ···W \n"; - String dump3 = "" + - "00000000 ba 37 e6 45 55 52 55 53 44 ba 8c 02 a6 02 00 00 ·7·EURUS D·······\n" + + String dump3 = "00000000 ba 37 e6 45 55 52 55 53 44 ba 8c 02 a6 02 00 00 ·7·EURUS D·······\n" + "00000010 00 ba 8d 02 a1 34 ba 8e 02 91 2e 90 a0 f8 31 e6 ·····4·· ··.···1·\n" + "00000020 f1 3f ba 8d 02 a1 35 ba 8e 02 91 a5 2c 43 1c eb ·?····5· ····,C··\n" + "00000030 e2 f1 3f ··? \n"; - String dump4 = "" + - "00000000 e6 45 55 52 55 53 44 a1 02 a1 34 94 b3 57 a1 35 ·EURUSD· ··4··W·5\n" + + String dump4 = "00000000 e6 45 55 52 55 53 44 a1 02 a1 34 94 b3 57 a1 35 ·EURUSD· ··4··W·5\n" + "00000010 94 ab 57 ··W \n"; - String dump5 = "" + - "00000000 e6 45 55 52 55 53 44 a6 02 00 00 00 a1 34 91 2e ·EURUSD· ·····4·.\n" + + String dump5 = "00000000 e6 45 55 52 55 53 44 a6 02 00 00 00 a1 34 91 2e ·EURUSD· ·····4·.\n" + "00000010 90 a0 f8 31 e6 f1 3f a1 35 91 a5 2c 43 1c eb e2 ···1··?· 5··,C···\n" + "00000020 f1 3f ·? \n"; // Return a list of objects arrays containing different test parameter combinations return Arrays.asList( - new Object[]{-1, false, false, false, dump_1}, + new Object[]{-1, false, false, false, textDump1}, new Object[]{0, false, false, false, dump0}, new Object[]{1, true, false, false, dump1}, new Object[]{2, false, true, false, dump2}, @@ -189,8 +180,9 @@ public void dump() { // Inner static class representing a snapshot of market data static class MarketDataSnapshot implements WriteMarshallable { // Fields representing the currency symbol and its opening and closing prices - String symbol; - double openingPrice, closingPrice; + final String symbol; + final double openingPrice; + final double closingPrice; // Constructor to initialize the market data snapshot with provided values MarketDataSnapshot(String symbol, double openingPrice, double closingPrice) { diff --git a/src/test/java/net/openhft/chronicle/wire/FileMarshallableOutValidationTest.java b/src/test/java/net/openhft/chronicle/wire/FileMarshallableOutValidationTest.java index 7b6e2547d8..93c6ee1b2c 100644 --- a/src/test/java/net/openhft/chronicle/wire/FileMarshallableOutValidationTest.java +++ b/src/test/java/net/openhft/chronicle/wire/FileMarshallableOutValidationTest.java @@ -12,6 +12,7 @@ /** * Tests for URL validation when creating file based MarshallableOut instances. */ +@SuppressWarnings({"deprecation", "removal"}) public class FileMarshallableOutValidationTest extends WireTestCommon { @Test(expected = IllegalArgumentException.class) diff --git a/src/test/java/net/openhft/chronicle/wire/FloatDtoTest.java b/src/test/java/net/openhft/chronicle/wire/FloatDtoTest.java index 42bfe1f936..562df0fa22 100644 --- a/src/test/java/net/openhft/chronicle/wire/FloatDtoTest.java +++ b/src/test/java/net/openhft/chronicle/wire/FloatDtoTest.java @@ -37,6 +37,7 @@ public void test() { static class Key extends SelfDescribingMarshallable implements KeyedMarshallable { // Suppress unused warning as the field may be used for serialization/deserialization purposes @SuppressWarnings("unused") + final int uiid; // Constructor to initialize the 'Key' with a unique ID diff --git a/src/test/java/net/openhft/chronicle/wire/ForwardAndBackwardCompatibilityMarshallableTest.java b/src/test/java/net/openhft/chronicle/wire/ForwardAndBackwardCompatibilityMarshallableTest.java index 9b7c678214..e3c419c32a 100644 --- a/src/test/java/net/openhft/chronicle/wire/ForwardAndBackwardCompatibilityMarshallableTest.java +++ b/src/test/java/net/openhft/chronicle/wire/ForwardAndBackwardCompatibilityMarshallableTest.java @@ -23,7 +23,7 @@ public class ForwardAndBackwardCompatibilityMarshallableTest extends WireTestCommon { private final WireType wireType; - private Bytes bytes = Bytes.allocateElasticOnHeap(); + private final Bytes bytes = Bytes.allocateElasticOnHeap(); public ForwardAndBackwardCompatibilityMarshallableTest(WireType wireType) { this.wireType = wireType; @@ -49,7 +49,7 @@ public void afterChecks() { // Test to check the compatibility of a marshallable StringBuilder @Test - public void marshableStringBuilderTest() throws Exception { + public void marshableStringBuilderTest() { final Wire wire = wireType.apply(bytes); wire.usePadding(wire.isBinary()); ClassLookup wrap1 = CLASS_ALIASES.wrap(); diff --git a/src/test/java/net/openhft/chronicle/wire/GenerateMethodBridgeTest.java b/src/test/java/net/openhft/chronicle/wire/GenerateMethodBridgeTest.java index fa79610178..8c29cefa82 100644 --- a/src/test/java/net/openhft/chronicle/wire/GenerateMethodBridgeTest.java +++ b/src/test/java/net/openhft/chronicle/wire/GenerateMethodBridgeTest.java @@ -33,6 +33,7 @@ interface GMBZ extends GMBA, GMBB { } // A JUnit test class +@SuppressWarnings({"deprecation", "removal"}) public class GenerateMethodBridgeTest extends WireTestCommon { @Test diff --git a/src/test/java/net/openhft/chronicle/wire/GenerateMethodDelegateTest.java b/src/test/java/net/openhft/chronicle/wire/GenerateMethodDelegateTest.java index 71c1211a38..e0b3ce7cb2 100644 --- a/src/test/java/net/openhft/chronicle/wire/GenerateMethodDelegateTest.java +++ b/src/test/java/net/openhft/chronicle/wire/GenerateMethodDelegateTest.java @@ -27,6 +27,7 @@ public class GenerateMethodDelegateTest extends WireTestCommon { public void hasDirect() { assumeFalse(Jvm.maxDirectMemory() == 0); } + // Test the validity of class naming conventions @Test(expected = IllegalArgumentException.class) public void testInvalidName() { @@ -135,9 +136,8 @@ interface Chained2 { void say(String text); } + // A combined interface that extends multiple standard Java interfaces @SuppressWarnings("rawtypes") - private - // A combined interface that extends multiple standard Java interfaces - interface RCSB extends Runnable, Consumer, Supplier, BiConsumer { + private interface RCSB extends Runnable, Consumer, Supplier, BiConsumer { } } diff --git a/src/test/java/net/openhft/chronicle/wire/GenerateMethodWriter2CoverageTest.java b/src/test/java/net/openhft/chronicle/wire/GenerateMethodWriter2CoverageTest.java index ec56e7b007..9a99808dee 100644 --- a/src/test/java/net/openhft/chronicle/wire/GenerateMethodWriter2CoverageTest.java +++ b/src/test/java/net/openhft/chronicle/wire/GenerateMethodWriter2CoverageTest.java @@ -12,9 +12,7 @@ import java.util.ArrayList; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; public class GenerateMethodWriter2CoverageTest extends WireTestCommon { @@ -38,6 +36,7 @@ public void generatesNestedWritersWithMethodIds() { MethodReader reader = wire.methodReader(recorder); while (reader.readOne()) { // drain + continue; } List expected = new ArrayList<>(); diff --git a/src/test/java/net/openhft/chronicle/wire/GenerateMethodWriterMultiInterfaceTest.java b/src/test/java/net/openhft/chronicle/wire/GenerateMethodWriterMultiInterfaceTest.java index 1e096a0aee..f43ea15503 100644 --- a/src/test/java/net/openhft/chronicle/wire/GenerateMethodWriterMultiInterfaceTest.java +++ b/src/test/java/net/openhft/chronicle/wire/GenerateMethodWriterMultiInterfaceTest.java @@ -10,13 +10,11 @@ import java.util.ArrayList; import java.util.List; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class GenerateMethodWriterMultiInterfaceTest extends WireTestCommon { - interface First { void one(int v); } - interface Second { void two(String s); } - @Test public void builderSupportsAdditionalInterfaces() { Bytes bytes = Bytes.allocateElasticOnHeap(); @@ -32,16 +30,30 @@ public void builderSupportsAdditionalInterfaces() { List seen = new ArrayList<>(); MethodReader reader = wire.methodReader(new First() { - @Override public void one(int v) { seen.add("one:" + v); } + @Override + public void one(int v) { + seen.add("one:" + v); + } }, new Second() { - @Override public void two(String s) { seen.add("two:" + s); } + @Override + public void two(String s) { + seen.add("two:" + s); + } }); while (reader.readOne()) { // drain + continue; } assertEquals(2, seen.size()); assertTrue(seen.get(0).startsWith("two:")); assertTrue(seen.get(1).startsWith("one:")); } -} + interface First { + void one(int v); + } + + interface Second { + void two(String s); + } +} diff --git a/src/test/java/net/openhft/chronicle/wire/HashWireTest.java b/src/test/java/net/openhft/chronicle/wire/HashWireTest.java index d18cabd6f7..bd94aa92d8 100644 --- a/src/test/java/net/openhft/chronicle/wire/HashWireTest.java +++ b/src/test/java/net/openhft/chronicle/wire/HashWireTest.java @@ -65,5 +65,10 @@ static class Field extends SelfDescribingMarshallable implements Cloneable { Field(String name) { this.name = name; } + + @Override + public Field clone() { + return deepCopy(); + } } } diff --git a/src/test/java/net/openhft/chronicle/wire/InnerMapTest.java b/src/test/java/net/openhft/chronicle/wire/InnerMapTest.java index dd25ac08bf..07bdafcaec 100644 --- a/src/test/java/net/openhft/chronicle/wire/InnerMapTest.java +++ b/src/test/java/net/openhft/chronicle/wire/InnerMapTest.java @@ -102,7 +102,7 @@ public MyMarshable name(String name) { // A nested class within the `MyMarshable` class static class MyNested extends SelfDescribingMarshallable { - String value; + final String value; // Constructor to initialize the value MyNested(String value) { diff --git a/src/test/java/net/openhft/chronicle/wire/InvalidYamWithCommonMistakesTest.java b/src/test/java/net/openhft/chronicle/wire/InvalidYamWithCommonMistakesTest.java index 58c6ce7eb6..eb6510870c 100644 --- a/src/test/java/net/openhft/chronicle/wire/InvalidYamWithCommonMistakesTest.java +++ b/src/test/java/net/openhft/chronicle/wire/InvalidYamWithCommonMistakesTest.java @@ -208,8 +208,8 @@ public void testAssumeTypeBasedOnWhatButUseAlias() { // DTO class containing a string and another DTO static class Dto extends SelfDescribingMarshallable { - String y; - DtoB x; + final String y; + final DtoB x; // Constructor to initialize DTO with given values Dto(final String y, final DtoB x) { diff --git a/src/test/java/net/openhft/chronicle/wire/JSONTypesWithEnumsAndBoxedTypesTest.java b/src/test/java/net/openhft/chronicle/wire/JSONTypesWithEnumsAndBoxedTypesTest.java index 92486c9a46..5110d6d080 100644 --- a/src/test/java/net/openhft/chronicle/wire/JSONTypesWithEnumsAndBoxedTypesTest.java +++ b/src/test/java/net/openhft/chronicle/wire/JSONTypesWithEnumsAndBoxedTypesTest.java @@ -4,6 +4,7 @@ package net.openhft.chronicle.wire; import net.openhft.chronicle.core.Jvm; +import net.openhft.chronicle.core.annotation.UsedViaReflection; import net.openhft.chronicle.core.pool.ClassAliasPool; import org.junit.Assert; import org.junit.Test; @@ -45,6 +46,7 @@ enum Location { } // Class representing Formula 1 details. + @UsedViaReflection static class F1 extends AbstractMarshallableCfg { private String surname; // Surname of the F1 driver. diff --git a/src/test/java/net/openhft/chronicle/wire/JSONTypesWithMapsTest.java b/src/test/java/net/openhft/chronicle/wire/JSONTypesWithMapsTest.java index 2cd35b3e1a..89b7494fce 100644 --- a/src/test/java/net/openhft/chronicle/wire/JSONTypesWithMapsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/JSONTypesWithMapsTest.java @@ -42,8 +42,8 @@ public JSONTypesWithMapsTest(boolean useTypes) { // Static class representing Formula 1 details. static class F1 { - private String surname; // Surname of the F1 driver. - private int car; // Represents the car number. + private final String surname; // Surname of the F1 driver. + private final int car; // Represents the car number. // Constructor for the F1 class. F1(String surname, int car) { diff --git a/src/test/java/net/openhft/chronicle/wire/JSONWireDTOTest.java b/src/test/java/net/openhft/chronicle/wire/JSONWireDTOTest.java index 4329bd378c..2c07115418 100644 --- a/src/test/java/net/openhft/chronicle/wire/JSONWireDTOTest.java +++ b/src/test/java/net/openhft/chronicle/wire/JSONWireDTOTest.java @@ -5,6 +5,7 @@ import net.openhft.chronicle.bytes.Bytes; import net.openhft.chronicle.core.Jvm; +import net.openhft.chronicle.core.annotation.UsedViaReflection; import org.jetbrains.annotations.NotNull; import org.junit.Test; @@ -28,7 +29,7 @@ public void dto() { Bytes bytes = Bytes.allocateElasticDirect(); // Instantiate JSONWire for serialization and deserialization. - JSONWire wire = new JSONWire(bytes); + final JSONWire wire = new JSONWire(bytes); // Create a test object. JSOuterClass dto = new JSOuterClass(); @@ -69,6 +70,7 @@ public void dto() { } // Class representing the outer structure of the DTO. + @UsedViaReflection static class JSOuterClass extends SelfDescribingMarshallable { String text; @NotNull @@ -87,7 +89,9 @@ static class JSOuterClass extends SelfDescribingMarshallable { } // Nested class representing a part of the DTO. + @UsedViaReflection class JSNestedClass extends SelfDescribingMarshallable { + // must non static and have this$0 for this tests String str; int num; diff --git a/src/test/java/net/openhft/chronicle/wire/JSONWireMiscTest.java b/src/test/java/net/openhft/chronicle/wire/JSONWireMiscTest.java index e08ccdd478..9cef26cce0 100644 --- a/src/test/java/net/openhft/chronicle/wire/JSONWireMiscTest.java +++ b/src/test/java/net/openhft/chronicle/wire/JSONWireMiscTest.java @@ -23,10 +23,11 @@ * relates to https://github.com/OpenHFT/Chronicle-Wire/issues/324 */ @RunWith(value = Parameterized.class) +@SuppressWarnings({"deprecation", "removal"}) public class JSONWireMiscTest extends net.openhft.chronicle.wire.WireTestCommon { // Constant representing the text value for tests - private final String TEXT = "abc"; + private static final String TEXT = "abc"; // Flag to indicate if types should be used or not private final boolean useTypes; @@ -34,6 +35,11 @@ public class JSONWireMiscTest extends net.openhft.chronicle.wire.WireTestCommon // Instance of JSONWire which will be used in the tests private JSONWire wire; + // Constructor to initialize the parameterized test instance with useTypes value + public JSONWireMiscTest(boolean useTypes) { + this.useTypes = useTypes; + } + // Parameterized test data provider @Parameterized.Parameters(name = "useTypes={0}") public static Collection wireTypes() { @@ -43,11 +49,6 @@ public static Collection wireTypes() { ); } - // Constructor to initialize the parameterized test instance with useTypes value - public JSONWireMiscTest(boolean useTypes) { - this.useTypes = useTypes; - } - // Setup method to initialize JSONWire with or without types based on the test instance @Before public void before() { @@ -94,11 +95,6 @@ public void sequenceOfStrings() { assertBalancedBrackets(actual); } - // Enum definitions to be used for the asEnum test - enum A { - FIRST, SECOND, THIRD; - } - // Test to write an enum value to the wire and verify the written content @Test public void asEnum() { @@ -148,15 +144,6 @@ public void localTime() { assertBalancedBrackets(actual); } - // Custom class definition with an integer value for testing - final static class Foo { - final int value; - - Foo(int value) { - this.value = value; - } - } - // Test to write a sequence of custom class Foo instances to the wire and verify the written content @Test public void sequenceOfCustomClass() { @@ -167,16 +154,6 @@ public void sequenceOfCustomClass() { assertBalancedBrackets(actual); } - // Custom class definition with a string value for testing - final static class Bar { - - final String value; - - Bar(String value) { - this.value = value; - } - } - // Test to write a custom class Bar instance to the wire and verify the written content @Test public void customClass() { @@ -196,12 +173,6 @@ public void duration() { assertBalancedBrackets(actual); } - // Custom class implementing Serializable interface for testing - static final class Ser implements Serializable { - private static final long serialVersionUID = 0L; - int foo; - } - // Test to write a serializable class instance to the wire and verify the written content @Test public void serializable() { @@ -213,4 +184,34 @@ public void serializable() { System.out.println("actual = " + actual); assertBalancedBrackets(actual); } + + // Enum definitions to be used for the asEnum test + enum A { + FIRST, SECOND, THIRD + } + + // Custom class definition with an integer value for testing + static final class Foo { + final int value; + + Foo(int value) { + this.value = value; + } + } + + // Custom class definition with a string value for testing + static final class Bar { + + final String value; + + Bar(String value) { + this.value = value; + } + } + + // Custom class implementing Serializable interface for testing + static final class Ser implements Serializable { + private static final long serialVersionUID = 0L; + int foo; + } } diff --git a/src/test/java/net/openhft/chronicle/wire/JSONWireTest.java b/src/test/java/net/openhft/chronicle/wire/JSONWireTest.java index dd629c6773..7e1915c1f8 100644 --- a/src/test/java/net/openhft/chronicle/wire/JSONWireTest.java +++ b/src/test/java/net/openhft/chronicle/wire/JSONWireTest.java @@ -28,6 +28,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assume.assumeFalse; +@SuppressWarnings({"deprecation", "removal"}) public class JSONWireTest extends WireTestCommon { // Utility function to test copying from a JSONWire to a binary wire and back to a JSONWire. @@ -45,7 +46,6 @@ private static void testCopyToBinaryAndBack(CharSequence str) { // Perform the copying operations json.copyTo(binary); -// System.out.println(binary.bytes().toHexString()); binary.copyTo(json2); // Assertions to make sure the copying was successful @@ -53,12 +53,10 @@ private static void testCopyToBinaryAndBack(CharSequence str) { str.toString() .replaceAll("\\.0(\\D)", "$1") .replaceAll(" ?\\[ ?", "[") - .replaceAll(" ?\\] ?", "]") - , + .replaceAll(" ?\\] ?", "]"), json2.toString() .replaceAll(" ?\\[ ?", "[") - .replaceAll(" ?\\] ?", "]") - ); + .replaceAll(" ?\\] ?", "]")); hexDump.releaseLast(); } @@ -84,12 +82,10 @@ private static void testCopyToYAMLAndBack(CharSequence str) { str.toString() .replaceAll("\\.0(\\D)", "$1") .replaceAll(" ?\\[ ?", "[") - .replaceAll(" ?\\] ?", "]") - , + .replaceAll(" ?\\] ?", "]"), json2.toString() .replaceAll(" ?\\[ ?", "[") - .replaceAll(" ?\\] ?", "]") - ); + .replaceAll(" ?\\] ?", "]")); } // Utility function to create a JSONWire from a string @@ -287,7 +283,6 @@ public void testMarshallableWithTwoLists() { "}\n", lists1.toString()); final String str = JSON.asString(lists1); testCopyToBinaryAndBack(str); -// testCopyToYAMLAndBack(str); } finally { // Release occupied memory wire.bytes().releaseLast(); @@ -386,7 +381,7 @@ public void testArrayInDictionary2() { // Assert that the extracted content matches the expected format assertEquals("[320, {as=[[32905.50000, 1.60291699, 1625822573.857656], [32905.60000, 0.10415889, 1625822573.194909]], bs=[[32893.60000, 0.15042948, 1625822574.220475]]}, book-10]", "" + list); testCopyToBinaryAndBack(str); // Test binary conversion and back with the provided JSON string - testCopyToYAMLAndBack('{'+str+'}'); + testCopyToYAMLAndBack('{' + str + '}'); } @Test @@ -396,12 +391,6 @@ public void testArrayDelimiterNoSpace() { // A complex JSON string causing some parsing issues String str = "[320,{\"as\":[[\"32905.50000\",\"1.60291699\",\"1625822573.857656\"],[\"32905.60000\",\"0.10415889\",\"1625822573.194909\"]],\"bs\":[[\"32893.60000\",\"0.15042948\",\"1625822574.220475\"]]},\"book-10\"]"; - // A simple version of JSON str for testing purposes (commented out) -// String str = "[1,{\"a\":[2,3]}]"; - - // A different simple JSON string that seems to work -// String str = "[1,2,3,\"c\"]"; - final Bytes byteBufferBytes = Bytes.elasticByteBuffer(); // Create an elastic byte buffer byteBufferBytes.append(str); // Append the JSON string to the byte buffer @@ -410,7 +399,7 @@ public void testArrayDelimiterNoSpace() { final List list = jsonWire.getValueIn().list(Object.class); // Extract the content of the wire into a list assertNotNull(list); // Assert that the extracted list is not null testCopyToBinaryAndBack(str); // Test binary conversion and back with the JSON string - testCopyToYAMLAndBack('{'+str+'}'); + testCopyToYAMLAndBack('{' + str + '}'); byteBufferBytes.releaseLast(); // Release the last buffer to free up resources } @@ -438,13 +427,6 @@ public void testQuotedFieldsEmptySequence() { assertEquals("{\"field1\":1234,\"field2\":456,\"field3\":[ ],\"field4\":[\"abc\",\"xyz\" ]}", JSON.asString(f)); } - // A static class to demonstrate a holder of maps with different types of numeric keys and string values - static class MapWithIntegerKeysHolder extends SelfDescribingMarshallable { - Map intMap = new LinkedHashMap<>(); // A map with integer keys - Map longMap = new LinkedHashMap<>(); // A map with long keys - Map doubleMap = new LinkedHashMap<>(); // A map with double keys - } - @Test public void nestedMapWithIntegerKeys() { assumeFalse(Jvm.maxDirectMemory() == 0); @@ -459,8 +441,7 @@ public void nestedMapWithIntegerKeys() { mh.doubleMap.put(2.56, "number"); final String str = JSON.asString(mh); // Convert the populated object to its JSON string representation // Assert the generated JSON string matches the expected JSON string - assertEquals("" + - "{\"intMap\":{\"1111\":\"ones\",\"2222\":\"twos\"},\"longMap\":{\"888888888888\":\"eights\",\"999999999999\":\"nines\"},\"doubleMap\":{\"1.28\":\"number\",\"2.56\":\"number\"}}", + assertEquals("{\"intMap\":{\"1111\":\"ones\",\"2222\":\"twos\"},\"longMap\":{\"888888888888\":\"eights\",\"999999999999\":\"nines\"},\"doubleMap\":{\"1.28\":\"number\",\"2.56\":\"number\"}}", str); // Convert the JSON string back to a new instance of MapWithIntegerKeysHolder MapWithIntegerKeysHolder mh2 = JSON.fromString(MapWithIntegerKeysHolder.class, str); @@ -531,6 +512,47 @@ public void copyTypedDataToBinaryAndBack() { testCopyToYAMLAndBack(str); } + @Test + public void typeLiteral1() { + assumeFalse(Jvm.maxDirectMemory() == 0); + + String expected = "{\"@net.openhft.chronicle.wire.JSONWireTest$DtoWithClassReference\":{\"implClass\":{\"@type\":\"net.openhft.chronicle.wire.JSONWireTest\"},\"bool\":false}}"; + Object o = WireType.JSON_ONLY.fromString(expected); + String json = WireType.JSON_ONLY.asString(o); + Assert.assertEquals(expected, json); + } + + @Test + public void typeLiteralTest2() { + assumeFalse(Jvm.maxDirectMemory() == 0); + + DtoWithClassReference dtoWithClassReference = new DtoWithClassReference(); + dtoWithClassReference.implClass = this.getClass(); + String json = WireType.JSON_ONLY.asString(dtoWithClassReference); + assertEquals("{\"@net.openhft.chronicle.wire.JSONWireTest$DtoWithClassReference\"" + + ":{\"implClass\":{\"@type\":\"net.openhft.chronicle.wire.JSONWireTest\"},\"bool\":false}}", + json); + assertEquals(dtoWithClassReference, WireType.JSON_ONLY.fromString(json)); + } + + @Test + public void testNullListCollectionWithMultipleFieldsJson() { + assumeFalse(Jvm.maxDirectMemory() == 0); + + ClassAliasPool.CLASS_ALIASES.addAlias(CollectionContainer.class); + CollectionContainer container = WireType.JSON_ONLY.fromString("{ \"@CollectionContainer\": { \"collection\": [null, \"testValue\"] } }"); + Object[] array = container.collection.toArray(); + Assert.assertNull(array[0]); + Assert.assertEquals("testValue", array[1]); + } + + // A static class to demonstrate a holder of maps with different types of numeric keys and string values + static class MapWithIntegerKeysHolder extends SelfDescribingMarshallable { + final Map intMap = new LinkedHashMap<>(); // A map with integer keys + final Map longMap = new LinkedHashMap<>(); // A map with long keys + final Map doubleMap = new LinkedHashMap<>(); // A map with double keys + } + // A class to represent a nested structure for testing JSON serialization private static class Value extends SelfDescribingMarshallable { final Inner a = new Inner(); // Inner object @@ -630,12 +652,20 @@ private static class Dates extends SelfDescribingMarshallable { } // Class to represent an entity with two fields and two lists of strings + // Don't reorder these fields, or it will break testQuotedFieldsEmptySequence private static final class SimpleTwoLists implements Marshallable { int field1; // Integer field 1 int field2; // Integer field 2 final List field3 = new ArrayList<>(); // List of strings for field3 final List field4 = new ArrayList<>(); // List of strings for field4 + // Helper method to read and add string values from the reader to a list + private static void readList(SimpleTwoLists record, List data, ValueIn reader) { + while (reader.hasNextSequenceItem()) { // Looping through sequence items + data.add(reader.text()); // Adding each text item to the list + } + } + // Method to read marshallable data from the wire input @Override public void readMarshallable(@NotNull final WireIn wire) throws IORuntimeException { @@ -644,36 +674,6 @@ public void readMarshallable(@NotNull final WireIn wire) throws IORuntimeExcepti wire.read(() -> "field3").sequence(this, field3, SimpleTwoLists::readList); // Reading sequence for field3 wire.read(() -> "field4").sequence(this, field4, SimpleTwoLists::readList); // Reading sequence for field4 } - - // Helper method to read and add string values from the reader to a list - private static void readList(SimpleTwoLists record, List data, ValueIn reader) { - while (reader.hasNextSequenceItem()) { // Looping through sequence items - data.add(reader.text()); // Adding each text item to the list - } - } - } - - @Test - public void typeLiteral1() { - assumeFalse(Jvm.maxDirectMemory() == 0); - - String expected = "{\"@net.openhft.chronicle.wire.JSONWireTest$DtoWithClassReference\":{\"implClass\":{\"@type\":\"net.openhft.chronicle.wire.JSONWireTest\"},\"bool\":false}}"; - Object o = WireType.JSON_ONLY.fromString(expected); - String json = WireType.JSON_ONLY.asString(o); - Assert.assertEquals(expected, json); - } - - @Test - public void typeLiteralTest2() { - assumeFalse(Jvm.maxDirectMemory() == 0); - - DtoWithClassReference dtoWithClassReference = new DtoWithClassReference(); - dtoWithClassReference.implClass = this.getClass(); - String json = WireType.JSON_ONLY.asString(dtoWithClassReference); - assertEquals("{\"@net.openhft.chronicle.wire.JSONWireTest$DtoWithClassReference\"" + - ":{\"implClass\":{\"@type\":\"net.openhft.chronicle.wire.JSONWireTest\"},\"bool\":false}}", - json); - assertEquals(dtoWithClassReference, WireType.JSON_ONLY.fromString(json)); } private static class DtoWithClassReference extends SelfDescribingMarshallable { @@ -681,19 +681,7 @@ private static class DtoWithClassReference extends SelfDescribingMarshallable { private boolean bool; } - @Test - public void testNullListCollectionWithMultipleFieldsJson() { - assumeFalse(Jvm.maxDirectMemory() == 0); - - ClassAliasPool.CLASS_ALIASES.addAlias(CollectionContainer.class); - CollectionContainer container = WireType.JSON_ONLY.fromString("{ \"@CollectionContainer\": { \"collection\": [null, \"testValue\"] } }"); - Object[] array = container.collection.toArray(); - Assert.assertNull(array[0]); - Assert.assertEquals("testValue", array[1]); - } - private static class CollectionContainer { private Collection collection; } - } diff --git a/src/test/java/net/openhft/chronicle/wire/JSONWireTypesTest.java b/src/test/java/net/openhft/chronicle/wire/JSONWireTypesTest.java index 149ecf8471..4ba0bbfff2 100644 --- a/src/test/java/net/openhft/chronicle/wire/JSONWireTypesTest.java +++ b/src/test/java/net/openhft/chronicle/wire/JSONWireTypesTest.java @@ -14,6 +14,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assume.assumeFalse; +@SuppressWarnings({"deprecation", "removal"}) public class JSONWireTypesTest extends WireTestCommon { @SuppressWarnings("unchecked") @Test diff --git a/src/test/java/net/openhft/chronicle/wire/JSONWireWithListsTest.java b/src/test/java/net/openhft/chronicle/wire/JSONWireWithListsTest.java index 234631bbe9..712254f89e 100644 --- a/src/test/java/net/openhft/chronicle/wire/JSONWireWithListsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/JSONWireWithListsTest.java @@ -39,8 +39,8 @@ public JSONWireWithListsTest(boolean useTypes) { // Inner class representing a Formula 1 driver with surname and car number static class F1 { - private String surname; // Surname of the driver - private int car; // Car number of the driver + private final String surname; // Surname of the driver + private final int car; // Car number of the driver // Constructor for initializing F1 driver data F1(String surname, int car) { diff --git a/src/test/java/net/openhft/chronicle/wire/JsonWireDoubleAndFloatSpecialValuesAcceptanceTests.java b/src/test/java/net/openhft/chronicle/wire/JsonWireDoubleAndFloatSpecialValuesAcceptanceTests.java index e0e1053847..30e5215a7c 100644 --- a/src/test/java/net/openhft/chronicle/wire/JsonWireDoubleAndFloatSpecialValuesAcceptanceTests.java +++ b/src/test/java/net/openhft/chronicle/wire/JsonWireDoubleAndFloatSpecialValuesAcceptanceTests.java @@ -27,6 +27,7 @@ *
  • {@link JSONWire.JSONValueOut#writeSpecialFloatValueToBytes(Bytes, float)}
  • * */ +@SuppressWarnings({"deprecation", "removal"}) class JsonWireDoubleAndFloatSpecialValuesAcceptanceTests { @ParameterizedTest @@ -194,5 +195,4 @@ private FloatDto(float value) { this.value = value; } } - } diff --git a/src/test/java/net/openhft/chronicle/wire/JsonWireToStringAcceptanceTest.java b/src/test/java/net/openhft/chronicle/wire/JsonWireToStringAcceptanceTest.java index ef304f11ee..7efb8306e0 100644 --- a/src/test/java/net/openhft/chronicle/wire/JsonWireToStringAcceptanceTest.java +++ b/src/test/java/net/openhft/chronicle/wire/JsonWireToStringAcceptanceTest.java @@ -3,6 +3,7 @@ */ package net.openhft.chronicle.wire; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -11,15 +12,13 @@ import java.util.HashMap; import java.util.Map; -import static org.junit.Assert.assertEquals; - /** * Verify that unicode characters can be properly represented in JSON output. */ -@SuppressWarnings("UnnecessaryUnicodeEscape") +@SuppressWarnings({"UnnecessaryUnicodeEscape", "deprecation", "removal"}) class JsonWireToStringAcceptanceTest { - private static Collection WIRE_TYPES = Arrays.asList(WireType.JSON, WireType.JSON_ONLY); + private static final Collection WIRE_TYPES = Arrays.asList(WireType.JSON, WireType.JSON_ONLY); @ParameterizedTest @ValueSource(strings = {"£", "€", "¥", "\u20B9", "ó", "óaóó", "", "ÊÆÄ"}) @@ -27,7 +26,7 @@ void json_verifyAsString(String input) { Map map = new HashMap<>(); map.put("x", input); for (WireType wireType : WIRE_TYPES) { - assertEquals("{\"x\":\"" + input + "\"}", wireType.asString(map)); + Assertions.assertEquals("{\"x\":\"" + input + "\"}", wireType.asString(map)); } } @@ -37,7 +36,7 @@ void json_verifyObjectToString(String input) { Map map = new HashMap<>(); map.put("x", input); WireOut object = new JSONWire().getValueOut().object(map); - assertEquals("{\"x\":\"" + input + "\"}", object.toString()); + Assertions.assertEquals("{\"x\":\"" + input + "\"}", object.toString()); } @ParameterizedTest @@ -47,7 +46,7 @@ void json_verifyAsText(String input) { map.put("x", input); JSONWire jsonWire = new JSONWire(); jsonWire.getValueOut().object(map); - assertEquals("{\"x\":\"" + input + "\"}", JSONWire.asText(jsonWire)); + Assertions.assertEquals("{\"x\":\"" + input + "\"}", JSONWire.asText(jsonWire)); } } diff --git a/src/test/java/net/openhft/chronicle/wire/KubernetesYamlTest.java b/src/test/java/net/openhft/chronicle/wire/KubernetesYamlTest.java index 505633acb1..b67a032560 100644 --- a/src/test/java/net/openhft/chronicle/wire/KubernetesYamlTest.java +++ b/src/test/java/net/openhft/chronicle/wire/KubernetesYamlTest.java @@ -18,7 +18,7 @@ public class KubernetesYamlTest extends WireTestCommon { // Directory path to Kubernetes YAML files - private static String DIR = "/yaml/k8s/"; + private static final String DIR = "/yaml/k8s/"; /** * Performs a test based on a given YAML file and expected results. diff --git a/src/test/java/net/openhft/chronicle/wire/LongArrayValueBitSetMoreOpsTest.java b/src/test/java/net/openhft/chronicle/wire/LongArrayValueBitSetMoreOpsTest.java index 222323842d..08448071ed 100644 --- a/src/test/java/net/openhft/chronicle/wire/LongArrayValueBitSetMoreOpsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/LongArrayValueBitSetMoreOpsTest.java @@ -8,12 +8,12 @@ import static org.junit.Assert.*; +@SuppressWarnings({"deprecation", "removal"}) public class LongArrayValueBitSetMoreOpsTest extends WireTestCommon { @Test public void previousAndRangeOps() { - LongArrayValueBitSet bs = new LongArrayValueBitSet(256, new BinaryWire(Bytes.allocateElasticOnHeap(256))); - try { + try (LongArrayValueBitSet bs = new LongArrayValueBitSet(256, new BinaryWire(Bytes.allocateElasticOnHeap(256)))) { bs.set(2, 70); assertTrue(bs.get(2)); assertTrue(bs.get(69)); @@ -22,9 +22,6 @@ public void previousAndRangeOps() { bs.clear(10, 60); assertFalse(bs.get(10)); assertEquals(60, bs.nextSetBit(10)); - } finally { - bs.close(); } } } - diff --git a/src/test/java/net/openhft/chronicle/wire/LongArrayValueBitSetOperationsTest.java b/src/test/java/net/openhft/chronicle/wire/LongArrayValueBitSetOperationsTest.java index ffc4c6e7f6..9ac3c8b943 100644 --- a/src/test/java/net/openhft/chronicle/wire/LongArrayValueBitSetOperationsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/LongArrayValueBitSetOperationsTest.java @@ -16,8 +16,7 @@ public class LongArrayValueBitSetOperationsTest extends WireTestCommon { @Test public void basicOps() { - LongArrayValueBitSet bs = new LongArrayValueBitSet(192, new BinaryWire(Bytes.allocateElasticOnHeap(256))); - try { + try (LongArrayValueBitSet bs = new LongArrayValueBitSet(192, new BinaryWire(Bytes.allocateElasticOnHeap(256)))) { bs.set(0); bs.set(64); bs.set(128); @@ -41,8 +40,6 @@ public void basicOps() { assertTrue(bs.get(10)); assertFalse(bs.get(12)); assertTrue(bs.get(14)); - } finally { - bs.close(); } } } diff --git a/src/test/java/net/openhft/chronicle/wire/LongConversionExampleC.java b/src/test/java/net/openhft/chronicle/wire/LongConversionExampleC.java index 4af3001978..5292f2a637 100644 --- a/src/test/java/net/openhft/chronicle/wire/LongConversionExampleC.java +++ b/src/test/java/net/openhft/chronicle/wire/LongConversionExampleC.java @@ -24,7 +24,7 @@ static class House extends SelfDescribingMarshallable { private long text4a, text4b, text4c, text4d, text4e; // Transient Bytes object to hold address data - private transient Bytes address = Bytes.forFieldGroup(this, "address"); + private final transient Bytes address = Bytes.forFieldGroup(this, "address"); // Method to append the address details to the Bytes object void address(CharSequence owner) { diff --git a/src/test/java/net/openhft/chronicle/wire/LongValueBitSetMoreOpsTest.java b/src/test/java/net/openhft/chronicle/wire/LongValueBitSetMoreOpsTest.java index f71c25dd11..9cbb4f94b3 100644 --- a/src/test/java/net/openhft/chronicle/wire/LongValueBitSetMoreOpsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/LongValueBitSetMoreOpsTest.java @@ -6,8 +6,10 @@ import net.openhft.chronicle.bytes.Bytes; import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +@SuppressWarnings({"deprecation", "removal"}) public class LongValueBitSetMoreOpsTest extends WireTestCommon { private static LongValueBitSet bound(int bits) { @@ -16,24 +18,24 @@ private static LongValueBitSet bound(int bits) { @Test public void previousAndNextClearBits() { - LongValueBitSet bs = bound(256); - try { - bs.set(1); bs.set(63); bs.set(64); bs.set(200); + try (LongValueBitSet bs = bound(256)) { + bs.set(1); + bs.set(63); + bs.set(64); + bs.set(200); assertEquals(0, bs.nextClearBit(0)); assertEquals(62, bs.previousClearBit(63)); assertEquals(65, bs.nextClearBit(65)); assertEquals(199, bs.previousClearBit(200)); - } finally { - bs.close(); } } @Test public void streamEqualsCopyFromAndMarshallRoundTrip() { - LongValueBitSet a = bound(128); - LongValueBitSet b = bound(128); - try { - a.set(3); a.set(5); a.set(127); + try (LongValueBitSet a = bound(128); LongValueBitSet b = bound(128)) { + a.set(3); + a.set(5); + a.set(127); b.copyFrom(a); assertEquals(a, b); assertTrue(a.stream().anyMatch(i -> i == 3)); @@ -43,10 +45,6 @@ public void streamEqualsCopyFromAndMarshallRoundTrip() { LongValueBitSet r = w.read("bs").object(LongValueBitSet.class); assertEquals(a, r); r.close(); - } finally { - a.close(); - b.close(); } } } - diff --git a/src/test/java/net/openhft/chronicle/wire/LongValueBitSetOperationsTest.java b/src/test/java/net/openhft/chronicle/wire/LongValueBitSetOperationsTest.java index 32826fd5e7..d2cebd3054 100644 --- a/src/test/java/net/openhft/chronicle/wire/LongValueBitSetOperationsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/LongValueBitSetOperationsTest.java @@ -11,6 +11,7 @@ /** * Exercises {@link LongValueBitSet} across word boundaries and common operations. */ +@SuppressWarnings({"deprecation", "removal"}) public class LongValueBitSetOperationsTest extends WireTestCommon { private static LongValueBitSet newSet(int bits) { @@ -21,8 +22,7 @@ private static LongValueBitSet newSet(int bits) { @Test public void setGetFlipAcrossWords() { - LongValueBitSet bs = newSet(128); - try { + try (LongValueBitSet bs = newSet(128)) { // Set boundary bits bs.set(0); @@ -50,15 +50,12 @@ public void setGetFlipAcrossWords() { // Clear range that includes last bit bs.clear(120, 128); assertEquals(-1, bs.nextSetBit(120)); - } finally { - bs.close(); } } @Test public void cardinalityAndToByteArray() { - LongValueBitSet bs = newSet(130); - try { + try (LongValueBitSet bs = newSet(130)) { bs.set(1); bs.set(65); bs.set(129); @@ -66,8 +63,6 @@ public void cardinalityAndToByteArray() { byte[] arr = bs.toByteArray(); assertNotNull(arr); assertTrue(arr.length > 0); - } finally { - bs.close(); } } } diff --git a/src/test/java/net/openhft/chronicle/wire/Marshallable2Test.java b/src/test/java/net/openhft/chronicle/wire/Marshallable2Test.java index e0dc63bbc8..34479cdc56 100644 --- a/src/test/java/net/openhft/chronicle/wire/Marshallable2Test.java +++ b/src/test/java/net/openhft/chronicle/wire/Marshallable2Test.java @@ -111,7 +111,7 @@ public void writingIsComplete() { // Static class representing an outer object that contains nested inner objects and implements the Validatable interface @SuppressWarnings("unused") private static class Outer extends SelfDescribingMarshallable implements Validatable { - String name; + final String name; Inner1 inner1; Inner2 inner2; transient boolean validated; diff --git a/src/test/java/net/openhft/chronicle/wire/MarshallableCfgResetTest.java b/src/test/java/net/openhft/chronicle/wire/MarshallableCfgResetTest.java index 208fd27ab4..35f2c7b12b 100644 --- a/src/test/java/net/openhft/chronicle/wire/MarshallableCfgResetTest.java +++ b/src/test/java/net/openhft/chronicle/wire/MarshallableCfgResetTest.java @@ -13,7 +13,7 @@ public class MarshallableCfgResetTest extends net.openhft.chronicle.wire.WireTes // Represents an engine with a configuration whether it's electric or not public static class Engine extends AbstractMarshallableCfg { - boolean isItElectric; + final boolean isItElectric; // Constructs an Engine instance with a given electric configuration Engine(boolean isItElectric) { @@ -25,7 +25,7 @@ public static class Engine extends AbstractMarshallableCfg { static class Boat extends SelfDescribingMarshallable { // Engine instance associated with the boat - Engine engine; + final Engine engine; // Constructs a Boat instance with a given engine Boat(Engine engine) { diff --git a/src/test/java/net/openhft/chronicle/wire/MarshallableOutBuilderTest.java b/src/test/java/net/openhft/chronicle/wire/MarshallableOutBuilderTest.java index 7603597874..65c657b87d 100644 --- a/src/test/java/net/openhft/chronicle/wire/MarshallableOutBuilderTest.java +++ b/src/test/java/net/openhft/chronicle/wire/MarshallableOutBuilderTest.java @@ -30,6 +30,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assume.assumeFalse; +@SuppressWarnings({"deprecation", "removal"}) public class MarshallableOutBuilderTest extends net.openhft.chronicle.wire.WireTestCommon { // Before each test case, obtain a thread dump @@ -151,7 +152,7 @@ public void http2() throws IOException, InterruptedException { // Test to ensure only JSON Wire is supported and if BINARY_LIGHT is used, an IllegalArgumentException is thrown. @Test(expected = IllegalArgumentException.class) - public void httpBinary() throws IOException, InterruptedException { + public void httpBinary() throws IOException { InetSocketAddress address = new InetSocketAddress(0); HttpServer server = HttpServer.create(address, 0); int port = server.getAddress().getPort(); @@ -248,7 +249,7 @@ public void complete() { // Handler for the benchmarking requests. class BenchHandler implements HttpHandler { - Wire wire = WireType.JSON_ONLY.apply(Bytes.allocateElasticOnHeap(128)); + final Wire wire = WireType.JSON_ONLY.apply(Bytes.allocateElasticOnHeap(128)); @Override public void handle(HttpExchange xchg) { diff --git a/src/test/java/net/openhft/chronicle/wire/MarshallableTest.java b/src/test/java/net/openhft/chronicle/wire/MarshallableTest.java index 7f788841fd..79f7b4e93a 100644 --- a/src/test/java/net/openhft/chronicle/wire/MarshallableTest.java +++ b/src/test/java/net/openhft/chronicle/wire/MarshallableTest.java @@ -18,6 +18,7 @@ import static net.openhft.chronicle.bytes.Bytes.allocateElasticOnHeap; import static org.junit.Assert.*; +@SuppressWarnings({"deprecation", "removal"}) public class MarshallableTest extends WireTestCommon { // Test to check if the fromFile() method of Marshallable throws an IOException for an empty file. diff --git a/src/test/java/net/openhft/chronicle/wire/MessageHistoryTest.java b/src/test/java/net/openhft/chronicle/wire/MessageHistoryTest.java index b41fd0db24..5671bbad60 100644 --- a/src/test/java/net/openhft/chronicle/wire/MessageHistoryTest.java +++ b/src/test/java/net/openhft/chronicle/wire/MessageHistoryTest.java @@ -15,6 +15,7 @@ import static org.junit.Assert.*; import static org.junit.Assume.assumeFalse; +@SuppressWarnings({"deprecation", "removal"}) public class MessageHistoryTest extends WireTestCommon { // Test to check if clearing and retrieving the MessageHistory works correctly. diff --git a/src/test/java/net/openhft/chronicle/wire/MethodReaderArgumentsRecycleTest.java b/src/test/java/net/openhft/chronicle/wire/MethodReaderArgumentsRecycleTest.java index 2f44b09b99..e00c39bbb6 100644 --- a/src/test/java/net/openhft/chronicle/wire/MethodReaderArgumentsRecycleTest.java +++ b/src/test/java/net/openhft/chronicle/wire/MethodReaderArgumentsRecycleTest.java @@ -5,6 +5,7 @@ import net.openhft.chronicle.bytes.Bytes; import net.openhft.chronicle.bytes.MethodReader; +import net.openhft.chronicle.core.annotation.UsedViaReflection; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -25,6 +26,15 @@ public class MethodReaderArgumentsRecycleTest extends WireTestCommon { // Will hold the last argument received in a method call. private volatile Object lastArgumentRef; + private static void assertRecycledEquality(Object a, Object b) { + if (a instanceof int[] && b instanceof int[]) + assertArrayEquals((int[]) a, (int[]) b); + else if (a instanceof Object[] && b instanceof Object[]) + assertArrayEquals((Object[]) a, (Object[]) b); + else + assertEquals(a, b); + } + // This method sets up the test environment before each test case. @SuppressWarnings("deprecation") @Before @@ -96,25 +106,16 @@ public void setCall(Set s) { }); } - private static void _assertEquals(Object a, Object b) { - if (a instanceof int[] && b instanceof int[]) - assertArrayEquals((int[]) a, (int[]) b); - else if (a instanceof Object[] && b instanceof Object[]) - assertArrayEquals((Object[]) a, (Object[]) b); - else - assertEquals(a, b); - } - // Utility method to verify that an argument is not recycled between method calls. private void verifyNotRecycled(T firstArg, T secondArg, Consumer call) { call.accept(firstArg); assertTrue(reader.readOne()); - Object firstRef = lastArgumentRef; - _assertEquals(firstArg, lastArgumentRef); + final Object firstRef = lastArgumentRef; + assertRecycledEquality(firstArg, lastArgumentRef); call.accept(secondArg); assertTrue(reader.readOne()); - _assertEquals(secondArg, lastArgumentRef); + assertRecycledEquality(secondArg, lastArgumentRef); assertNotSame(firstRef, lastArgumentRef); } @@ -123,7 +124,7 @@ private void verifyNotRecycled(T firstArg, T secondArg, Consumer call) { private void verifyRecycled(T firstArg, T secondArg, Consumer call) { call.accept(firstArg); assertTrue(reader.readOne()); - Object firstRef = lastArgumentRef; + final Object firstRef = lastArgumentRef; assertEquals(firstArg, lastArgumentRef); call.accept(secondArg); @@ -154,10 +155,10 @@ public void testObjectArrayNotRecycled() { // Test to verify that a MyMarshallable object argument gets recycled between calls. @Test public void testMarshallableRecycled() { - MyMarshallable first = new MyMarshallable(); + final MyMarshallable first = new MyMarshallable(); first.l = 5L; - MyMarshallable second = new MyMarshallable(); + final MyMarshallable second = new MyMarshallable(); second.l = 7L; verifyRecycled(first, second, writer::marshallableCall); @@ -166,10 +167,10 @@ public void testMarshallableRecycled() { // Test to confirm that a MyBytesMarshallable object argument gets recycled between calls. @Test public void testBytesMarshallableRecycled() { - MyBytesMarshallable first = new MyBytesMarshallable(); + final MyBytesMarshallable first = new MyBytesMarshallable(); first.d = 8.5; - MyBytesMarshallable second = new MyBytesMarshallable(); + final MyBytesMarshallable second = new MyBytesMarshallable(); second.d = 32.25; verifyRecycled(first, second, writer::bytesMarshallableCall); @@ -220,10 +221,10 @@ public void testWrappedListRecycled() { // Test to ascertain that a DTO object's list field gets recycled between calls. @Test public void testWrappedListAsObjectRecycled() { - ObjectContainingDto first = new ObjectContainingDto(); + final ObjectContainingDto first = new ObjectContainingDto(); first.list = new ArrayList<>(Arrays.asList(6, "f")); - ObjectContainingDto second = new ObjectContainingDto(); + final ObjectContainingDto second = new ObjectContainingDto(); second.list = new ArrayList<>(Arrays.asList(-3, "s")); verifyRecycled(first, second, writer::wrappedObjectCall); @@ -241,19 +242,18 @@ public void testWrappedListAsObjectRecycledDTO() { // Make a call with the first ListContainingDto and read the response. writer.wrappedObjectCall(first); assertTrue(reader.readOne()); - Object firstRef = lastArgumentRef; - assertEquals("" + - "!net.openhft.chronicle.wire.MethodReaderArgumentsRecycleTest$ObjectContainingDto {\n" + + final Object firstRef = lastArgumentRef; + assertEquals("!net.openhft.chronicle.wire.MethodReaderArgumentsRecycleTest$ObjectContainingDto {\n" + " list: [\n" + " !net.openhft.chronicle.wire.MethodReaderArgumentsRecycleTest$MyDto { a: 1, b: 2 },\n" + " !net.openhft.chronicle.wire.MethodReaderArgumentsRecycleTest$MyDto { a: 3, b: 4 },\n" + " !net.openhft.chronicle.wire.MethodReaderArgumentsRecycleTest$MyDto { a: 5, b: 6 }\n" + " ]\n" + "}\n", lastArgumentRef.toString()); - List list1 = (List) ((ObjectContainingDto) lastArgumentRef).list; + final List list1 = (List) ((ObjectContainingDto) lastArgumentRef).list; assertEquals(first.list, list1); - MyDto dto0 = (MyDto) list1.get(0); - MyDto dto1 = (MyDto) list1.get(1); + final MyDto dto0 = (MyDto) list1.get(0); + final MyDto dto1 = (MyDto) list1.get(1); // Make a call with the second ListContainingDto and read the response. writer.wrappedObjectCall(second); @@ -264,7 +264,7 @@ public void testWrappedListAsObjectRecycledDTO() { " !net.openhft.chronicle.wire.MethodReaderArgumentsRecycleTest$MyDto { a: 9, b: 0 }\n" + " ]\n" + "}\n", lastArgumentRef.toString()); - List list2 = (List) ((ObjectContainingDto) lastArgumentRef).list; + final List list2 = (List) ((ObjectContainingDto) lastArgumentRef).list; assertEquals(second.list, list2); assertSame(dto0, list1.get(0)); assertSame(dto1, list1.get(1)); @@ -374,6 +374,7 @@ static class ObjectContainingDto extends SelfDescribingMarshallable { Object list; } + @UsedViaReflection static class MyDto extends SelfDescribingMarshallable { private final int a; private final int b; diff --git a/src/test/java/net/openhft/chronicle/wire/MethodReaderBuilderExceptionHandlerTest.java b/src/test/java/net/openhft/chronicle/wire/MethodReaderBuilderExceptionHandlerTest.java index 9771e7e628..95233c24c7 100644 --- a/src/test/java/net/openhft/chronicle/wire/MethodReaderBuilderExceptionHandlerTest.java +++ b/src/test/java/net/openhft/chronicle/wire/MethodReaderBuilderExceptionHandlerTest.java @@ -20,8 +20,7 @@ public class MethodReaderBuilderExceptionHandlerTest extends WireTestCommon { // Static input data for the tests - private static final String input = "" + - "---\n" + + private static final String input = "---\n" + "a: a1\n" + "...\n" + "---\n" + @@ -40,25 +39,6 @@ public class MethodReaderBuilderExceptionHandlerTest extends WireTestCommon { "c: c2\n" + "...\n"; - // Interface for handling 'a' type messages - interface _A { - void a(String text); - } - - // Interface for handling 'b' type messages - interface _B { - void b(String text); - } - - // Interface for handling 'c' type messages - interface _C { - void c(String text); - } - - // Composite interface extending both _B and _C - private interface _BC extends _B, _C { - } - // Test where nothing is expected to happen, using non-scanning method @Test public void testNothing() { @@ -89,7 +69,7 @@ public void testA() { "# true\n" + "# true\n" + "# true\n", - ExceptionHandler.ignoresEverything(), _A.class, false); + ExceptionHandler.ignoresEverything(), IA.class, false); } // Test focusing on the 'a' type message, using scanning method @@ -100,11 +80,9 @@ public void testAScanning() { "a[a2]\n" + "# true\n" + "# false\n", - ExceptionHandler.ignoresEverything(), _A.class, true); + ExceptionHandler.ignoresEverything(), IA.class, true); } -// Continue from the previously provided class `MethodReaderBuilderExceptionHandlerTest`. - // Test focusing on both 'b' and 'c' type messages using non-scanning method @Test public void testBC() { @@ -118,7 +96,7 @@ public void testBC() { "# true\n" + "c[c2]\n" + "# true\n", - ExceptionHandler.ignoresEverything(), _BC.class, false); + ExceptionHandler.ignoresEverything(), IBC.class, false); } // Test focusing on both 'b' and 'c' type messages using scanning method @@ -132,7 +110,7 @@ public void testBCScanning() { "# true\n" + "c[c2]\n" + "# true\n", - ExceptionHandler.ignoresEverything(), _BC.class, true); + ExceptionHandler.ignoresEverything(), IBC.class, true); } // Test focusing on 'b' and 'c' type messages using non-scanning method, while expecting a warning for the 'a' type message @@ -149,7 +127,7 @@ public void testBCWarn() { "# true\n" + "c[c2]\n" + "# true\n", - Jvm.warn(), _BC.class, false); + Jvm.warn(), IBC.class, false); } // Test focusing on 'b' and 'c' type messages using scanning method, while expecting a warning for the 'a' type message @@ -164,7 +142,7 @@ public void testBCWarnScanning() { "# true\n" + "c[c2]\n" + "# true\n", - Jvm.warn(), _BC.class, true); + Jvm.warn(), IBC.class, true); } // A helper method for performing tests: @@ -187,4 +165,23 @@ private void doTest(String expected, ExceptionHandler eh, Class type, boolean } assertEquals(expected, out.toString().replace("\r", "")); } + + // Interface for handling 'a' type messages + interface IA { + void a(String text); + } + + // Interface for handling 'b' type messages + interface IB { + void b(String text); + } + + // Interface for handling 'c' type messages + interface IC { + void c(String text); + } + + // Composite interface extending both _B and _C + private interface IBC extends IB, IC { + } } diff --git a/src/test/java/net/openhft/chronicle/wire/MethodReaderDelegationTest.java b/src/test/java/net/openhft/chronicle/wire/MethodReaderDelegationTest.java index 1b748ca817..c26c02621a 100644 --- a/src/test/java/net/openhft/chronicle/wire/MethodReaderDelegationTest.java +++ b/src/test/java/net/openhft/chronicle/wire/MethodReaderDelegationTest.java @@ -25,6 +25,7 @@ import static org.junit.Assert.*; @RunWith(Parameterized.class) +@SuppressWarnings({"deprecation", "removal"}) public class MethodReaderDelegationTest extends WireTestCommon { private final boolean useMethodId; @@ -113,8 +114,9 @@ private void doTestUnsuccessfulCallIsDelegated(Wire wire, boolean scanning) { try (DocumentContext dc = wire.acquireWritingDocument(false)) { if (useMethodId) { Objects.requireNonNull(dc.wire()).writeEventId(myFallId).text(""); - } else + } else { Objects.requireNonNull(dc.wire()).writeEventName("myFall").text(""); + } } // Call the 'myCall' method on the writer again diff --git a/src/test/java/net/openhft/chronicle/wire/MethodWriterBytesTest.java b/src/test/java/net/openhft/chronicle/wire/MethodWriterBytesTest.java index 134f2df32f..af6ef4c0c2 100644 --- a/src/test/java/net/openhft/chronicle/wire/MethodWriterBytesTest.java +++ b/src/test/java/net/openhft/chronicle/wire/MethodWriterBytesTest.java @@ -18,14 +18,7 @@ @SuppressWarnings("rawtypes") public class MethodWriterBytesTest extends net.openhft.chronicle.wire.WireTestCommon { // A blocking queue to hold Bytes instances, used for synchronization between writer and reader. - private ArrayBlockingQueue q = new ArrayBlockingQueue<>(1); - - /** - * An interface defining a single method that accepts a Bytes message. - */ - interface Print { - void msg(Bytes message); - } + private final ArrayBlockingQueue q = new ArrayBlockingQueue<>(1); /** * This test verifies that a Bytes message can be written and read using MethodWriter and MethodReader respectively. @@ -45,6 +38,10 @@ public void test() throws InterruptedException { Bytes result = q.poll(10, TimeUnit.SECONDS); // Verify that the fetched message matches the expected content Assert.assertEquals("hello", result.toString()); + if (result != null) { + result.releaseLast(); + } + w.bytes().releaseLast(); } /** @@ -53,4 +50,66 @@ public void test() throws InterruptedException { private void println(Bytes bytes) { q.add(bytes); } + + @Test + public void reusedBytesRemainStableAcrossDispatches() throws InterruptedException { + Wire wire = new BinaryWire(Bytes.allocateElasticOnHeap()); + Print printer = wire.methodWriter(Print.class); + Bytes reusable = Bytes.allocateElasticOnHeap(); + try { + reusable.writeUtf8("alpha"); + printer.msg(reusable); + + reusable.clear(); + reusable.writeUtf8("beta"); + printer.msg(reusable); + + ArrayBlockingQueue sink = new ArrayBlockingQueue<>(2); + MethodReader reader = wire.methodReader((Print) bytes -> { + bytes.readPosition(0); + sink.add(bytes.readUtf8()); + }); + + Assert.assertTrue(reader.readOne()); + Assert.assertEquals("alpha", sink.poll(5, TimeUnit.SECONDS)); + Assert.assertTrue(reader.readOne()); + Assert.assertEquals("beta", sink.poll(5, TimeUnit.SECONDS)); + } finally { + reusable.releaseLast(); + wire.bytes().releaseLast(); + } + } + + @Test + public void producerMutationDuringCallbackDoesNotCorruptPayload() throws InterruptedException { + Wire wire = new BinaryWire(Bytes.allocateElasticOnHeap()); + Bytes shared = Bytes.allocateElasticOnHeap(); + try { + Print printer = wire.methodWriter(Print.class); + shared.writeUtf8("original"); + printer.msg(shared); + + ArrayBlockingQueue sink = new ArrayBlockingQueue<>(1); + MethodReader reader = wire.methodReader((Print) bytes -> { + // mutate the shared Bytes while the reader is consuming + shared.clear(); + shared.writeUtf8("mutated"); + bytes.readPosition(0); + sink.add(bytes.readUtf8()); + }); + + Assert.assertTrue(reader.readOne()); + Assert.assertEquals("original", sink.poll(5, TimeUnit.SECONDS)); + } finally { + shared.releaseLast(); + wire.bytes().releaseLast(); + } + } + + /** + * An interface defining a single method that accepts a Bytes message. + */ + interface Print { + void msg(Bytes message); + } } diff --git a/src/test/java/net/openhft/chronicle/wire/MethodWriterCodegenToggleTest.java b/src/test/java/net/openhft/chronicle/wire/MethodWriterCodegenToggleTest.java index 1519d26340..c32c12a66e 100644 --- a/src/test/java/net/openhft/chronicle/wire/MethodWriterCodegenToggleTest.java +++ b/src/test/java/net/openhft/chronicle/wire/MethodWriterCodegenToggleTest.java @@ -16,7 +16,8 @@ import java.util.List; import static net.openhft.chronicle.wire.VanillaMethodWriterBuilder.DISABLE_WRITER_PROXY_CODEGEN; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * Smoke test that toggles codegen/proxy path via system property and verifies @@ -25,19 +26,17 @@ @RunWith(Parameterized.class) public class MethodWriterCodegenToggleTest extends WireTestCommon { - interface API { void a(int x); void b(String s); } - - @Parameterized.Parameters(name = DISABLE_WRITER_PROXY_CODEGEN + "={0}") - public static Collection data() { - return Arrays.asList(new Object[]{Boolean.TRUE}, new Object[]{Boolean.FALSE}); - } - private final boolean disable; public MethodWriterCodegenToggleTest(boolean disable) { this.disable = disable; } + @Parameterized.Parameters(name = DISABLE_WRITER_PROXY_CODEGEN + "={0}") + public static Collection data() { + return Arrays.asList(new Object[]{Boolean.TRUE}, new Object[]{Boolean.FALSE}); + } + @After public void clearProp() { System.clearProperty(DISABLE_WRITER_PROXY_CODEGEN); @@ -56,13 +55,27 @@ public void roundTrip() { List seen = new ArrayList<>(); MethodReader r = w.methodReader(new API() { - @Override public void a(int x) { seen.add("a:" + x); } - @Override public void b(String s) { seen.add("b:" + s); } + @Override + public void a(int x) { + seen.add("a:" + x); + } + + @Override + public void b(String s) { + seen.add("b:" + s); + } }); - while (r.readOne()) { /* drain */ } + while (r.readOne()) { + continue; + } assertEquals(2, seen.size()); assertTrue(seen.get(0).startsWith("a:")); assertTrue(seen.get(1).startsWith("b:")); } -} + interface API { + void a(int x); + + void b(String s); + } +} diff --git a/src/test/java/net/openhft/chronicle/wire/MethodWriterHistoryTest.java b/src/test/java/net/openhft/chronicle/wire/MethodWriterHistoryTest.java index 792d663550..f4f0ad71e0 100644 --- a/src/test/java/net/openhft/chronicle/wire/MethodWriterHistoryTest.java +++ b/src/test/java/net/openhft/chronicle/wire/MethodWriterHistoryTest.java @@ -4,7 +4,6 @@ package net.openhft.chronicle.wire; import net.openhft.chronicle.bytes.Bytes; -import net.openhft.chronicle.bytes.MethodReader; import net.openhft.chronicle.core.pool.ClassAliasPool; import net.openhft.chronicle.wire.ValueIn; import org.junit.Test; diff --git a/src/test/java/net/openhft/chronicle/wire/MethodWriterReaderDispatchTest.java b/src/test/java/net/openhft/chronicle/wire/MethodWriterReaderDispatchTest.java index 5840828ae5..3349f2e2ac 100644 --- a/src/test/java/net/openhft/chronicle/wire/MethodWriterReaderDispatchTest.java +++ b/src/test/java/net/openhft/chronicle/wire/MethodWriterReaderDispatchTest.java @@ -10,15 +10,11 @@ import java.util.ArrayList; import java.util.List; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class MethodWriterReaderDispatchTest extends WireTestCommon { - interface Api { - void a(int i); - void b(String s); - } - @Test public void dispatchKnownMethodsAndIgnoreUnknown() { Wire w = new BinaryWire(Bytes.allocateElasticOnHeap(256)); @@ -31,15 +27,28 @@ public void dispatchKnownMethodsAndIgnoreUnknown() { List seen = new ArrayList<>(); MethodReader r = w.methodReader(new Api() { - @Override public void a(int i) { seen.add("a:" + i); } - @Override public void b(String s) { seen.add("b:" + s); } + @Override + public void a(int i) { + seen.add("a:" + i); + } + + @Override + public void b(String s) { + seen.add("b:" + s); + } }); while (r.readOne()) { // drain + continue; } assertEquals(2, seen.size()); assertTrue(seen.get(0).startsWith("a:")); assertTrue(seen.get(1).startsWith("b:")); } -} + interface Api { + void a(int i); + + void b(String s); + } +} diff --git a/src/test/java/net/openhft/chronicle/wire/MethodWriterReaderSimpleIntegrationTest.java b/src/test/java/net/openhft/chronicle/wire/MethodWriterReaderSimpleIntegrationTest.java index 910d18945e..562e058a5e 100644 --- a/src/test/java/net/openhft/chronicle/wire/MethodWriterReaderSimpleIntegrationTest.java +++ b/src/test/java/net/openhft/chronicle/wire/MethodWriterReaderSimpleIntegrationTest.java @@ -10,7 +10,8 @@ import java.util.ArrayList; import java.util.List; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * Small end‑to‑end flow using MethodWriter and VanillaMethodReader to @@ -18,14 +19,6 @@ */ public class MethodWriterReaderSimpleIntegrationTest extends WireTestCommon { - interface Echo { - void one(int v); - - void two(String t); - - void three(long a, double b); - } - @Test public void roundTrip() { Wire w = new BinaryWire(Bytes.allocateElasticOnHeap(256)); @@ -38,15 +31,24 @@ public void roundTrip() { List seen = new ArrayList<>(); MethodReader reader = w.methodReader(new Echo() { @Override - public void one(int v) { seen.add("one:" + v); } + public void one(int v) { + seen.add("one:" + v); + } + @Override - public void two(String t) { seen.add("two:" + t); } + public void two(String t) { + seen.add("two:" + t); + } + @Override - public void three(long a, double b) { seen.add("three:" + a + "," + b); } + public void three(long a, double b) { + seen.add("three:" + a + "," + b); + } }); while (reader.readOne()) { // loop until exhausted + continue; } assertEquals(3, seen.size()); @@ -54,4 +56,12 @@ public void roundTrip() { assertTrue(seen.get(1).startsWith("two:")); assertTrue(seen.get(2).startsWith("three:")); } + + interface Echo { + void one(int v); + + void two(String t); + + void three(long a, double b); + } } diff --git a/src/test/java/net/openhft/chronicle/wire/MethodWriterStringTest.java b/src/test/java/net/openhft/chronicle/wire/MethodWriterStringTest.java index f153e94550..170e8c73a3 100644 --- a/src/test/java/net/openhft/chronicle/wire/MethodWriterStringTest.java +++ b/src/test/java/net/openhft/chronicle/wire/MethodWriterStringTest.java @@ -17,7 +17,7 @@ */ public class MethodWriterStringTest extends net.openhft.chronicle.wire.WireTestCommon { // A blocking queue to hold String messages, used for synchronization between writer and reader. - private ArrayBlockingQueue q = new ArrayBlockingQueue<>(1); + private final ArrayBlockingQueue q = new ArrayBlockingQueue<>(1); /** * An interface defining a single method that accepts a String message. diff --git a/src/test/java/net/openhft/chronicle/wire/MethodWriterVagueTypesTest.java b/src/test/java/net/openhft/chronicle/wire/MethodWriterVagueTypesTest.java index de670d1003..d5a6ecf572 100644 --- a/src/test/java/net/openhft/chronicle/wire/MethodWriterVagueTypesTest.java +++ b/src/test/java/net/openhft/chronicle/wire/MethodWriterVagueTypesTest.java @@ -21,11 +21,12 @@ * It extends the WireTestCommon from the `net.openhft.chronicle.wire` package for common test setup and utilities. */ @RunWith(value = Parameterized.class) +@SuppressWarnings({"deprecation", "removal"}) public class MethodWriterVagueTypesTest extends net.openhft.chronicle.wire.WireTestCommon { - private ArrayBlockingQueue singleQ = new ArrayBlockingQueue<>(1); - private ArrayBlockingQueue doubleQ = new ArrayBlockingQueue<>(2); + private final ArrayBlockingQueue singleQ = new ArrayBlockingQueue<>(1); + private final ArrayBlockingQueue doubleQ = new ArrayBlockingQueue<>(2); private final List, Object>> usedObjects = Arrays.asList(new HashMap<>(), new HashMap<>()); - private Class[] prevObjClasses = new Class[2]; + private final Class[] prevObjClasses = new Class[2]; private final Boolean multipleNonMarshallableParamTypes; public MethodWriterVagueTypesTest(Boolean multipleNonMarshallableParamTypes) { @@ -67,7 +68,7 @@ static class MarshallableTestContainer extends NonMarshallableTestContainer impl static class NonMarshallableTestContainer implements Container { - String randomInt = String.valueOf(new Random().nextInt()); + final String randomInt = String.valueOf(new Random().nextInt()); @Override public String toString() { @@ -125,9 +126,9 @@ public void testDouble() throws Exception { testDouble(printer::msg, reader, "key2", new NonMarshallableTestContainer()); testDouble(printer::msg, reader, new MarshallableTestContainer(), new MarshallableTestContainer()); testDouble(printer::msg, reader, new NonMarshallableTestContainer(), new NonMarshallableTestContainer()); - testDouble(printer::msg, reader, Integer.valueOf(5), new MarshallableTestContainer()); - testDouble(printer::msg, reader, Integer.valueOf(6), new MarshallableTestContainer()); - testDouble(printer::msg, reader, Long.valueOf(3L), new MarshallableTestContainer()); + testDouble(printer::msg, reader, 5, new MarshallableTestContainer()); + testDouble(printer::msg, reader, 6, new MarshallableTestContainer()); + testDouble(printer::msg, reader, 3L, new MarshallableTestContainer()); } @Test @@ -172,7 +173,7 @@ private void testSingle(PrintObjectSingle printer, MethodReader reader, Object o test(() -> printer.msg(obj), reader, singleQ, obj); } - private void testDouble(BiConsumer printer, MethodReader reader, K key, C obj) throws Exception { + private void testDouble(BiConsumer printer, MethodReader reader, K key, C obj) throws Exception { test(() -> printer.accept(key, obj), reader, doubleQ, key, obj); } diff --git a/src/test/java/net/openhft/chronicle/wire/MicroLongConverterTest.java b/src/test/java/net/openhft/chronicle/wire/MicroLongConverterTest.java index 4880ba7ef8..7504a6e1dd 100644 --- a/src/test/java/net/openhft/chronicle/wire/MicroLongConverterTest.java +++ b/src/test/java/net/openhft/chronicle/wire/MicroLongConverterTest.java @@ -11,6 +11,7 @@ * This class tests the functionality of the MicroLongConverter. * It extends the WireTestCommon for common test setup and utilities. */ +@SuppressWarnings({"deprecation", "removal"}) public class MicroLongConverterTest extends WireTestCommon { /** diff --git a/src/test/java/net/openhft/chronicle/wire/MicroTimestampLongConverterTest.java b/src/test/java/net/openhft/chronicle/wire/MicroTimestampLongConverterTest.java index f0ec8d93dc..ac0055a7ba 100644 --- a/src/test/java/net/openhft/chronicle/wire/MicroTimestampLongConverterTest.java +++ b/src/test/java/net/openhft/chronicle/wire/MicroTimestampLongConverterTest.java @@ -56,7 +56,7 @@ public void testTrailingZ() { // Test timestamp parsing with New York timezone @Test - public void NYparse() { + public void parseNewYorkTimeZone() { MicroTimestampLongConverter mtlc = new MicroTimestampLongConverter("America/New_York"); long time = INSTANCE.parse("2020/09/18T01:02:03.456789"); final String str = mtlc.asString(time); diff --git a/src/test/java/net/openhft/chronicle/wire/MilliTimestampLongConverterTest.java b/src/test/java/net/openhft/chronicle/wire/MilliTimestampLongConverterTest.java index badb301542..cc3cac90e4 100644 --- a/src/test/java/net/openhft/chronicle/wire/MilliTimestampLongConverterTest.java +++ b/src/test/java/net/openhft/chronicle/wire/MilliTimestampLongConverterTest.java @@ -8,6 +8,7 @@ import static net.openhft.chronicle.wire.MilliTimestampLongConverter.INSTANCE; import static org.junit.Assert.assertEquals; +@SuppressWarnings({"deprecation", "removal"}) public class MilliTimestampLongConverterTest extends WireTestCommon { // Define constant strings for different timestamp representations diff --git a/src/test/java/net/openhft/chronicle/wire/MyTypesCustom.java b/src/test/java/net/openhft/chronicle/wire/MyTypesCustom.java index 2f54f6f455..b751f3530a 100644 --- a/src/test/java/net/openhft/chronicle/wire/MyTypesCustom.java +++ b/src/test/java/net/openhft/chronicle/wire/MyTypesCustom.java @@ -6,6 +6,7 @@ import org.jetbrains.annotations.NotNull; // Class MyTypesCustom extends MyTypes and implements Marshallable to provide custom serialization logic +@SuppressWarnings({"deprecation", "removal"}) public class MyTypesCustom extends MyTypes implements Marshallable { // Override the writeMarshallable method to dictate how instances of MyTypesCustom will be serialized to wire format diff --git a/src/test/java/net/openhft/chronicle/wire/NestedMapsTest.java b/src/test/java/net/openhft/chronicle/wire/NestedMapsTest.java index 98939839d2..0e873fc0f3 100644 --- a/src/test/java/net/openhft/chronicle/wire/NestedMapsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/NestedMapsTest.java @@ -97,8 +97,7 @@ public void testMapped() { break; case BINARY: // Expected serialized format for BINARY wire type - assertEquals("" + - "--- !!data #binary\n" + + assertEquals("--- !!data #binary\n" + "mapped: !net.openhft.chronicle.wire.NestedMapsTest$Mapped {\n" + " words: [\n" + " A,\n" + @@ -132,8 +131,7 @@ public void testMapped() { break; case FIELDLESS_BINARY: // Expected serialized format for FIELDLESS_BINARY wire type - assertEquals("" + - "--- !!data #binary\n" + + assertEquals("--- !!data #binary\n" + "mapped: !net.openhft.chronicle.wire.NestedMapsTest$Mapped [\n" + " [\n" + " A,\n" + @@ -165,6 +163,9 @@ public void testMapped() { " }\n" + "]\n", Wires.fromSizePrefixedBlobs(wire)); break; + default: + // Other wire types do not have deterministic string forms to assert. + break; } // Deserialize the Mapped object from wire @@ -237,6 +238,9 @@ public void testMappedTopLevel() { case FIELDLESS_BINARY: assertEquals("[pos: 0, rlim: 119, wlim: 2147483632, cap: 2147483632 ] ǁ\\u0082*٠٠٠áAåquickåbrownãfoxåjumpsäoverãtheälazyãdog\\u0082⒕٠٠٠¡⒈¡⒉¡⒉¡⒊¡⒌¡⒏¡⒔\\u0082⒙٠٠٠¹⒊ayeãAAA¹⒊beeãBBB\\u0082\\u0019٠٠٠¹⒊one¡⒈¹⒔two point two\\u0092Ü⒈‡٠٠٠٠٠٠٠٠٠", wire.bytes().toDebugString()); break; + default: + // Other wire types do not have deterministic string forms to assert. + break; } // Deserialize the object and assert if it matches the original diff --git a/src/test/java/net/openhft/chronicle/wire/OverrideAValueTest.java b/src/test/java/net/openhft/chronicle/wire/OverrideAValueTest.java index b213394bde..7be01bd84d 100644 --- a/src/test/java/net/openhft/chronicle/wire/OverrideAValueTest.java +++ b/src/test/java/net/openhft/chronicle/wire/OverrideAValueTest.java @@ -66,6 +66,7 @@ static class NumberHolder extends SelfDescribingMarshallable { static final Integer ONE = new Integer(1); // Non-static Integer field num, initialized to ONE @NotNull + final Integer num = ONE; } @@ -76,6 +77,7 @@ static class ObjectHolder extends SelfDescribingMarshallable { static final NumberHolder NH = new NumberHolder(); // Non-static NumberHolder field nh, initialized to NH @NotNull + final NumberHolder nh = NH; } diff --git a/src/test/java/net/openhft/chronicle/wire/PrimArraysTest.java b/src/test/java/net/openhft/chronicle/wire/PrimArraysTest.java index 10a4d931d6..28cf9cad6a 100644 --- a/src/test/java/net/openhft/chronicle/wire/PrimArraysTest.java +++ b/src/test/java/net/openhft/chronicle/wire/PrimArraysTest.java @@ -89,7 +89,6 @@ public void testPrimArray() { // Write the test array to the wire wire.write("test") .object(array); - // System.out.println(wire); // Assert that the textual representation matches when using WireType.TEXT if (wireType == WireType.TEXT) assertEquals(asText.trim(), wire.toString().trim()); diff --git a/src/test/java/net/openhft/chronicle/wire/PrimitiveTypeWrappersTest.java b/src/test/java/net/openhft/chronicle/wire/PrimitiveTypeWrappersTest.java index aa916d3510..c4f971c0ba 100644 --- a/src/test/java/net/openhft/chronicle/wire/PrimitiveTypeWrappersTest.java +++ b/src/test/java/net/openhft/chronicle/wire/PrimitiveTypeWrappersTest.java @@ -18,7 +18,7 @@ @RunWith(value = Parameterized.class) public class PrimitiveTypeWrappersTest extends WireTestCommon { - private boolean isTextWire; // Variable to determine if using text wire format + private final boolean isTextWire; // Variable to determine if using text wire format // Constructor to initialize the isTextWire flag public PrimitiveTypeWrappersTest(Object isTextWire) { @@ -50,7 +50,6 @@ public void testNumbers() { @NotNull final Wire wire = wireFactory(); wire.write().object(num); // Write the number to the wire - // System.out.println(wire); @Nullable final Object object = wire.read().object(type); // Read the number back as the specified type Assert.assertTrue(num.getClass() + " to " + type.getName(), type.isAssignableFrom(object.getClass())); Assert.assertEquals(num.getClass() + " to " + type.getName(), num.intValue(), ((Number) object).intValue()); @@ -67,7 +66,6 @@ public void testNumbers2() { @NotNull final Wire wire = wireFactory(); wire.write().object(num); - // System.out.println(num.getClass() + " of " + num + " is " + (isTextWire ? wire.toString() : wire.bytes().toHexString())); @Nullable final Object object = wire.read().object(Object.class); Assert.assertSame(num.getClass(), object.getClass()); Assert.assertEquals(num.getClass().getName(), num, object); diff --git a/src/test/java/net/openhft/chronicle/wire/ProjectTest.java b/src/test/java/net/openhft/chronicle/wire/ProjectTest.java index ab44fa4946..8e8fe43f9b 100644 --- a/src/test/java/net/openhft/chronicle/wire/ProjectTest.java +++ b/src/test/java/net/openhft/chronicle/wire/ProjectTest.java @@ -42,7 +42,7 @@ public static Collection data() { // Test case to verify the projection functionality between two data transfer objects. @SuppressWarnings("unchecked") @Test - public void testProject() throws Exception { + public void testProject() { assumeFalse(Jvm.maxDirectMemory() == 0); // Initialize the first DTO with sample data @@ -83,6 +83,7 @@ public void testProjectWithNestedMarshallable() { @SuppressWarnings("rawtypes") static class Dto1 extends SelfDescribingMarshallable { @NotNull + final Map m = new HashMap<>(); String anotherField; long someValue; @@ -94,6 +95,7 @@ static class Dto2 extends SelfDescribingMarshallable { long someValue; String anotherField; @NotNull + final Map m = new HashMap<>(); } diff --git a/src/test/java/net/openhft/chronicle/wire/QueryWireTest.java b/src/test/java/net/openhft/chronicle/wire/QueryWireTest.java index a207178907..b48574c5c2 100644 --- a/src/test/java/net/openhft/chronicle/wire/QueryWireTest.java +++ b/src/test/java/net/openhft/chronicle/wire/QueryWireTest.java @@ -9,13 +9,15 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Base64; import java.util.List; +import static java.nio.charset.StandardCharsets.ISO_8859_1; import static net.openhft.chronicle.bytes.Bytes.allocateElasticOnHeap; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; // This class tests the functionalities related to the QueryWire's read and write operations. +@SuppressWarnings({"deprecation", "removal"}) public class QueryWireTest extends WireTestCommon { // Byte storage to hold serialized data @@ -64,6 +66,7 @@ public void readWriteQuery() { // Verify that the results list contains the correct values assertEquals(new ArrayList<>(Arrays.asList(true, 12345L, "Hello World", 12.345)), results); + bytes.releaseLast(); } @Test @@ -74,7 +77,7 @@ public void writesAndReadsQueryFragments() { writer.write("flag").bool(true); writer.write("count").int64(42); writer.write("name").text("alpha beta"); - writer.write("raw").rawBytes("tail".getBytes(java.nio.charset.StandardCharsets.ISO_8859_1)); + writer.write("raw").rawBytes("tail".getBytes(ISO_8859_1)); writer.write("payload").bytes(new byte[]{1, 2, 3}); String query = bytes.toString(); @@ -97,4 +100,66 @@ public void writesAndReadsQueryFragments() { bytes.releaseLast(); } + + @Test + public void percentEncodedCharactersRemainLiteral() { + @NotNull QueryWire wire = createWire(); + String literal = "value%2Bplus+space"; + wire.write("token").text(literal); + + assertTrue(bytes.toString().contains("token=" + literal)); + + bytes.readPositionRemaining(0, bytes.writePosition()); + QueryWire reader = new QueryWire(bytes); + assertEquals(literal, reader.read("token").text()); + bytes.releaseLast(); + } + + @Test + public void handlesZeroBytesAndDanglingKeys() { + Bytes storage = allocateElasticOnHeap(); + QueryWire wire = new QueryWire(storage); + byte[] raw = new byte[]{'A', 0, 'B'}; + wire.write("raw").rawBytes(raw); + wire.write("encoded").bytes(raw); + + storage.readPositionRemaining(0, storage.writePosition()); + QueryWire reader = new QueryWire(storage); + Bytes sink = allocateElasticOnHeap(); + reader.read("raw").textTo(sink); + assertArrayEquals(raw, sink.toByteArray()); + sink.releaseLast(); + assertEquals(Base64.getEncoder().encodeToString(raw), reader.read("encoded").text()); + storage.releaseLast(); + + Bytes truncated = Bytes.from("done=true&dangling"); + try { + QueryWire danglingReader = new QueryWire(truncated); + assertEquals("true", danglingReader.read("done").text()); + assertEquals("", danglingReader.read("dangling").text()); + } finally { + truncated.releaseLast(); + } + } + + @Test + public void queryWireOutputCanFeedTextWireAfterFormatting() { + @NotNull QueryWire wire = createWire(); + wire.write("name").text("alpha beta"); + wire.write("count").int64(7); + + String yamlLike = bytes.toString() + .replace("&", "\n") + .replace("=", ": "); + + Bytes yamlBytes = Bytes.from(yamlLike); + try { + Wire textWire = WireType.TEXT.apply(yamlBytes); + assertEquals("alpha beta", textWire.read("name").text()); + assertEquals(7L, textWire.read("count").int64()); + } finally { + yamlBytes.releaseLast(); + bytes.releaseLast(); + } + } } diff --git a/src/test/java/net/openhft/chronicle/wire/RFCExamplesTest.java b/src/test/java/net/openhft/chronicle/wire/RFCExamplesTest.java index f96a224a4a..14ad21ee44 100644 --- a/src/test/java/net/openhft/chronicle/wire/RFCExamplesTest.java +++ b/src/test/java/net/openhft/chronicle/wire/RFCExamplesTest.java @@ -32,25 +32,13 @@ public void testPuts() { // Allocate an elastic buffer on heap. @NotNull Bytes bytes = Bytes.allocateElasticOnHeap(); -/* - This represents a serialized format of the metadata and data. - It shows the service lookup, the type of view (Map), and the key/value types. - */ -/* ---- !!meta-data -csp:///service-lookup -tid: 1426502826520 ---- !!data -lookup: { relativeUri: test, view: !Map, types: [ !Integer, !String ] } - */ @NotNull Wire text = WireType.TEXT.apply(bytes); text.usePadding(true); writeMessageOne(text); // System.out.println(Wires.fromSizePrefixedBlobs(bytes)); // Validate the serialization result. - assertEquals("" + - "--- !!meta-data\n" + + assertEquals("--- !!meta-data\n" + "csp: ///service-lookup\n" + "tid: 149873598325\n" + "# position: 48, header: 0\n" + @@ -73,8 +61,7 @@ It shows the service lookup, the type of view (Map), and the key/value types. writeMessageOne(wire); // Validate the binary representation. - assertEquals("" + - "[pos: 0, rlim: 132, wlim: 2147483632, cap: 2147483632 ] ǁ$٠٠@Ãcspñ///service-lookupÃtid§u\\u009F)å\"٠٠٠\\u008FX٠٠٠Ælookup\\u0082I٠٠٠ËrelativeUriätestÄview¼⒊MapÅtypes\\u0082#٠٠٠ÇkeyType¼⒎IntegerÉvalueType¼⒍String\\u008F\\u008F\\u008F‡٠٠٠٠٠٠٠٠٠٠٠٠٠", + assertEquals("[pos: 0, rlim: 132, wlim: 2147483632, cap: 2147483632 ] ǁ$٠٠@Ãcspñ///service-lookupÃtid§u\\u009F)å\"٠٠٠\\u008FX٠٠٠Ælookup\\u0082I٠٠٠ËrelativeUriätestÄview¼⒊MapÅtypes\\u0082#٠٠٠ÇkeyType¼⒎IntegerÉvalueType¼⒍String\\u008F\\u008F\\u008F‡٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString()); // Create a raw representation of the wire. @@ -84,33 +71,14 @@ It shows the service lookup, the type of view (Map), and the key/value types. writeMessageOne(raw); // Validate the raw representation. - assertEquals("" + - "[pos: 0, rlim: 68, wlim: 2147483632, cap: 2147483632 ] ǁ\\u001C٠٠@⒘///service-lookupu\\u009F)å\"٠٠٠٠٠ ٠٠٠\\u001C٠٠٠⒋test⒊Map⒖٠٠٠⒎Integer⒍String‡٠٠٠٠٠٠٠٠", + assertEquals("[pos: 0, rlim: 68, wlim: 2147483632, cap: 2147483632 ] ǁ\\u001C٠٠@⒘///service-lookupu\\u009F)å\"٠٠٠٠٠ ٠٠٠\\u001C٠٠٠⒋test⒊Map⒖٠٠٠⒎Integer⒍String‡٠٠٠٠٠٠٠٠", bytes.toDebugString()); - /* - This serialized format is supposed to be a representation of put operations. - It shows the metadata (like the server URL and transaction id) and the key/value pairs to put. - */ -/* ---- !!meta-data -cid: 1 -# or -csp://server1/test -tid: 1426502826525 ---- !!data -put: [ 1, hello ] ---- !!data -put: [ 2, world ] ---- !!data -put: [ 3, bye ] -*/ clear(bytes); writeMessageTwo(text); // Validate the serialized format of the put operations. - assertEquals("" + - "--- !!meta-data\n" + + assertEquals("--- !!meta-data\n" + "csp: //server1/test\n" + "cid: 1\n" + "# position: 32, header: 0\n" + @@ -132,8 +100,7 @@ It shows the metadata (like the server URL and transaction id) and the key/value " value: bye\n" + "}\n", Wires.fromSizePrefixedBlobs(bytes)); - assertEquals("" + - "[pos: 0, rlim: 148, wlim: 2147483632, cap: 2147483632 ] ǁ\\u001C٠٠@csp: //server1/test⒑cid: 1⒑ $٠٠٠put: {⒑ key: 1,⒑ value: hello⒑}⒑ $٠٠٠put: {⒑ key: 2,⒑ value: world⒑}⒑ ٠٠٠put: {⒑ key: 3,⒑ value: bye⒑}⒑‡٠٠٠٠٠٠٠٠٠٠٠٠٠", + assertEquals("[pos: 0, rlim: 148, wlim: 2147483632, cap: 2147483632 ] ǁ\\u001C٠٠@csp: //server1/test⒑cid: 1⒑ $٠٠٠put: {⒑ key: 1,⒑ value: hello⒑}⒑ $٠٠٠put: {⒑ key: 2,⒑ value: world⒑}⒑ ٠٠٠put: {⒑ key: 3,⒑ value: bye⒑}⒑‡٠٠٠٠٠٠٠٠٠٠٠٠٠", bytes.toDebugString()); clear(bytes); @@ -141,16 +108,14 @@ It shows the metadata (like the server URL and transaction id) and the key/value // System.out.println(Wires.fromSizePrefixedBlobs(bytes)); // Validate the binary format of the put operations. - assertEquals("" + - "[pos: 0, rlim: 128, wlim: 2147483632, cap: 2147483632 ] ǁ\\u001C٠٠@Ãcspî//server1/testÃcid¡⒈\\u008F\\u008F\\u008F\\u001C٠٠٠Ãput\\u0082⒙٠٠٠Ãkey¡⒈Åvalueåhello\\u008F\\u001C٠٠٠Ãput\\u0082⒙٠٠٠Ãkey¡⒉Åvalueåworld\\u008F\\u001C٠٠٠Ãput\\u0082⒗٠٠٠Ãkey¡⒊Åvalueãbye\\u008F\\u008F\\u008F‡٠٠٠٠٠٠٠٠٠", + assertEquals("[pos: 0, rlim: 128, wlim: 2147483632, cap: 2147483632 ] ǁ\\u001C٠٠@Ãcspî//server1/testÃcid¡⒈\\u008F\\u008F\\u008F\\u001C٠٠٠Ãput\\u0082⒙٠٠٠Ãkey¡⒈Åvalueåhello\\u008F\\u001C٠٠٠Ãput\\u0082⒙٠٠٠Ãkey¡⒉Åvalueåworld\\u008F\\u001C٠٠٠Ãput\\u0082⒗٠٠٠Ãkey¡⒊Åvalueãbye\\u008F\\u008F\\u008F‡٠٠٠٠٠٠٠٠٠", bytes.toDebugString()); clear(bytes); writeMessageTwo(raw); // Validate the raw format of the put operations. - assertEquals("" + - "[pos: 0, rlim: 96, wlim: 2147483632, cap: 2147483632 ] ǁ\\u0018٠٠@⒕//server1/test⒈٠٠٠٠٠٠٠٠⒛٠٠٠⒕٠٠٠⒈٠٠٠٠٠٠٠⒌hello٠٠⒛٠٠٠⒕٠٠٠⒉٠٠٠٠٠٠٠⒌world٠٠⒗٠٠٠⒓٠٠٠⒊٠٠٠٠٠٠٠⒊bye‡٠٠٠٠٠٠٠٠", + assertEquals("[pos: 0, rlim: 96, wlim: 2147483632, cap: 2147483632 ] ǁ\\u0018٠٠@⒕//server1/test⒈٠٠٠٠٠٠٠٠⒛٠٠٠⒕٠٠٠⒈٠٠٠٠٠٠٠⒌hello٠٠⒛٠٠٠⒕٠٠٠⒉٠٠٠٠٠٠٠⒌world٠٠⒗٠٠٠⒓٠٠٠⒊٠٠٠٠٠٠٠⒊bye‡٠٠٠٠٠٠٠٠", bytes.toDebugString()); } @@ -179,8 +144,8 @@ private void writeMessageOne(@NotNull Wire wire) { out2.write(relativeUri).text("test") .write(view).typeLiteral("Map") .write(types).marshallable(m -> - m.write(() -> "keyType").typeLiteral("Integer") - .write(() -> "valueType").typeLiteral("String")))); + m.write(() -> "keyType").typeLiteral("Integer") + .write(() -> "valueType").typeLiteral("String")))); // Uncomment to print the serialized data. // System.out.println(wire); diff --git a/src/test/java/net/openhft/chronicle/wire/RawWirePerfMain.java b/src/test/java/net/openhft/chronicle/wire/RawWirePerfMain.java index f93d42b1ed..dc63c846aa 100644 --- a/src/test/java/net/openhft/chronicle/wire/RawWirePerfMain.java +++ b/src/test/java/net/openhft/chronicle/wire/RawWirePerfMain.java @@ -4,16 +4,12 @@ package net.openhft.chronicle.wire; import org.jetbrains.annotations.NotNull; -import org.junit.Ignore; -import org.junit.Test; import java.io.StreamCorruptedException; -import static org.junit.Assert.assertTrue; - public class RawWirePerfMain extends WireTestCommon { - public static void main(String[] args) throws StreamCorruptedException { + public static void main(String[] args) { // Create an instance of BinaryWirePerfTest with specific parameters. // These parameters typically control the test conditions. @NotNull BinaryWirePerfTest test = new BinaryWirePerfTest(-1, true, false, true); diff --git a/src/test/java/net/openhft/chronicle/wire/RawWireRoundTripTest.java b/src/test/java/net/openhft/chronicle/wire/RawWireRoundTripTest.java index f97bd294b8..5469cddae1 100644 --- a/src/test/java/net/openhft/chronicle/wire/RawWireRoundTripTest.java +++ b/src/test/java/net/openhft/chronicle/wire/RawWireRoundTripTest.java @@ -4,9 +4,6 @@ package net.openhft.chronicle.wire; import net.openhft.chronicle.bytes.Bytes; -import net.openhft.chronicle.bytes.BytesOut; -import net.openhft.chronicle.bytes.ref.BinaryLongArrayReference; -import net.openhft.chronicle.core.values.LongArrayValues; import org.junit.Test; import java.util.UUID; @@ -14,6 +11,7 @@ import static org.junit.Assert.*; +@SuppressWarnings({"deprecation", "removal"}) public class RawWireRoundTripTest extends WireTestCommon { @Test diff --git a/src/test/java/net/openhft/chronicle/wire/RawWireTest.java b/src/test/java/net/openhft/chronicle/wire/RawWireTest.java index 19702ebfc8..b1b952080b 100644 --- a/src/test/java/net/openhft/chronicle/wire/RawWireTest.java +++ b/src/test/java/net/openhft/chronicle/wire/RawWireTest.java @@ -25,14 +25,14 @@ import static net.openhft.chronicle.bytes.NativeBytes.nativeBytes; import static org.junit.Assert.*; +@SuppressWarnings({"deprecation", "removal"}) public class RawWireTest extends WireTestCommon { // Suppressing raw type warnings for the Bytes object. + // Bytes object used to simulate wire data storage. @SuppressWarnings("rawtypes") @NotNull - private - // Bytes object used to simulate wire data storage. - Bytes bytes = nativeBytes(); + private final Bytes bytes = nativeBytes(); // Override the method from WireTestCommon to ensure byte references are released. @Override @@ -545,7 +545,7 @@ public void testBytes() { .write().bytes(Bytes.wrapForRead("Hello".getBytes(ISO_8859_1))) .write().bytes(Bytes.wrapForRead("quotable, text".getBytes(ISO_8859_1))) .write().bytes(allBytes); - // System.out.println(bytes.toDebugString()); + @NotNull NativeBytes allBytes2 = nativeBytes(); // Reading and validating byte arrays from the wire wire.read().bytes(b -> assertEquals(0, b.readRemaining())) diff --git a/src/test/java/net/openhft/chronicle/wire/ReadAnyWireDetectionTest.java b/src/test/java/net/openhft/chronicle/wire/ReadAnyWireDetectionTest.java index 4a9cf949b3..dcde9961bb 100644 --- a/src/test/java/net/openhft/chronicle/wire/ReadAnyWireDetectionTest.java +++ b/src/test/java/net/openhft/chronicle/wire/ReadAnyWireDetectionTest.java @@ -13,6 +13,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +@SuppressWarnings({"deprecation", "removal"}) public class ReadAnyWireDetectionTest extends WireTestCommon { @Test diff --git a/src/test/java/net/openhft/chronicle/wire/ReadDocumentContextTest.java b/src/test/java/net/openhft/chronicle/wire/ReadDocumentContextTest.java index 3bb4c984c5..31f95eecc5 100644 --- a/src/test/java/net/openhft/chronicle/wire/ReadDocumentContextTest.java +++ b/src/test/java/net/openhft/chronicle/wire/ReadDocumentContextTest.java @@ -17,6 +17,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeFalse; +@SuppressWarnings({"deprecation", "removal"}) public class ReadDocumentContextTest extends WireTestCommon { // Test for writing a document that's not complete using non-shared memory @@ -158,7 +159,7 @@ public void testEmptyMessage() { } @Test - public void testReadingADocumentThatHasNotBeenFullyReadFromTheTcpSocketAt2Bytes() throws Exception { + public void testReadingADocumentThatHasNotBeenFullyReadFromTheTcpSocketAt2Bytes() { // Create an elastic byte buffer Bytes b = Bytes.allocateElasticOnHeap(); diff --git a/src/test/java/net/openhft/chronicle/wire/ReadOneTest.java b/src/test/java/net/openhft/chronicle/wire/ReadOneTest.java index 29e4092daf..f24f120437 100644 --- a/src/test/java/net/openhft/chronicle/wire/ReadOneTest.java +++ b/src/test/java/net/openhft/chronicle/wire/ReadOneTest.java @@ -3,7 +3,6 @@ */ package net.openhft.chronicle.wire; -import net.openhft.chronicle.bytes.Bytes; import net.openhft.chronicle.bytes.MethodReader; import net.openhft.chronicle.core.Jvm; import org.jetbrains.annotations.NotNull; @@ -18,35 +17,6 @@ */ public class ReadOneTest extends WireTestCommon { - // Definition for MyDto class, used for testing reading data from the Wire - static class MyDto extends SelfDescribingMarshallable { - String data; - } - - // Listener interface for MyDto to react when a MyDto is read - interface MyDtoListener { - void myDto(MyDto dto); - } - - // Definition for SnapshotDTO class, used to represent snapshots in the test - static class SnapshotDTO extends SelfDescribingMarshallable { - String data; - - public String data() { - return data; - } - - SnapshotDTO data(String data) { - this.data = data; - return this; - } - } - - // Listener interface for SnapshotDTO to react when a SnapshotDTO is read - interface SnapshotListener { - void snapshot(SnapshotDTO dto); - } - // Basic test for reading without scanning the wire @Test public void test() throws InterruptedException { @@ -64,7 +34,7 @@ public void testScanning() throws InterruptedException { } // Core testing method that simulates writing to and reading from the Wire - private void doTest(boolean scanning) throws InterruptedException { + private void doTest(boolean scanning) { ignoreException("Unknown @MethodId='history' called on interface net.openhft.chronicle.wire.ReadOneTest$SnapshotListener"); ignoreException("Unknown method-name='myDto' called on interface net.openhft.chronicle.wire.ReadOneTest$SnapshotListener"); // Initialization phase @@ -76,7 +46,7 @@ public boolean recordHistory() { }; MyDtoListener myOut = wire.methodWriterBuilder(MyDtoListener.class).build(); - SnapshotListener snapshotOut = wire.methodWriterBuilder(SnapshotListener.class).build(); + final SnapshotListener snapshotOut = wire.methodWriterBuilder(SnapshotListener.class).build(); ((VanillaMessageHistory) MessageHistory.get()).useBytesMarshallable(false); // Simulating different historical records and writes to the Wire @@ -141,4 +111,33 @@ private VanillaMessageHistory generateHistory(int value) { messageHistory.addSource(value, value); return messageHistory; } + + // Listener interface for MyDto to react when a MyDto is read + interface MyDtoListener { + void myDto(MyDto dto); + } + + // Listener interface for SnapshotDTO to react when a SnapshotDTO is read + interface SnapshotListener { + void snapshot(SnapshotDTO dto); + } + + // Definition for MyDto class, used for testing reading data from the Wire + static class MyDto extends SelfDescribingMarshallable { + String data; + } + + // Definition for SnapshotDTO class, used to represent snapshots in the test + static class SnapshotDTO extends SelfDescribingMarshallable { + String data; + + public String data() { + return data; + } + + SnapshotDTO data(String data) { + this.data = data; + return this; + } + } } diff --git a/src/test/java/net/openhft/chronicle/wire/ReadmeChapter1Test.java b/src/test/java/net/openhft/chronicle/wire/ReadmeChapter1Test.java index ef0cb75b78..f126835f91 100644 --- a/src/test/java/net/openhft/chronicle/wire/ReadmeChapter1Test.java +++ b/src/test/java/net/openhft/chronicle/wire/ReadmeChapter1Test.java @@ -5,6 +5,7 @@ import net.openhft.chronicle.bytes.Bytes; import net.openhft.chronicle.core.Jvm; +import net.openhft.chronicle.core.annotation.UsedViaReflection; import net.openhft.chronicle.core.pool.ClassAliasPool; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -58,7 +59,7 @@ public void example1() { .write(() -> "number").int64(1234567890L) .write(() -> "code").asEnum(TimeUnit.SECONDS) .write(() -> "price").float64(10.50); - // System.out.println(bytes); + // System.out.println(bytes); /* ``` prints @@ -78,7 +79,7 @@ public void example1() { .write(() -> "number").int64(1234567890L) .write(() -> "code").asEnum(TimeUnit.SECONDS) .write(() -> "price").float64(10.50); - // System.out.println(bytes2.toHexString()); + // System.out.println(bytes2.toHexString()); // to obtain the underlying ByteBuffer to write to a Channel @Nullable ByteBuffer byteBuffer = bytes2.underlyingObject(); @@ -103,7 +104,7 @@ public void example1() { .write(() -> "number").int64(1234567890L) .write(() -> "code").asEnum(TimeUnit.SECONDS) .write(() -> "price").float64(10.50); - // System.out.println(bytes3.toHexString()); + // System.out.println(bytes3.toHexString()); /* ``` prints in RawWire @@ -132,11 +133,11 @@ public void example2() { @NotNull Data data = new Data("Hello World", 1234567890L, TimeUnit.NANOSECONDS, 10.50); data.writeMarshallable(wire); - // System.out.println(bytes); + // System.out.println(bytes); @NotNull Data data2 = new Data(); data2.readMarshallable(wire); - // System.out.println(data2); + // System.out.println(data2); /* ``` @@ -156,11 +157,11 @@ public void example2() { @NotNull Wire wire2 = new BinaryWire(bytes2); data.writeMarshallable(wire2); - // System.out.println(bytes2.toHexString()); + // System.out.println(bytes2.toHexString()); @NotNull Data data3 = new Data(); data3.readMarshallable(wire2); - // System.out.println(data3); + // System.out.println(data3); /* ``` prints @@ -189,11 +190,11 @@ public void example3() { @NotNull Data data = new Data("Hello World", 1234567890L, TimeUnit.NANOSECONDS, 10.50); wire.write(() -> "mydata").marshallable(data); - // System.out.println(bytes); + // System.out.println(bytes); @NotNull Data data2 = new Data(); wire.read(() -> "mydata").marshallable(data2); - // System.out.println(data2); + // System.out.println(data2); /* ``` @@ -214,11 +215,11 @@ public void example3() { @NotNull Wire wire2 = new BinaryWire(bytes2); wire2.write(() -> "mydata").marshallable(data); - // System.out.println(bytes2.toHexString()); + // System.out.println(bytes2.toHexString()); @NotNull Data data3 = new Data(); wire2.read(() -> "mydata").marshallable(data3); - // System.out.println(data3); + // System.out.println(data3); /* ``` prints @@ -251,10 +252,10 @@ public void example4() { @NotNull Data data = new Data("Hello World", 1234567890L, TimeUnit.NANOSECONDS, 10.50); wire.write(() -> "mydata").object(data); - // System.out.println(bytes); + // System.out.println(bytes); @Nullable Data data2 = wire.read(() -> "mydata").object(Data.class); - // System.out.println(data2); + // System.out.println(data2); /* ``` @@ -275,10 +276,10 @@ public void example4() { @NotNull Wire wire2 = new BinaryWire(bytes2); wire2.write(() -> "mydata").object(data); - // System.out.println(bytes2.toHexString()); + // System.out.println(bytes2.toHexString()); @Nullable Data data3 = wire2.read(() -> "mydata").object(Data.class); - // System.out.println(data3); + // System.out.println(data3); /* ``` prints @@ -318,11 +319,11 @@ public void example5() { @NotNull Data data = new Data("Hello World", 1234567890L, TimeUnit.NANOSECONDS, 10.50); wire.writeDocument(false, data); - // System.out.println(Wires.fromSizePrefixedBlobs(bytes)); + // System.out.println(Wires.fromSizePrefixedBlobs(bytes)); @NotNull Data data2 = new Data(); assertTrue(wire.readDocument(null, data2)); - // System.out.println(data2); + // System.out.println(data2); /* ``` @@ -344,11 +345,11 @@ public void example5() { wire2.usePadding(true); wire2.writeDocument(false, data); - // System.out.println(Wires.fromSizePrefixedBlobs(bytes2)); + // System.out.println(Wires.fromSizePrefixedBlobs(bytes2)); @NotNull Data data3 = new Data(); assertTrue(wire2.readDocument(null, data3)); - // System.out.println(data3); + // System.out.println(data3); /* ``` prints @@ -387,7 +388,7 @@ public void example6() { }; wire.writeDocument(false, w -> w.write(() -> "mydata") .sequence(v -> Stream.of(data).forEach(v::object))); - // System.out.println(Wires.fromSizePrefixedBlobs(bytes)); + // System.out.println(Wires.fromSizePrefixedBlobs(bytes)); @NotNull List dataList = new ArrayList<>(); assertTrue(wire.readDocument(null, w -> w.read(() -> "mydata") @@ -438,7 +439,7 @@ public void example6() { wire2.writeDocument(false, w -> w.write(() -> "mydata") .sequence(v -> Stream.of(data).forEach(v::object))); - // System.out.println(Wires.fromSizePrefixedBlobs(bytes2)); + // System.out.println(Wires.fromSizePrefixedBlobs(bytes2)); @NotNull List dataList2 = new ArrayList<>(); assertTrue(wire2.readDocument(null, w -> w.read(() -> "mydata") @@ -499,12 +500,12 @@ public void example7() { @NotNull Data data = new Data("Hello World", 1234567890L, TimeUnit.NANOSECONDS, 10.50); wire.getValueOut().object(data); - // System.out.println(bytes); + // System.out.println(bytes); @Nullable Object o = wire.getValueIn().object(Object.class); if (o instanceof Data) { @Nullable Data data2 = (Data) o; - // System.out.println(data2); + // System.out.println(data2); } /* @@ -526,12 +527,12 @@ public void example7() { @NotNull Wire wire2 = new BinaryWire(bytes2); wire2.getValueOut().object(data); - // System.out.println(bytes2.toHexString()); + // System.out.println(bytes2.toHexString()); @Nullable Object o2 = wire2.getValueIn().object(Object.class); if (o2 instanceof Data) { @NotNull Data data2 = (Data) o2; - // System.out.println(data2); + // System.out.println(data2); } /* ``` @@ -550,10 +551,12 @@ public void example7() { bytes2.releaseLast(); } } + /* The code for the class Data ```java */ +@UsedViaReflection class Data extends SelfDescribingMarshallable { private String message; private long number; @@ -573,5 +576,6 @@ public Data(String message, long number, TimeUnit timeUnit, double price) { /* ``` */ - } + +// CHECKSTYLE:ON diff --git a/src/test/java/net/openhft/chronicle/wire/ReadmePojoTest.java b/src/test/java/net/openhft/chronicle/wire/ReadmePojoTest.java index 6019866076..e7f116cca5 100644 --- a/src/test/java/net/openhft/chronicle/wire/ReadmePojoTest.java +++ b/src/test/java/net/openhft/chronicle/wire/ReadmePojoTest.java @@ -14,6 +14,7 @@ import static net.openhft.chronicle.wire.WireType.TEXT; import static org.junit.Assert.assertEquals; +@SuppressWarnings({"deprecation", "removal"}) public class ReadmePojoTest extends WireTestCommon { static { // Registering 'MyPojos' class for aliasing purposes @@ -27,8 +28,7 @@ public void testFromString() throws IOException { mps.myPojos.add(new MyPojo("text1", 1, 1.1)); mps.myPojos.add(new MyPojo("text2", 2, 2.2)); - // System.out.println(mps); - // Convert MyPojos instance to string and back, then validate equality + // Convert MyPojos instance to string and back, then validate equality @Nullable MyPojos mps2 = Marshallable.fromString(mps.toString()); assertEquals(mps, mps2); @@ -49,7 +49,7 @@ public void testFromString() throws IOException { } @Test - public void testMapDump() throws IOException { + public void testMapDump() { // Creating a LinkedHashMap with various key-value pairs @NotNull Map map = new LinkedHashMap<>(); map.put("text", "words"); @@ -88,9 +88,9 @@ public void testMapDump() throws IOException { } static class MyPojo extends SelfDescribingMarshallable { - String text; // Textual data - int num; // Numerical value - double factor; // Floating point factor + final String text; // Textual data + final int num; // Numerical value + final double factor; // Floating point factor // Constructor for MyPojo MyPojo(String text, int num, double factor) { @@ -101,8 +101,9 @@ static class MyPojo extends SelfDescribingMarshallable { } static class MyPojos extends SelfDescribingMarshallable { - String name; // Name of the collection + final String name; // Name of the collection @NotNull + final List myPojos = new ArrayList<>(); // List of MyPojo objects // Constructor for MyPojos diff --git a/src/test/java/net/openhft/chronicle/wire/SequenceTest.java b/src/test/java/net/openhft/chronicle/wire/SequenceTest.java index 3440959ba5..02a33496a5 100644 --- a/src/test/java/net/openhft/chronicle/wire/SequenceTest.java +++ b/src/test/java/net/openhft/chronicle/wire/SequenceTest.java @@ -201,8 +201,8 @@ public void readMapAsObject() { // Static class My extending the SelfDescribingMarshallable class. static class My extends SelfDescribingMarshallable { - List stuff = new ArrayList<>(); // Instance variable to hold data. - transient List stuffBuffer = new ArrayList<>(); // Buffer for intermediate operations. + final List stuff = new ArrayList<>(); // Instance variable to hold data. + final transient List stuffBuffer = new ArrayList<>(); // Buffer for intermediate operations. // Method to read marshallable data from the wire. @Override diff --git a/src/test/java/net/openhft/chronicle/wire/SerializableObjectTest.java b/src/test/java/net/openhft/chronicle/wire/SerializableObjectTest.java index 1c324d6e05..6f487f3b73 100644 --- a/src/test/java/net/openhft/chronicle/wire/SerializableObjectTest.java +++ b/src/test/java/net/openhft/chronicle/wire/SerializableObjectTest.java @@ -6,9 +6,7 @@ import io.github.classgraph.*; import net.openhft.chronicle.bytes.Bytes; import net.openhft.chronicle.core.Jvm; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DynamicTest; -import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.api.*; import javax.sql.rowset.serial.SerialClob; import javax.swing.*; @@ -17,13 +15,13 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.math.MathContext; -import java.sql.Date; import java.sql.*; +import java.sql.Date; import java.text.SimpleDateFormat; import java.time.Instant; +import java.util.*; import java.util.List; import java.util.Queue; -import java.util.*; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Function; @@ -34,8 +32,6 @@ import java.util.stream.Stream; import static java.util.stream.Collectors.toSet; -import static org.junit.Assert.assertEquals; -import static org.junit.Assume.assumeFalse; // Test class to verify serializable objects with Wire. final class SerializableObjectTest extends WireTestCommon { @@ -81,6 +77,10 @@ final class SerializableObjectTest extends WireTestCommon { net.openhft.chronicle.wire.serializable.ScalarValues.class, net.openhft.chronicle.wire.serializable.Nested.class )); + // Predicate to check if a constructor is the default one. + private static final Predicate CONSTRUCTOR_IS_DEFAULT = methodInfo -> methodInfo.isPublic() && methodInfo.getTypeDescriptor().getTypeParameters().isEmpty(); + // Filter to exclude the ignored packages. + private static final ClassInfoList.ClassInfoFilter NOT_IGNORED = ci -> IGNORED_PACKAGES.stream().noneMatch(ip -> ci.getPackageName().startsWith(ip)); // Static block to handle specific classes that fail in certain Java versions. static { @@ -94,11 +94,6 @@ final class SerializableObjectTest extends WireTestCommon { } } - // Predicate to check if a constructor is the default one. - private static final Predicate CONSTRUCTOR_IS_DEFAULT = methodInfo -> methodInfo.isPublic() && methodInfo.getTypeDescriptor().getTypeParameters().isEmpty(); - // Filter to exclude the ignored packages. - private static final ClassInfoList.ClassInfoFilter NOT_IGNORED = ci -> IGNORED_PACKAGES.stream().noneMatch(ip -> ci.getPackageName().startsWith(ip)); - // Return test cases for different wire types and objects. private static Stream cases() { return wires() @@ -178,10 +173,7 @@ private static Stream handcraftedObjects() { // Instant.ofEpochMilli(TIME_MS), Color.BLUE, -// new MessageFormat("%s%n"), -// InetAddress.getLoopbackAddress(), new File("file") -// create(() -> new URL("http://chronicle.software/dir/files")) ).filter(SerializableObjectTest::isSerializableEqualsByObject); // Retain only those objects that are serializable and equivalent when reconstituted. } @@ -237,7 +229,7 @@ private static boolean isSerializableEqualsByObject(Object o) { * back to an object that is equal to the original. * * @param aClass The class to check. - * @param o An optional instance of the class to check. If null, a new instance will be created. + * @param o An optional instance of the class to check. If null, a new instance will be created. * @return true if the class is serializable and deserializable, and the original and deserialized objects are equal; false otherwise. */ private static boolean isSerializableEquals(Class aClass, Object o) { @@ -327,20 +319,20 @@ private static Stream wires() { // Assert that two objects are "equivalent" based on certain conditions private static void assertEqualEnough(Object a, Object b) { if (a.getClass() != b.getClass()) - assertEquals(a, b); + Assertions.assertEquals(a, b); if (a instanceof Throwable) { - assertEquals(a.getClass(), b.getClass()); - assertEquals(((Throwable) a).getMessage(), ((Throwable) b).getMessage()); + Assertions.assertEquals(a.getClass(), b.getClass()); + Assertions.assertEquals(((Throwable) a).getMessage(), ((Throwable) b).getMessage()); } else if (a instanceof Queue) { - assertEquals(a.toString(), b.toString()); + Assertions.assertEquals(a.toString(), b.toString()); } else { - assertEquals(a, b); + Assertions.assertEquals(a, b); } } @BeforeEach void hasDirect() { - assumeFalse(Jvm.maxDirectMemory() == 0); + Assumptions.assumeFalse(Jvm.maxDirectMemory() == 0); } @SuppressWarnings({"rawtypes", "unchecked"}) @@ -356,13 +348,13 @@ Stream test() { try { // Serialize and deserialize the object using the wire type final Wire wire = wireTypeObject.wireType.apply(bytes); - wire.getValueOut().object((Class) source.getClass(), source); + wire.getValueOut().object(source.getClass(), source); final Object target = wire.getValueIn().object(source.getClass()); // Assert the source and target objects are equivalent if (!(source instanceof Comparable) || ((Comparable) source).compareTo(target) != 0) { if (wireTypeObject.wireType == WireType.JSON || source instanceof EnumMap) - assertEquals(source.toString(), target.toString()); + Assertions.assertEquals(source.toString(), target.toString()); else assertEqualEnough(source, target); } @@ -386,8 +378,8 @@ public interface ThrowingSupplier { // Inner class representing a pairing of WireType and object for testing private static final class WireTypeObject { - WireType wireType; - Object object; + final WireType wireType; + final Object object; WireTypeObject(WireType wireType, Object object) { this.wireType = wireType; diff --git a/src/test/java/net/openhft/chronicle/wire/SizeLongConverterTest.java b/src/test/java/net/openhft/chronicle/wire/SizeLongConverterTest.java index 393bf392bd..36f2cc780b 100644 --- a/src/test/java/net/openhft/chronicle/wire/SizeLongConverterTest.java +++ b/src/test/java/net/openhft/chronicle/wire/SizeLongConverterTest.java @@ -9,7 +9,7 @@ public class SizeLongConverterTest { - private SizeLongConverter converter = SizeLongConverter.INSTANCE; + private final SizeLongConverter converter = SizeLongConverter.INSTANCE; @Test public void testParse() { diff --git a/src/test/java/net/openhft/chronicle/wire/SkipValueTest.java b/src/test/java/net/openhft/chronicle/wire/SkipValueTest.java index a4e7e19e5c..62999bf741 100644 --- a/src/test/java/net/openhft/chronicle/wire/SkipValueTest.java +++ b/src/test/java/net/openhft/chronicle/wire/SkipValueTest.java @@ -59,17 +59,15 @@ private static Consumer wr(Consumer valueOutConsumer) { @Parameterized.Parameters(name = "{index}: {0}") public static Collection data() throws IllegalAccessException { - // An array that will be populated with test cases. Object[][] list = { - // Here you define each test case. The array consists of: - // { name of wire code (filled out later), the code itself, a consumer to produce the value } + // { name of wire code (filled out later), the code itself, a consumer to produce the value } {null, BYTES_LENGTH8, wr(v -> v.object(Dto8.class, new Dto8()))}, {null, BYTES_LENGTH16, wr(v -> v.object(Dto16.class, new Dto16()))}, {null, BYTES_LENGTH32, wr(v -> v.object(Dto32.class, new Dto32()))}, -/* {null, BYTES_MARSHALLABLE, wr(v -> { - v.object(BM.class, new BM()); - v.wireOut().bytes().readPosition(5); - })},*/ + /* {null, BYTES_MARSHALLABLE, wr(v -> { + v.object(BM.class, new BM()); + v.wireOut().bytes().readPosition(5); + })}, */ {null, U8_ARRAY, wr(v -> { v.bytes(new byte[4]); v.wireOut().bytes().readPosition(2); @@ -88,9 +86,6 @@ public static Collection data() throws IllegalAccessException { {null, FLOAT_STOP_2, wr(v -> v.float64(1.23))}, {null, FLOAT_STOP_4, wr(v -> v.float64(0.0123))}, {null, FLOAT_STOP_6, wr(v -> v.float64(0.000123))}, -// public static final int FLOAT_SET_LOW_0 = 0x9A; -// public static final int FLOAT_SET_LOW_2 = 0x9B; -// public static final int FLOAT_SET_LOW_4 = 0x9C; {null, UUID, wr(v -> v.uuid(java.util.UUID.randomUUID()))}, {null, UINT8, wr(v -> v.uint8(129))}, {null, UINT16, wr(v -> v.uint16(65500))}, @@ -99,8 +94,6 @@ public static Collection data() throws IllegalAccessException { {null, INT16, wr(v -> v.int16(-32000))}, {null, INT32, wr(v -> v.int32(-65555))}, {null, INT64, wr(v -> v.int64(1234567890123456789L))}, -// public static final int SET_LOW_INT8 = 0xA8; -// public static final int SET_LOW_INT16 = 0xA9; {null, INT64_0x, wr(v -> v.int64_0x(1L << 63))}, {null, FALSE, wr(v -> v.bool(false))}, {null, TRUE, wr(v -> v.bool(true))}, @@ -109,17 +102,10 @@ public static Collection data() throws IllegalAccessException { {null, DATE_TIME, wr(v -> v.dateTime(LocalDateTime.now()))}, {null, ZONED_DATE_TIME, wr(v -> v.zonedDateTime(ZonedDateTime.now()))}, {null, TYPE_PREFIX, wr(v -> v.object(new Dto8()))}, -// public static final int FIELD_NAME_ANY = 0xB7; {null, STRING_ANY, wr(v -> v.text("Long string 012345678901234567890123456789"))}, -// public static final int EVENT_NAME = 0xB9; -// public static final int FIELD_NUMBER = 0xBA; {null, NULL, wr(v -> v.nu11())}, {null, TYPE_LITERAL, wr(v -> v.typeLiteral(String.class))}, -// public static final int EVENT_OBJECT = 0xBD; {null, COMMENT, wr(v -> v.wireOut().writeComment("hi").getValueOut().text("hi"))}, -// public static final int HINT = 0xBF; -// public static final int FIELD_NAME0 = 0xC0; -// public static final int FIELD_NAME31 = 0xDF; {null, STRING_0, wr(v -> v.text(""))}, {null, STRING_31, wr(v -> v.text("0123456789012345678901234567890"))}, }; diff --git a/src/test/java/net/openhft/chronicle/wire/StrangeTextCombinationTest.java b/src/test/java/net/openhft/chronicle/wire/StrangeTextCombinationTest.java index 15fd1ba12c..b916b882f5 100644 --- a/src/test/java/net/openhft/chronicle/wire/StrangeTextCombinationTest.java +++ b/src/test/java/net/openhft/chronicle/wire/StrangeTextCombinationTest.java @@ -17,8 +17,7 @@ // A parameterized test class that tests various string serialization behaviors for different WireTypes. @RunWith(value = Parameterized.class) public class StrangeTextCombinationTest extends net.openhft.chronicle.wire.WireTestCommon { - private WireType wireType; - private Bytes bytes; + private final WireType wireType; // Constructor initializes the WireType for this instance of the test. public StrangeTextCombinationTest(WireType wireType) { @@ -156,7 +155,7 @@ public void testXML() { // The Wire is backed by an on-heap elastic byte buffer. @NotNull private Wire wireFactory() { - bytes = Bytes.allocateElasticOnHeap(64); + Bytes bytes = Bytes.allocateElasticOnHeap(64); return wireType.apply(bytes); } } diff --git a/src/test/java/net/openhft/chronicle/wire/StreamMain.java b/src/test/java/net/openhft/chronicle/wire/StreamMain.java index 49306ff634..6b7a1c645d 100644 --- a/src/test/java/net/openhft/chronicle/wire/StreamMain.java +++ b/src/test/java/net/openhft/chronicle/wire/StreamMain.java @@ -11,6 +11,7 @@ import java.util.UUID; // Main class to demonstrate the serialization of data in various Wire formats. +@SuppressWarnings({"deprecation", "removal"}) public class StreamMain { public static void main(String[] args) { // Register the class alias for FileFormat class for efficient serialization. @@ -51,6 +52,7 @@ public static void main(String[] args) { } // Represents a file format with version, timestamp, creator, and other metadata. +@SuppressWarnings({"deprecation", "removal"}) class FileFormat extends SelfDescribingMarshallable { private int version = 100; private ZonedDateTime createdTime = ZonedDateTime.now(); diff --git a/src/test/java/net/openhft/chronicle/wire/StringConsumerMarshallableOutTest.java b/src/test/java/net/openhft/chronicle/wire/StringConsumerMarshallableOutTest.java index 051ebfd74e..36a649572f 100644 --- a/src/test/java/net/openhft/chronicle/wire/StringConsumerMarshallableOutTest.java +++ b/src/test/java/net/openhft/chronicle/wire/StringConsumerMarshallableOutTest.java @@ -3,7 +3,6 @@ */ package net.openhft.chronicle.wire; -import net.openhft.chronicle.wire.internal.StringConsumerMarshallableOut; import org.junit.Test; import java.io.StringWriter; @@ -11,6 +10,7 @@ import static org.junit.Assert.assertEquals; // Unit test class extending from WireTestCommon to get basic setup for the Chronicle Wire tests. +@SuppressWarnings({"deprecation", "removal"}) public class StringConsumerMarshallableOutTest extends net.openhft.chronicle.wire.WireTestCommon { // Test case to check if serialization to the YAML format works correctly. @@ -43,7 +43,7 @@ private void doTest(WireType wireType, String expected) { StringWriter sw = new StringWriter(); // StringWriter to hold the serialized data. // Create an instance of MarshallableOut which will write to the StringWriter. - MarshallableOut out = new StringConsumerMarshallableOut(s -> { + MarshallableOut out = new net.openhft.chronicle.wire.internal.StringConsumerMarshallableOut(s -> { sw.append(s); // Append serialized string. if (!s.endsWith("\n")) sw.append('\n'); // Add newline if not already present. diff --git a/src/test/java/net/openhft/chronicle/wire/TestJsonIssue467.java b/src/test/java/net/openhft/chronicle/wire/TestJsonIssue467.java index ee9c626047..2fc723fcc6 100644 --- a/src/test/java/net/openhft/chronicle/wire/TestJsonIssue467.java +++ b/src/test/java/net/openhft/chronicle/wire/TestJsonIssue467.java @@ -5,7 +5,6 @@ import net.openhft.chronicle.bytes.Bytes; import net.openhft.chronicle.bytes.OnHeapBytes; -import org.jetbrains.annotations.NotNull; import org.junit.Assert; import org.junit.Test; @@ -15,7 +14,6 @@ public class TestJsonIssue467 { static class ResponseItem467 extends SelfDescribingMarshallable { - @NotNull public String index; public final Bytes key = Bytes.allocateElasticOnHeap(); public Object payload; @@ -122,8 +120,7 @@ public void test2() { private static Wire jsonResponseItem() { CLASS_ALIASES.addAlias(ResponseItem467.class); String json = " {\"@ResponseItem467\":{\"index\":\"4dc800000034\",\"key\":\"notificationMsg\",\"payload\":\"Successfully debited your account by 0.0\"}}"; - final Wire jsonWire = WireType.JSON_ONLY.apply(Bytes.from(json)); - return jsonWire; + return WireType.JSON_ONLY.apply(Bytes.from(json)); } @Test diff --git a/src/test/java/net/openhft/chronicle/wire/TestLongConversion.java b/src/test/java/net/openhft/chronicle/wire/TestLongConversion.java index 3ae27b514d..19c40e9d1e 100644 --- a/src/test/java/net/openhft/chronicle/wire/TestLongConversion.java +++ b/src/test/java/net/openhft/chronicle/wire/TestLongConversion.java @@ -14,7 +14,7 @@ @RunWith(value = Parameterized.class) public class TestLongConversion { - private static char SEPARATOR = '/'; + private static final char SEPARATOR = '/'; private final LongConverter longConverter; @Parameterized.Parameters diff --git a/src/test/java/net/openhft/chronicle/wire/TestMarshallable.java b/src/test/java/net/openhft/chronicle/wire/TestMarshallable.java index ea2546bfa5..e7ca3ebc22 100644 --- a/src/test/java/net/openhft/chronicle/wire/TestMarshallable.java +++ b/src/test/java/net/openhft/chronicle/wire/TestMarshallable.java @@ -12,7 +12,7 @@ class TestMarshallable extends SelfDescribingMarshallable { // Defining a non-null StringBuilder field named 'name' to store a name value, // initializing it to an empty StringBuilder instance @NotNull - private StringBuilder name = new StringBuilder(); + private final StringBuilder name = new StringBuilder(); // Defining an integer field named 'count' to store a count value private int count; diff --git a/src/test/java/net/openhft/chronicle/wire/TextBinaryWireTest.java b/src/test/java/net/openhft/chronicle/wire/TextBinaryWireTest.java index da54fc4007..7c196715b6 100644 --- a/src/test/java/net/openhft/chronicle/wire/TextBinaryWireTest.java +++ b/src/test/java/net/openhft/chronicle/wire/TextBinaryWireTest.java @@ -22,6 +22,7 @@ // Use Parameterized runner for performing tests with different WireType instances. @RunWith(value = Parameterized.class) +@SuppressWarnings({"deprecation", "removal"}) public class TextBinaryWireTest extends WireTestCommon { // The specific WireType for the current test run. diff --git a/src/test/java/net/openhft/chronicle/wire/TextCompatibilityTest.java b/src/test/java/net/openhft/chronicle/wire/TextCompatibilityTest.java index 35b9ca08a9..9aad07b198 100644 --- a/src/test/java/net/openhft/chronicle/wire/TextCompatibilityTest.java +++ b/src/test/java/net/openhft/chronicle/wire/TextCompatibilityTest.java @@ -84,18 +84,14 @@ private static void runTest(String filename, String expectedFilename, boolean pr if (s.trim().equals(expected.trim())) return; if (print) { - // System.out.println("Comparison failure in " + filename); - // System.out.println("Expected:\n" + expected); - // System.out.println("Actual:\n" + s); - } else { - assertEquals(expected, s); + return; } + assertEquals(expected, s); } finally { bytes.releaseLast(); } Object o = TEXT.fromFile(Object.class, filename); } catch (Exception e) { - // System.out.println("Expected:\n" + expected); throw new AssertionError(filename, e); } } diff --git a/src/test/java/net/openhft/chronicle/wire/TextDocumentTest.java b/src/test/java/net/openhft/chronicle/wire/TextDocumentTest.java index 635df5ae55..199e5fff2b 100644 --- a/src/test/java/net/openhft/chronicle/wire/TextDocumentTest.java +++ b/src/test/java/net/openhft/chronicle/wire/TextDocumentTest.java @@ -19,6 +19,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assume.assumeFalse; +@SuppressWarnings({"deprecation", "removal"}) public class TextDocumentTest extends WireTestCommon { // A helper function that performs the test on documents given a wireType. diff --git a/src/test/java/net/openhft/chronicle/wire/TextWireAgitatorTest.java b/src/test/java/net/openhft/chronicle/wire/TextWireAgitatorTest.java index be9b127fea..a0ff73908e 100644 --- a/src/test/java/net/openhft/chronicle/wire/TextWireAgitatorTest.java +++ b/src/test/java/net/openhft/chronicle/wire/TextWireAgitatorTest.java @@ -8,8 +8,6 @@ import net.openhft.chronicle.core.util.ClassNotFoundRuntimeException; import org.junit.Test; -import java.util.Map; - import static org.junit.Assert.*; import static org.junit.Assume.assumeFalse; diff --git a/src/test/java/net/openhft/chronicle/wire/TextWireTest.java b/src/test/java/net/openhft/chronicle/wire/TextWireTest.java index f4014110ee..53dd38f0b0 100644 --- a/src/test/java/net/openhft/chronicle/wire/TextWireTest.java +++ b/src/test/java/net/openhft/chronicle/wire/TextWireTest.java @@ -3,7 +3,10 @@ */ package net.openhft.chronicle.wire; -import net.openhft.chronicle.bytes.*; +import net.openhft.chronicle.bytes.Bytes; +import net.openhft.chronicle.bytes.BytesStore; +import net.openhft.chronicle.bytes.MethodReader; +import net.openhft.chronicle.bytes.PointerBytesStore; import net.openhft.chronicle.bytes.internal.NoBytesStore; import net.openhft.chronicle.core.Jvm; import net.openhft.chronicle.core.annotation.UsedViaReflection; @@ -51,7 +54,7 @@ public class TextWireTest extends WireTestCommon { // Create a new TextWire instance with an elastic heap allocated buffer - private static Wire wire = WireType.TEXT.apply(Bytes.allocateElasticOnHeap()); + private static final Wire wire = WireType.TEXT.apply(Bytes.allocateElasticOnHeap()); private Bytes bytes; @Before @@ -92,7 +95,7 @@ public void testWhiteSpaceInType() { // Test handling of Bytes data type in TextWire. @Test public void testBytes() { - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); @NotNull byte[] allBytes = new byte[256]; for (int i = 0; i < 256; i++) allBytes[i] = (byte) i; @@ -116,7 +119,7 @@ public void testBytes() { // Test handling of comments in TextWire. @Test public void comment() { - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); wire.writeComment("\thi: omg"); wire.write("hi").text("there"); assertEquals("there", wire.read("hi").text()); @@ -1189,9 +1192,9 @@ public void testABCDBytes() { // Test the string building behavior for ABC objects with Wire. @Test public void testABCStringBuilder() { - String A = "A: \"hi\", # This is an A\n"; - String B = "B: 'hi', # This is a B\n"; - String C = "C: hi, # And that's a C\n"; + String stringA = "A: \"hi\", # This is an A\n"; + String stringB = "B: 'hi', # This is a B\n"; + String stringC = "C: hi, # And that's a C\n"; // Create a wire and append values for A, B, and C @NotNull Wire wire = createWire(); @@ -1200,7 +1203,13 @@ public void testABCStringBuilder() { ABC abc = new ABC(); // Read from wire and assert its value for all permutations - for (String input : new String[] { A + B + C, B + A + C, C + A + B, A + C + B, B + C + A, C + B + A }) { + for (String input : new String[]{ + stringA + stringB + stringC, + stringB + stringA + stringC, + stringC + stringA + stringB, + stringA + stringC + stringB, + stringB + stringC + stringA, + stringC + stringB + stringA}) { wire.reset(); wire.bytes().append(input); assertEquals(input, "!net.openhft.chronicle.wire.TextWireTest$ABC {\n" + @@ -1282,7 +1291,7 @@ public void testBytesField() { @Test public void testWriteMarshallable() { // Create wire instance - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); @NotNull MyTypesCustom mtA = new MyTypesCustom(); mtA.flag = true; mtA.d = 123.456; @@ -1338,7 +1347,7 @@ public void testWriteMarshallable() { @Test public void testWriteMarshallableAndFieldLength() { // Create wire instance - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); @NotNull MyTypesCustom mtA = new MyTypesCustom(); mtA.flag = true; mtA.d = 123.456; @@ -1348,13 +1357,13 @@ public void testWriteMarshallableAndFieldLength() { @NotNull ValueOut write = wire.write(() -> "A"); // Determine the start position for field length calculation - long start = wire.bytes().writePosition() + 1; // including one space for "sep". + final long start = wire.bytes().writePosition() + 1; // including one space for "sep". // Write the Marshallable instance to wire write.marshallable(mtA); // Calculate the length of written field - long fieldLen = wire.bytes().lengthWritten(start); + final long fieldLen = wire.bytes().lengthWritten(start); // Assert the string format of wire after writing expectWithSnakeYaml("{A={B_FLAG=true, S_NUM=12345, D_NUM=123.456, L_NUM=0, I_NUM=-12345789, TEXT=}}", wire); @@ -1362,7 +1371,7 @@ public void testWriteMarshallableAndFieldLength() { @NotNull ValueIn read = wire.read(() -> "A"); // Determine the length of the read field - long len = read.readLength(); + final long len = read.readLength(); // Assert the equality of calculated field lengths assertEquals(fieldLen, len, 1); @@ -1730,14 +1739,14 @@ public void testStringMap() { @Nullable Map map = wire.read().object(Map.class); assertEquals(0, map.size()); - // TODO we shouldn't need to create a new wire. + // TODO we should not need to create a new wire. // wire = createWire(); -// + // // Set threeObjects = new HashSet(Arrays.asList(new String[]{"abc", "def", "ghi"})); // wire.write().object(threeObjects); -// + // // Set list2 = wire.read() - // .object(Set.class); + // .object(Set.class); // assertEquals(3, list2.size()); // assertEquals("[abc, def, ghi]", list2.toString()); } @@ -1745,7 +1754,7 @@ public void testStringMap() { // This test case demonstrates how to decode nested structures from a textual representation. @Test public void testNestedDecode() { - @NotNull String s = "cluster: {\n" + + final String s = "cluster: {\n" + " host1: {\n" + " hostId: 1,\n" + // " name: one,\n" + @@ -1891,7 +1900,7 @@ public void two() { @Test public void testByteArray() { // Initialize a new Wire instance. - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); // Enable padding for the Wire. wire.usePadding(true); @@ -1908,16 +1917,15 @@ public void testByteArray() { wire.writeDocument(false, w -> w.write("four").object(four)); // Validate the written content on the Wire. - assertEquals("" + - "--- !!data\n" + + assertEquals("--- !!data\n" + "nothing: !byte[] !!binary\n" + "# position: 32, header: 1\n" + "--- !!data\n" + "one: !byte[] !!binary AQ==\n" + "# position: 64, header: 2\n" + "--- !!data\n" + - "four: !byte[] !!binary AQIDBA==\n" - , Wires.fromSizePrefixedBlobs(wire.bytes())); + "four: !byte[] !!binary AQIDBA==\n", + Wires.fromSizePrefixedBlobs(wire.bytes())); // Read back each byte array from the Wire and verify its contents. wire.readDocument(null, w -> assertArrayEquals(new byte[0], (byte[]) w.read(() -> "nothing").object())); @@ -1934,7 +1942,7 @@ public void testObjectKeys() { map.put(new MyMarshallable("key2"), "value2"); // Initialize a new Wire instance. - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); // Disable padding for the Wire. wire.usePadding(false); @@ -1950,8 +1958,8 @@ public void testObjectKeys() { "? { MyField: parent }: {\n" + " ? !net.openhft.chronicle.wire.MyMarshallable { MyField: key1 }: value1,\n" + " ? !net.openhft.chronicle.wire.MyMarshallable { MyField: key2 }: value2\n" + - "}\n" - , Wires.fromSizePrefixedBlobs(wire.bytes())); + "}\n", + Wires.fromSizePrefixedBlobs(wire.bytes())); // Read back the map from the Wire and verify its contents. wire.readDocument(null, w -> { @@ -1967,13 +1975,13 @@ public void testObjectKeys() { // Test for attempting to serialize a non-serializable object (current thread). @Test(expected = IllegalArgumentException.class) - public void writeUnserializable1() throws IOException { + public void writeUnserializable1() { System.out.println(TEXT.asString(Thread.currentThread())); } // Test for attempting to serialize a non-serializable object (socket instance). @Test(expected = IllegalArgumentException.class) - public void writeUnserializable2() throws IOException { + public void writeUnserializable2() { @NotNull Socket s = new Socket(); System.out.println(TEXT.asString(s)); } @@ -1989,7 +1997,7 @@ public void writeUnserializable3() throws IOException { @Test public void writeCharacter() { // Initialize a new Wire instance. - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); // Define a set of characters to test with. for (char ch : new char[]{0, '!', 'a', Character.MAX_VALUE}) { @@ -2006,7 +2014,7 @@ public void writeCharacter() { @Test public void testSortedSet() { // Initialize a new Wire instance. - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); // Create a SortedSet (TreeSet) and populate it with strings. @NotNull SortedSet set = new TreeSet<>(); @@ -2034,7 +2042,7 @@ public void testSortedSet() { @Test public void testSortedMap() { // Initialize a new Wire instance. - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); // Create a SortedMap (TreeMap) and populate it with key-value pairs. @NotNull SortedMap set = new TreeMap<>(); @@ -2063,7 +2071,7 @@ public void testSortedMap() { public void testStringArray() { // Initialize a new Wire instance and append a serialized StringArray object to it. @NotNull Wire wire = createWire(); - wire.bytes().append("!" + StringArray.class.getName() + " { strings: [ a, b, c ] }"); + wire.bytes().append("!").append(StringArray.class.getName()).append(" { strings: [ a, b, c ] }"); // Deserialize the StringArray from the Wire and validate its content. StringArray sa = wire.getValueIn() @@ -2072,7 +2080,7 @@ public void testStringArray() { // Repeat the test with a different serialized StringArray. @NotNull Wire wire2 = createWire(); - wire2.bytes().append("!" + StringArray.class.getName() + " { strings: abc }"); + wire2.bytes().append("!").append(StringArray.class.getName()).append(" { strings: abc }"); // Deserialize the StringArray and validate its content. StringArray sa2 = wire2.getValueIn() @@ -2102,12 +2110,6 @@ public void testSetBytesAfterDeserialization() { bw.bytes.releaseLast(); } - /** - * Tests the serialization and deserialization process for the DoubleWrapper class. - * This test ensures that double values in the DoubleWrapper class are correctly serialized - * to their engineering notation (where appropriate) and deserialized back to their original - * values. It also tests the use of a class alias for a more concise serialization format. - */ @Test public void testDoubleEngineering() { // Registering an alias 'D' for the DoubleWrapper class to shorten the serialized format. @@ -2164,7 +2166,7 @@ public void testDoubleEngineering() { assertEquals(10e6, dw5.d, 0); } - // Tests the consistency of serialization and deserialization of NestedList objects and various property combinations. + // Tests the consistency of serialization and deserialization of NestedList objects and various property combinations. @Test public void testNestedList() { // Create a NestedList instance from its serialized string representation. @@ -2222,6 +2224,8 @@ public void testNestedList() { case 3: cs += " num: 128,\n"; break; + default: + throw new IllegalStateException("Unexpected selector"); } z /= 4; } @@ -2295,7 +2299,7 @@ public void readMarshallableAsEnum() { @Test public void nestedWithEnumSet() { // Create a Wire instance and a NestedWithEnumSet object - Wire wire = createWire(); + final Wire wire = createWire(); NestedWithEnumSet n = new NestedWithEnumSet(); n.list.add(new WithEnumSet("none")); n.list.add(new WithEnumSet("one", EnumSet.of(TimeUnit.DAYS))); @@ -2368,7 +2372,7 @@ public void testDoublePrecisionOverTextWire() { final double d2 = textWire.getValueIn().float64(); // Validate the double value remains consistent after the transfer - Assert.assertEquals(d2, d, 0); + Assert.assertEquals(d, d2, 0); } @Test @@ -2477,7 +2481,7 @@ public void readsComment() { } // Setup a method reader to capture DTOs - final MethodReader reader = wire.methodReader((BinaryWireTest.IDTO) dto -> sb.append("dto: " + dto + "\n")); + final MethodReader reader = wire.methodReader((BinaryWireTest.IDTO) dto -> sb.append("dto: ").append(dto).append("\n")); // Validate the read comments and DTO assertTrue(reader.readOne()); @@ -2545,7 +2549,7 @@ public void testNestedListInterleavedComments() { " # fin\n"); // Assert that the object was deserialized correctly without being affected by the comments. - assertArrayEquals(obj.strings, new String[] { "bar", "quux" }); + assertArrayEquals(new String[]{"bar", "quux"}, obj.strings); } @Test @@ -2553,16 +2557,16 @@ public void testListInterleavedComments() { // Deserialize a string containing a list with interleaved comments to an object. List obj = Marshallable.fromString( " # first\n" + - "[\n" + - " # foo\n" + - " 'bar',\n" + - " # baz\n" + - " 'quux'\n" + - " # thud\n" + - "]\n" + - " # fin\n"); - - // Assert that the object was deserialized correctly without being affected by the comments. + "[\n" + + " # foo\n" + + " 'bar',\n" + + " # baz\n" + + " 'quux'\n" + + " # thud\n" + + "]\n" + + " # fin\n"); + + // Assert that the object was deserialised correctly without being affected by the comments. assertEquals(obj, Arrays.asList("bar", "quux")); } @@ -2589,8 +2593,8 @@ static class MapHolder extends SelfDescribingMarshallable { // Class representing a field having an Enum type and a byte array static final class FieldWithEnum extends SelfDescribingMarshallable { - private byte[] allowedFoos; private final OrderLevel orderLevel = OrderLevel.PARENT; + private byte[] allowedFoos; } // Class containing a field with an associated comment @@ -2614,7 +2618,7 @@ static class TwoFields extends AbstractMarshallableCfg { int d; int notThere; // transient Map to hold other unexpected fields - transient Map others = new LinkedHashMap<>(); + final transient Map others = new LinkedHashMap<>(); @Override public void unexpectedField(Object event, ValueIn valueIn) { @@ -2622,13 +2626,13 @@ public void unexpectedField(Object event, ValueIn valueIn) { } } - // Class with fields of Bytes type initialized with various Byte buffers + // Class with fields of Bytes type initialised with various Byte buffers. @SuppressWarnings("java:S116") // Keep A,B,C,D uppercase to match expected YAML keys in assertions static class ABCD extends SelfDescribingMarshallable implements Monitorable { - Bytes A = Bytes.allocateElasticDirect(); - Bytes B = Bytes.allocateDirect(64); - Bytes C = Bytes.allocateElasticOnHeap(); - Bytes D = Bytes.allocateElasticOnHeap(1); + final Bytes A = Bytes.allocateElasticDirect(); + final Bytes B = Bytes.allocateDirect(64); + final Bytes C = Bytes.allocateElasticOnHeap(); + final Bytes D = Bytes.allocateElasticOnHeap(1); // Method to release all byte buffers void releaseAll() { @@ -2674,6 +2678,7 @@ static class StringArray implements Marshallable { // Class wrapping a Bytes field and providing a method to set it static class BytesWrapper extends SelfDescribingMarshallable { @NotNull + final Bytes bytes = allocateElasticDirect(); void bytes(@NotNull CharSequence cs) { @@ -2684,8 +2689,8 @@ void bytes(@NotNull CharSequence cs) { // Class wrapping two double fields with a constructor to set them static class DoubleWrapper extends SelfDescribingMarshallable { - double d; - double n; + final double d; + final double n; DoubleWrapper(double d) { this.d = d; @@ -2696,10 +2701,10 @@ static class DoubleWrapper extends SelfDescribingMarshallable { // Class representing a nested list structure, capable of marshallable reading. static class NestedList extends SelfDescribingMarshallable { String name; - List listA = new ArrayList<>(); - List listB = new ArrayList<>(); - transient List listA2 = new ArrayList<>(); - transient List listB2 = new ArrayList<>(); + final List listA = new ArrayList<>(); + final List listB = new ArrayList<>(); + final transient List listA2 = new ArrayList<>(); + final transient List listB2 = new ArrayList<>(); int num; // Override readMarshallable to define custom deserialization logic from a wire format. @@ -2721,7 +2726,7 @@ private static class NestedItem extends SelfDescribingMarshallable { // Class encapsulating a list of WithEnumSet instances, providing a structure for nesting. static class NestedWithEnumSet extends SelfDescribingMarshallable { - List list = new ArrayList<>(); + final List list = new ArrayList<>(); } // Class representing an item that pairs a name with a set of TimeUnit enumeration items. @@ -2754,7 +2759,7 @@ public void writeMarshallable(@NotNull WireOut wire) { // Class holding a list of strings with customized marshallable reading. static class MyDto extends SelfDescribingMarshallable { - List strings = new ArrayList<>(); + final List strings = new ArrayList<>(); // Define a custom way to read objects of this type from the wire format. public void readMarshallable(@NotNull WireIn wire) throws IORuntimeException { @@ -2795,9 +2800,11 @@ public void writeMarshallable(@NotNull WireOut wire) { static class TwoLongs extends SelfDescribingMarshallable { @LongConversion(HexadecimalLongConverter.class) + final long hexadecimal; @LongConversion(HexadecimalLongConverter.class) + final long hexa2; // Constructor initializing both long fields. @@ -2809,8 +2816,8 @@ static class TwoLongs extends SelfDescribingMarshallable { // Class encapsulating an integer and a Duration object, to be serialized/deserialized. static class DurationHolder extends SelfDescribingMarshallable { - int foo; - Duration duration; + final int foo; + final Duration duration; // Constructor initializing both fields. DurationHolder(int foo, Duration duration) { @@ -2820,6 +2827,6 @@ static class DurationHolder extends SelfDescribingMarshallable { } // Basic class capable of being serialized/deserialized without field definition. - private class Circle implements Marshallable { + private static class Circle implements Marshallable { } } diff --git a/src/test/java/net/openhft/chronicle/wire/ThrowableTest.java b/src/test/java/net/openhft/chronicle/wire/ThrowableTest.java index fa60075cdb..38ae37e21d 100644 --- a/src/test/java/net/openhft/chronicle/wire/ThrowableTest.java +++ b/src/test/java/net/openhft/chronicle/wire/ThrowableTest.java @@ -24,16 +24,10 @@ public void writeReadThrowable() { Wire wire = wireType.apply(Bytes.allocateElasticDirect()); try (DocumentContext dc = wire.writingDocument()) { // Initialize the Throwable object with a message and cause - Throwable message = new Throwable("message"); - message.initCause(new Throwable("cause")); + Throwable message = new Throwable("message", new Throwable("cause")); dc.wire().getValueOut() .object(message); } -/* if (wireType == WireType.TEXT) - System.out.println(wire); - else - System.out.println(wire.bytes().toHexString()+"\n"+Wires.fromSizePrefixedBlobs(wire.bytes()));*/ - assumeFalse(Jvm.maxDirectMemory() == 0); // Read the written Throwable and validate its content try (DocumentContext dc = wire.readingDocument()) { diff --git a/src/test/java/net/openhft/chronicle/wire/TimestampLongConverterTest.java b/src/test/java/net/openhft/chronicle/wire/TimestampLongConverterTest.java index 0f126cc0d9..da616e9c52 100644 --- a/src/test/java/net/openhft/chronicle/wire/TimestampLongConverterTest.java +++ b/src/test/java/net/openhft/chronicle/wire/TimestampLongConverterTest.java @@ -20,7 +20,7 @@ * This class replaces the need for separate Milli, Micro, and Nano test classes, * reducing code duplication and improving maintainability. */ -@SuppressWarnings("unused") +@SuppressWarnings({"unused", "deprecation", "removal"}) class TimestampLongConverterTest extends WireTestCommon { // Defines the data sets for each converter (Milli, Micro, Nano) diff --git a/src/test/java/net/openhft/chronicle/wire/TimestampLongConverterZoneIdsTest.java b/src/test/java/net/openhft/chronicle/wire/TimestampLongConverterZoneIdsTest.java index d4b2389be1..738dfd8408 100644 --- a/src/test/java/net/openhft/chronicle/wire/TimestampLongConverterZoneIdsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/TimestampLongConverterZoneIdsTest.java @@ -24,6 +24,7 @@ // Running the test class in a parameterized manner. @RunWith(value = Parameterized.class) +@SuppressWarnings({"deprecation", "removal"}) public class TimestampLongConverterZoneIdsTest extends WireTestCommon { private final Future future; @@ -81,7 +82,7 @@ public NanoTimestampLongConverter createConverter(String zoneId) { }; // The sample time in UTC for each converter type. - long sampleTimeInUTC; + final long sampleTimeInUTC; ConverterType(long sampleTimeInUTC) { this.sampleTimeInUTC = sampleTimeInUTC; diff --git a/src/test/java/net/openhft/chronicle/wire/TriviallyCopyableJLBH.java b/src/test/java/net/openhft/chronicle/wire/TriviallyCopyableJLBH.java index d444818915..2c19032a15 100644 --- a/src/test/java/net/openhft/chronicle/wire/TriviallyCopyableJLBH.java +++ b/src/test/java/net/openhft/chronicle/wire/TriviallyCopyableJLBH.java @@ -18,18 +18,6 @@ @SuppressWarnings("this-escape") public class TriviallyCopyableJLBH implements JLBHTask { - enum HouseType { - TRIVIALLY_COPYABLE, - BINARY_WIRE, - UNKNOWN; - } - - // use -Dio.type=binary or trivial to set. Defaults to binary - private HouseType type = HouseType.UNKNOWN; - - // use -Dcpu=N to set. Defaults to 2 - private final int CPU; - static { System.setProperty("jvm.resource.tracing", "false"); CLASS_ALIASES.addAlias(TriviallyCopyableHouse.class, "House1"); @@ -38,93 +26,41 @@ enum HouseType { System.setProperty("jvm.resource.tracing", "false"); } - public interface BaseHouse { - BaseHouse address(CharSequence owner); - - } - - /** - * Using Trivially Copyable Objects To Improve Java Serialisation Speeds - */ - public static class TriviallyCopyableHouse extends BytesInBinaryMarshallable implements BaseHouse { - - @FieldGroup("address") - // 5 longs, each at 8 bytes = 40 bytes, so we can store a String with up to 40 ISO-8859 characters - private long text4a, text4b, text4c, text4d, text4e; - private transient Bytes address = Bytes.forFieldGroup(this, "address"); - - private static final int[] START_END = BytesUtil.triviallyCopyableRange(TriviallyCopyableHouse.class); - private static final int START = START_END[0]; - private static final int LENGTH = START_END[1] - START_END[0]; - - public BaseHouse address(CharSequence owner) { - address.clear().append(owner); - return this; - } - - // reads the bytes and updates 'this' instance, with the data in the bytes. - @Override - public void readMarshallable(BytesIn bytes) { - bytes.unsafeReadObject(this, START, LENGTH); - } - - // reads 'this' instance and writes a copy of it to the bytes. - @Override - public void writeMarshallable(BytesOut bytes) { - bytes.unsafeWriteObject(this, START, LENGTH); - } - - // the amount of data data in `this` - @Override - public BinaryLengthLength binaryLengthLength() { - return BinaryLengthLength.LENGTH_8BIT; - } - } - - public static class House extends SelfDescribingMarshallable implements BaseHouse { - - final Bytes address = Bytes.allocateDirect(128); - - public BaseHouse address(CharSequence owner) { - address.clear().append(owner); - return this; - } - } - - private JLBH lth; + // use -Dcpu=N to set. Defaults to 2 + private final int cpu; private final BaseHouse originalHouse; - - private BaseHouse newHouse(HouseType type) { - return type == HouseType.TRIVIALLY_COPYABLE ? new TriviallyCopyableHouse() : new House(); - } - private final BaseHouse targetHouse; - private final Wire wire = WireType.BINARY.apply(Bytes.allocateDirect(1024)); + // use -Dio.type=binary or trivial to set. Defaults to binary + private HouseType type = HouseType.UNKNOWN; + private JLBH lth; - public static void main(String[] args) { - new TriviallyCopyableJLBH().test(); - System.exit(0); - } - - private TriviallyCopyableJLBH() - { + private TriviallyCopyableJLBH() { String ioType = System.getProperty("io.type", "binary"); - if(ioType.equals("binary")) { + if (ioType.equals("binary")) { type = HouseType.BINARY_WIRE; - } else if(ioType.equals("trivial")) { + } else if (ioType.equals("trivial")) { type = HouseType.TRIVIALLY_COPYABLE; } else { System.out.println("-Dio.type must be \"binary\" or \"trivial\""); System.exit(-1); } - CPU = Integer.parseInt(System.getProperty("cpu", "2")); + cpu = Integer.parseInt(System.getProperty("cpu", "2")); originalHouse = newHouse(type).address("82 St John Street, Clerkenwell"); targetHouse = newHouse(type); } + public static void main(String[] args) { + new TriviallyCopyableJLBH().test(); + System.exit(0); + } + + private BaseHouse newHouse(HouseType type) { + return type == HouseType.TRIVIALLY_COPYABLE ? new TriviallyCopyableHouse() : new House(); + } + private void test() { deleteDirWithFiles("tmp"); @NotNull JLBHOptions jlbhOptions = new JLBHOptions() @@ -132,7 +68,7 @@ private void test() { .iterations(1_000_000) .throughput(100_000) .accountForCoordinatedOmission(false) - .acquireLock(()->AffinityLock.acquireLock(CPU)) + .acquireLock(() -> AffinityLock.acquireLock(cpu)) .recordOSJitter(false) .runs(5) .jlbhTask(this); @@ -160,4 +96,62 @@ private Class houseType(HouseType type) { public void init(JLBH lth) { this.lth = lth; } + + enum HouseType { + TRIVIALLY_COPYABLE, + BINARY_WIRE, + UNKNOWN + } + + public interface BaseHouse { + BaseHouse address(CharSequence owner); + + } + + /** + * Using Trivially Copyable Objects To Improve Java Serialisation Speeds + */ + public static class TriviallyCopyableHouse extends BytesInBinaryMarshallable implements BaseHouse { + + private static final int[] START_END = BytesUtil.triviallyCopyableRange(TriviallyCopyableHouse.class); + private static final int START = START_END[0]; + private static final int LENGTH = START_END[1] - START_END[0]; + @FieldGroup("address") + // 5 longs, each at 8 bytes = 40 bytes, so we can store a String with up to 40 ISO-8859 characters + private long text4a, text4b, text4c, text4d, text4e; + private final transient Bytes address = Bytes.forFieldGroup(this, "address"); + + public BaseHouse address(CharSequence owner) { + address.clear().append(owner); + return this; + } + + // reads the bytes and updates 'this' instance, with the data in the bytes. + @Override + public void readMarshallable(BytesIn bytes) { + bytes.unsafeReadObject(this, START, LENGTH); + } + + // reads 'this' instance and writes a copy of it to the bytes. + @Override + public void writeMarshallable(BytesOut bytes) { + bytes.unsafeWriteObject(this, START, LENGTH); + } + + // the amount of data data in `this` + @Override + public BinaryLengthLength binaryLengthLength() { + return BinaryLengthLength.LENGTH_8BIT; + } + } + + public static class House extends SelfDescribingMarshallable implements BaseHouse { + + final Bytes address = Bytes.allocateDirect(128); + + public BaseHouse address(CharSequence owner) { + address.clear().append(owner); + return this; + } + } } diff --git a/src/test/java/net/openhft/chronicle/wire/TupleInvocationHandlerTest.java b/src/test/java/net/openhft/chronicle/wire/TupleInvocationHandlerTest.java index 804e529e14..ab462c477c 100644 --- a/src/test/java/net/openhft/chronicle/wire/TupleInvocationHandlerTest.java +++ b/src/test/java/net/openhft/chronicle/wire/TupleInvocationHandlerTest.java @@ -36,8 +36,8 @@ public void tupleSupportsFieldApiAndDeepCopy() throws InvalidMarshallableExcepti int hash = tuple.hashCode(); assertTrue(hash != 0); - assertTrue(tuple.equals(tuple)); - assertFalse(tuple.equals("other")); + assertEquals(tuple, tuple); + assertNotEquals("other", tuple); SampleTuple copy = tuple.deepCopy(); assertNotNull(copy); @@ -58,9 +58,9 @@ public void tupleSupportsFieldApiAndDeepCopy() throws InvalidMarshallableExcepti } interface SampleTuple extends Marshallable { - void setField(String name, Object value) throws NoSuchFieldException; + void setField(String name, Object value); - T getField(String name, Class type) throws NoSuchFieldException; + T getField(String name, Class type); List $fieldInfos(); } diff --git a/src/test/java/net/openhft/chronicle/wire/UnicodeStringTest.java b/src/test/java/net/openhft/chronicle/wire/UnicodeStringTest.java index 84bfdb5c6b..eb603ea9e0 100644 --- a/src/test/java/net/openhft/chronicle/wire/UnicodeStringTest.java +++ b/src/test/java/net/openhft/chronicle/wire/UnicodeStringTest.java @@ -25,13 +25,13 @@ public class UnicodeStringTest extends WireTestCommon { @SuppressWarnings("rawtypes") @NotNull // Static byte buffer used for wire operations - private static Bytes bytes = nativeBytes(); + private static final Bytes bytes = nativeBytes(); // Wire object to handle serialization and deserialization - private static Wire wire = createWire(); + private static final Wire wire = createWire(); // Char array to be used in tests - private static char[] chars = new char[128]; + private static final char[] chars = new char[128]; // Character under test private final char ch; diff --git a/src/test/java/net/openhft/chronicle/wire/UnknownFieldsTest.java b/src/test/java/net/openhft/chronicle/wire/UnknownFieldsTest.java index 4646bac151..fa2adc713c 100644 --- a/src/test/java/net/openhft/chronicle/wire/UnknownFieldsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/UnknownFieldsTest.java @@ -11,6 +11,7 @@ * Checks that exception raised by {@link ReadMarshallable#unexpectedField(Object, ValueIn)} * is thrown back to the user call. */ +@SuppressWarnings({"deprecation", "removal"}) public class UnknownFieldsTest extends WireTestCommon { // Static initialization block to add class aliases to ClassAliasPool for the test variations @@ -24,12 +25,11 @@ public class UnknownFieldsTest extends WireTestCommon { @Test public void testExceptionIsNotSwallowed() { try { - WireType.TEXT.fromString - ("!Variation1 {\n" + - " object: !Inner {\n" + - " unknown: true" + - " }\n" + - "}\n"); + WireType.TEXT.fromString("!Variation1 {\n" + + " object: !Inner {\n" + + " unknown: true" + + " }\n" + + "}\n"); Assert.fail(); // If no exception is thrown, the test should fail } catch (UnexpectedFieldHandlingException e) { // Verify that the cause of the exception is as expected @@ -41,12 +41,11 @@ public void testExceptionIsNotSwallowed() { @Test public void testExceptionIsNotTransformed() { try { - WireType.TEXT.fromString - ("!Variation2 {\n" + - " object: !Inner {\n" + - " unknown: true\n" + - " }\n" + - "}\n"); + WireType.TEXT.fromString("!Variation2 {\n" + + " object: !Inner {\n" + + " unknown: true\n" + + " }\n" + + "}\n"); Assert.fail(); // If no exception is thrown, the test should fail } catch (UnexpectedFieldHandlingException e) { // Verify that the cause of the exception is as expected @@ -75,9 +74,8 @@ private static class Variation2 implements Marshallable { @Override public void unexpectedField(Object event, ValueIn valueIn) { // Throw an AssertionError with a descriptive message - throw new AssertionError - ("This should not be called with the field name '" + event + - "' and value '" + valueIn + "'"); + throw new AssertionError("This should not be called with the field name '" + event + + "' and value '" + valueIn + "'"); } } } diff --git a/src/test/java/net/openhft/chronicle/wire/UpdateInterceptorReturnTypeTest.java b/src/test/java/net/openhft/chronicle/wire/UpdateInterceptorReturnTypeTest.java index 9d397d7489..ce6efcc46c 100644 --- a/src/test/java/net/openhft/chronicle/wire/UpdateInterceptorReturnTypeTest.java +++ b/src/test/java/net/openhft/chronicle/wire/UpdateInterceptorReturnTypeTest.java @@ -35,8 +35,7 @@ public static Collection data() { // Creates and returns a new Wire instance with allocated memory private static Wire createWire() { - final Wire wire = BINARY.apply(Bytes.allocateElasticOnHeap()); - return wire; + return BINARY.apply(Bytes.allocateElasticOnHeap()); } // Before each test execution, set the appropriate system property and diff --git a/src/test/java/net/openhft/chronicle/wire/UsingTestMarshallableTest.java b/src/test/java/net/openhft/chronicle/wire/UsingTestMarshallableTest.java index fd3c899ea5..4c9fb9c429 100644 --- a/src/test/java/net/openhft/chronicle/wire/UsingTestMarshallableTest.java +++ b/src/test/java/net/openhft/chronicle/wire/UsingTestMarshallableTest.java @@ -37,20 +37,14 @@ public void testConverMarshallableToTextName() { // Deserialize the Wire's bytes to a String String value = Wires.fromSizePrefixedBlobs(wire.bytes()); - //String replace = value.replace("\n", "\\n"); - - // System.out.println(byteBufferBytes.toHexString()); - - // Ensure the serialized output matches the expected format - assertEquals("" + - "--- !!data\n" + - "any-key: {\n" + - " name: hello world,\n" + - " count: 0\n" + - "}\n", + // Ensure the serialised output matches the expected format + assertEquals("--- !!data\n" + + "any-key: {\n" + + " name: hello world,\n" + + " count: 0\n" + + "}\n", value); - // Assert.assertTrue(replace.length() > 1); // Release the ByteBuffer's resources byteBufferBytes.releaseLast(); } @@ -78,8 +72,6 @@ public void testMarshall() { @NotNull final ValueIn read = wire.read(() -> "key"); @Nullable final MyMarshallable result = read.typedMarshallable(); - // System.out.println(result.toString()); - // Ensure the read value matches the written one assertEquals("text", result.text.toString()); @@ -118,7 +110,8 @@ public void test() { static class MyMarshallable implements Marshallable { // Mutable sequence of characters to store textual data. - @NotNull StringBuilder text = new StringBuilder(); + @NotNull + final StringBuilder text = new StringBuilder(); // Method responsible for deserializing the object from the Wire input. @Override @@ -188,6 +181,7 @@ static class SortedFilter extends SelfDescribingMarshallable { public List marshableOrderBy = new ArrayList<>(); // List of filter conditions specifying the columns and their respective filter expressions. - @NotNull List marshableFilters = new ArrayList<>(); + @NotNull + final List marshableFilters = new ArrayList<>(); } } diff --git a/src/test/java/net/openhft/chronicle/wire/ValueInApisNegativeTest.java b/src/test/java/net/openhft/chronicle/wire/ValueInApisNegativeTest.java index 5a7bbc59b0..05d071bb40 100644 --- a/src/test/java/net/openhft/chronicle/wire/ValueInApisNegativeTest.java +++ b/src/test/java/net/openhft/chronicle/wire/ValueInApisNegativeTest.java @@ -6,11 +6,13 @@ import net.openhft.chronicle.bytes.Bytes; import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; /** * Drives less common ValueIn APIs and empty sequence paths. */ +@SuppressWarnings({"deprecation", "removal"}) public class ValueInApisNegativeTest extends WireTestCommon { @Test @@ -19,9 +21,16 @@ public void emptySequenceAndBytesMatch() { Wire w = wt.apply(Bytes.allocateElasticOnHeap(256)); // empty sequence - w.write("s").sequence(v -> {}); + w.write("s").sequence(v -> { + }); int len = w.read("s").sequenceWithLength(new Object[0], (in, o) -> { - int c = 0; while (in.hasNextSequenceItem()) { in.skipValue(); c++; } return c; }); + int c = 0; + while (in.hasNextSequenceItem()) { + in.skipValue(); + c++; + } + return c; + }); assertEquals(0, len); // bytesMatch on binary only (text/yaml base64 specifics are covered elsewhere) diff --git a/src/test/java/net/openhft/chronicle/wire/ValueInArrayReadersTest.java b/src/test/java/net/openhft/chronicle/wire/ValueInArrayReadersTest.java index f215d4ab6b..571f50ea53 100644 --- a/src/test/java/net/openhft/chronicle/wire/ValueInArrayReadersTest.java +++ b/src/test/java/net/openhft/chronicle/wire/ValueInArrayReadersTest.java @@ -11,6 +11,7 @@ /** * Exercises ValueIn array readers using sequences for common wire types. */ +@SuppressWarnings({"deprecation", "removal"}) public class ValueInArrayReadersTest extends WireTestCommon { @Test diff --git a/src/test/java/net/openhft/chronicle/wire/ValueInBestEffortTest.java b/src/test/java/net/openhft/chronicle/wire/ValueInBestEffortTest.java index 7f0a2019df..05eaeadbd7 100644 --- a/src/test/java/net/openhft/chronicle/wire/ValueInBestEffortTest.java +++ b/src/test/java/net/openhft/chronicle/wire/ValueInBestEffortTest.java @@ -3,7 +3,6 @@ */ package net.openhft.chronicle.wire; -import net.openhft.chronicle.bytes.Bytes; import org.junit.Test; import java.util.Map; diff --git a/src/test/java/net/openhft/chronicle/wire/ValueInSequenceBoundariesTest.java b/src/test/java/net/openhft/chronicle/wire/ValueInSequenceBoundariesTest.java index 40dca09384..9f8953e79a 100644 --- a/src/test/java/net/openhft/chronicle/wire/ValueInSequenceBoundariesTest.java +++ b/src/test/java/net/openhft/chronicle/wire/ValueInSequenceBoundariesTest.java @@ -6,27 +6,41 @@ import net.openhft.chronicle.bytes.Bytes; import org.junit.Test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; /** * Covers empty, single, and larger sequences to hit hasNextSequenceItem boundaries. */ +@SuppressWarnings({"deprecation", "removal"}) public class ValueInSequenceBoundariesTest extends WireTestCommon { @Test public void emptyAndSingle() { for (WireType wt : new WireType[]{WireType.BINARY, WireType.TEXT, WireType.YAML}) { Wire w = wt.apply(Bytes.allocateElasticOnHeap(256)); - w.write("e").sequence(v -> {}); + w.write("e").sequence(v -> { + // empty sequence + }); w.write("s").sequence(v -> v.int64(1L)); int n0 = w.read("e").sequenceWithLength(new Object[0], (in, o) -> { - int c = 0; while (in.hasNextSequenceItem()) { in.skipValue(); c++; } return c; }); + int c = 0; + while (in.hasNextSequenceItem()) { + in.skipValue(); + c++; + } + return c; + }); assertEquals(0, n0); final long[] one = new long[1]; int n1 = w.read("s").sequenceWithLength(one, (in, arr) -> { - int c = 0; while (in.hasNextSequenceItem()) { arr[c++] = in.int64(); } return c; }); + int c = 0; + while (in.hasNextSequenceItem()) { + arr[c++] = in.int64(); + } + return c; + }); assertEquals(1, n1); assertEquals(1L, one[0]); } @@ -37,13 +51,16 @@ public void manyItems() { for (WireType wt : new WireType[]{WireType.BINARY, WireType.TEXT, WireType.YAML}) { Wire w = wt.apply(Bytes.allocateElasticOnHeap(1024)); w.write("m").sequence(v -> { - for (int i = 0; i < 65; i++) v.int32(i); + for (int i = 0; i < 65; i++) { + v.int32(i); + } }); int[] arr = new int[65]; int n = w.read("m").array(arr); assertEquals(65, n); - for (int i = 0; i < 65; i++) assertEquals(i, arr[i]); + for (int i = 0; i < 65; i++) { + assertEquals(i, arr[i]); + } } } } - diff --git a/src/test/java/net/openhft/chronicle/wire/ValueOutTest.java b/src/test/java/net/openhft/chronicle/wire/ValueOutTest.java index 82cae2495d..bbb552df64 100644 --- a/src/test/java/net/openhft/chronicle/wire/ValueOutTest.java +++ b/src/test/java/net/openhft/chronicle/wire/ValueOutTest.java @@ -50,8 +50,7 @@ public void test() { ); - // System.out.println(Wires.fromSizePrefixedBlobs(wire.bytes())); - // Verify that the read byte array matches the written byte array + // Verify that the read byte array matches the written byte array wire.readDocument(null, w -> { @NotNull final byte[] actual = (byte[]) w.read().object(); Assert.assertArrayEquals(expected, actual); @@ -74,8 +73,7 @@ public void testRequestedType() { @NotNull final byte[] expected = "this is my byte array".getBytes(ISO_8859_1); wire.writeDocument(false, w -> w.write().object(expected)); - // System.out.println(Wires.fromSizePrefixedBlobs(wire.bytes())); - // Read the byte array back and ensure it matches the original + // Read the byte array back and ensure it matches the original wire.readDocument(null, w -> { @Nullable final byte[] actual = w.read().object(byte[].class); Assert.assertArrayEquals(expected, actual); diff --git a/src/test/java/net/openhft/chronicle/wire/VanillaMethodWriterBuilderOptionsTest.java b/src/test/java/net/openhft/chronicle/wire/VanillaMethodWriterBuilderOptionsTest.java index 854506dac2..842eba0471 100644 --- a/src/test/java/net/openhft/chronicle/wire/VanillaMethodWriterBuilderOptionsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/VanillaMethodWriterBuilderOptionsTest.java @@ -10,12 +10,11 @@ import java.util.ArrayList; import java.util.List; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +@SuppressWarnings({"deprecation", "removal"}) public class VanillaMethodWriterBuilderOptionsTest extends WireTestCommon { - interface Events { void event(String s); } - @Test public void honoursUpdateInterceptorAndThreadSafeToggle() { Bytes bytes = Bytes.allocateElasticOnHeap(); @@ -34,9 +33,13 @@ public void honoursUpdateInterceptorAndThreadSafeToggle() { MethodReader reader = wire.methodReader((Events) seen::add); while (reader.readOne()) { // drain + continue; } assertEquals(1, seen.size()); assertEquals("keep", seen.get(0)); } -} + interface Events { + void event(String s); + } +} diff --git a/src/test/java/net/openhft/chronicle/wire/VanillaMethodWriterBuilderVerboseTypesTest.java b/src/test/java/net/openhft/chronicle/wire/VanillaMethodWriterBuilderVerboseTypesTest.java index 041f1acbca..5955b4d8f4 100644 --- a/src/test/java/net/openhft/chronicle/wire/VanillaMethodWriterBuilderVerboseTypesTest.java +++ b/src/test/java/net/openhft/chronicle/wire/VanillaMethodWriterBuilderVerboseTypesTest.java @@ -5,6 +5,7 @@ import net.openhft.chronicle.bytes.Bytes; import net.openhft.chronicle.core.Jvm; +import net.openhft.chronicle.core.annotation.UsedViaReflection; import net.openhft.chronicle.core.pool.ClassAliasPool; import org.jetbrains.annotations.NotNull; import org.junit.Assert; @@ -62,6 +63,7 @@ public static Collection combinations() { } // Nested class representing a specific object with a string and value + @UsedViaReflection static class MyObject2 extends SelfDescribingMarshallable { private final String str; @@ -75,7 +77,7 @@ static class MyObject2 extends SelfDescribingMarshallable { // Nested class representing an object containing a list of `MyObject2` static class MyObject extends SelfDescribingMarshallable { - + @UsedViaReflection private final ArrayList list = new ArrayList<>(); MyObject(String str, int value) { diff --git a/src/test/java/net/openhft/chronicle/wire/WireCollectionsAndMapsTest.java b/src/test/java/net/openhft/chronicle/wire/WireCollectionsAndMapsTest.java index 24339a8328..7b3ac4680f 100644 --- a/src/test/java/net/openhft/chronicle/wire/WireCollectionsAndMapsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/WireCollectionsAndMapsTest.java @@ -19,10 +19,11 @@ public class WireCollectionsAndMapsTest extends WireTestCommon { @Test public void sequenceReadWrite() { for (WireType wt : new WireType[]{WireType.BINARY, WireType.TEXT, WireType.YAML}) { - Wire w = wt.apply(Bytes.allocateElasticOnHeap(256)); + final Wire w = wt.apply(Bytes.allocateElasticOnHeap(256)); // empty and single element sequence - w.write("empty").sequence(v -> {}); + w.write("empty").sequence(v -> { + }); w.write("one").sequence(v -> v.int32(7)); // mixed types w.write("mix").sequence(v -> { @@ -34,11 +35,22 @@ public void sequenceReadWrite() { // read back final int[] len = {0}; len[0] = w.read("empty").sequenceWithLength(new Object[0], (in, arr) -> { - int c = 0; while (in.hasNextSequenceItem()) { in.skipValue(); c++; } return c; }); + int c = 0; + while (in.hasNextSequenceItem()) { + in.skipValue(); + c++; + } + return c; + }); assertEquals(0, len[0]); len[0] = w.read("one").sequenceWithLength(new int[1], (in, arr) -> { - int c = 0; while (in.hasNextSequenceItem()) { arr[c++] = in.int32(); } return c; }); + int c = 0; + while (in.hasNextSequenceItem()) { + arr[c++] = in.int32(); + } + return c; + }); assertEquals(1, len[0]); Object[] out = new Object[3]; @@ -55,11 +67,12 @@ public void sequenceReadWrite() { public void mapsRoundTripViaMarshallable() { // Use ValueIn.marshallableAsMap across supported wire types. for (WireType wt : new WireType[]{WireType.BINARY, WireType.TEXT, WireType.YAML}) { - Wire w = wt.apply(Bytes.allocateElasticOnHeap(256)); Map in = new LinkedHashMap<>(); in.put("k1", 1); in.put("k2", "v2"); in.put("k3", 3L); + + final Wire w = wt.apply(Bytes.allocateElasticOnHeap(256)); w.write("m").map(in); Map out = w.read("m").marshallableAsMap(String.class, Object.class); diff --git a/src/test/java/net/openhft/chronicle/wire/WireDumperRandomTest.java b/src/test/java/net/openhft/chronicle/wire/WireDumperRandomTest.java index fd414ab7f7..49a805904b 100644 --- a/src/test/java/net/openhft/chronicle/wire/WireDumperRandomTest.java +++ b/src/test/java/net/openhft/chronicle/wire/WireDumperRandomTest.java @@ -50,9 +50,6 @@ public void dumpBinary() { // Check whether the string starts with the predefined starting string. if (!string.startsWith(starts)) { count++; -// if (count++ < 10) -// System.out.println("i: " + i + " " + string); -// assertEquals("i: " + i + " " + string, starts, string.substring(0, starts.length())); } } diff --git a/src/test/java/net/openhft/chronicle/wire/WireInternalInternTest.java b/src/test/java/net/openhft/chronicle/wire/WireInternalInternTest.java index b4fa6cc17e..c1bb42ab07 100644 --- a/src/test/java/net/openhft/chronicle/wire/WireInternalInternTest.java +++ b/src/test/java/net/openhft/chronicle/wire/WireInternalInternTest.java @@ -39,33 +39,19 @@ public WireInternalInternTest(String typeValue) { @Parameterized.Parameters(name = "{0}") public static Collection combinations() { return Stream.of( - // A list of date/time related objects for testing. -// new Date(), -// TimeZone.getTimeZone("GMT"), -// UUID.randomUUID(), - DayOfWeek.of(1), - LocalDate.now(), - LocalDateTime.now(), - LocalTime.now(), - Month.of(1) -// MonthDay.of(1, 2), -// OffsetDateTime.now(), -// OffsetTime.now(), -// Period.ofDays(2), -// Year.now(), -// YearMonth.now(), -// ZonedDateTime.now() -// ZoneId.of("GMT") -// ZoneOffset.ofHoursMinutes(5, 30) - ) - // Mapping each object to a new Object array with a formatted string. - .map(s -> new Object[]{"!" + ClassAliasPool.CLASS_ALIASES.nameFor(s.getClass()) + " " + s + " "}) + // A list of date/time related objects for testing. + DayOfWeek.of(1), + LocalDate.now(), + LocalDateTime.now(), + LocalTime.now(), + Month.of(1) + ) + // Mapping each object to a new Object array with a formatted string. + .map(s -> new Object[]{"!" + ClassAliasPool.CLASS_ALIASES.nameFor(s.getClass()) + " " + s + " "}) .collect(Collectors.toList()); } - // This test ensures that when values are interned, the same instance is returned for the same input. - // It's currently commented out, so it won't be executed. -// @Test + // Helper to ensure that when values are interned, the same instance is returned for the same input. public void intern() { int sep = typeValue.indexOf(' '); Class type = ClassAliasPool.CLASS_ALIASES.forName( diff --git a/src/test/java/net/openhft/chronicle/wire/WireMarshallerDeepGraphTest.java b/src/test/java/net/openhft/chronicle/wire/WireMarshallerDeepGraphTest.java index f553f0813c..24273fae5f 100644 --- a/src/test/java/net/openhft/chronicle/wire/WireMarshallerDeepGraphTest.java +++ b/src/test/java/net/openhft/chronicle/wire/WireMarshallerDeepGraphTest.java @@ -11,23 +11,10 @@ import java.util.List; import java.util.Map; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; public class WireMarshallerDeepGraphTest extends WireTestCommon { - public static class Child extends SelfDescribingMarshallable { - int id; - String name; - public Child() {} - public Child(int id, String name) { this.id = id; this.name = name; } - } - - public static class Parent extends SelfDescribingMarshallable { - String title = "p"; - List children = new ArrayList<>(); - Map counters = new LinkedHashMap<>(); - } - @Test public void deepGraphBinaryAndText() { for (WireType wt : new WireType[]{WireType.BINARY, WireType.TEXT}) { @@ -43,5 +30,23 @@ public void deepGraphBinaryAndText() { assertEquals(p, r); } } -} + public static class Child extends SelfDescribingMarshallable { + int id; + String name; + + public Child() { + } + + public Child(int id, String name) { + this.id = id; + this.name = name; + } + } + + public static class Parent extends SelfDescribingMarshallable { + String title = "p"; + final List children = new ArrayList<>(); + final Map counters = new LinkedHashMap<>(); + } +} diff --git a/src/test/java/net/openhft/chronicle/wire/WireNumberFormatsTest.java b/src/test/java/net/openhft/chronicle/wire/WireNumberFormatsTest.java index fde1f13dd2..359bfb49c0 100644 --- a/src/test/java/net/openhft/chronicle/wire/WireNumberFormatsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/WireNumberFormatsTest.java @@ -11,6 +11,7 @@ /** * Exercises number formats and booleans across wire types. */ +@SuppressWarnings({"deprecation", "removal"}) public class WireNumberFormatsTest extends WireTestCommon { @Test @@ -61,4 +62,3 @@ public void binaryExtremesRoundTrip() { assertEquals(0.0, w.read("mz").float64(), 0.0); } } - diff --git a/src/test/java/net/openhft/chronicle/wire/WireResetTest.java b/src/test/java/net/openhft/chronicle/wire/WireResetTest.java index dc150217d1..f75ca47f7a 100644 --- a/src/test/java/net/openhft/chronicle/wire/WireResetTest.java +++ b/src/test/java/net/openhft/chronicle/wire/WireResetTest.java @@ -49,7 +49,7 @@ public void testEventAbstractCloseable() { //https://github.com/OpenHFT/Chronicle-Wire/issues/732 public void testDeepReset() { Event event1 = new Event(); - Identifier identifier1 = event1.identifier; + final Identifier identifier1 = event1.identifier; event1.identifier.id = "id"; event1.identifier.parent = new Identifier("parent_id1"); event1.identifier.permissions.put("uid1", "r"); @@ -104,17 +104,17 @@ public void canDeepResetOnDtosContainingLocalDates() { public static class Event extends SelfDescribingMarshallable implements Closeable { - private boolean isClosed; - - Identifier identifier = new Identifier(); - Collection ids = new LinkedList<>(); + final Identifier identifier = new Identifier(); + final Collection ids = new LinkedList<>(); String payload; LocalDate someDate; + private boolean isClosed; @Override public void close() { isClosed = true; } + @Override public boolean isClosed() { return isClosed; @@ -130,7 +130,7 @@ protected void performClose() { static class Identifier extends SelfDescribingMarshallable { String id; Identifier parent; - Map permissions = new HashMap<>(); + final Map permissions = new HashMap<>(); Identifier() { } diff --git a/src/test/java/net/openhft/chronicle/wire/WireResourcesTest.java b/src/test/java/net/openhft/chronicle/wire/WireResourcesTest.java index a342be0c87..ea66a36a3c 100644 --- a/src/test/java/net/openhft/chronicle/wire/WireResourcesTest.java +++ b/src/test/java/net/openhft/chronicle/wire/WireResourcesTest.java @@ -22,6 +22,15 @@ public class WireResourcesTest extends WireTestCommon { + // Helper method to write a message into the given wire. + private static void writeMessage(@NotNull Wire wire) { + try (DocumentContext dc = wire.writingDocument()) { + final Bytes bytes = dc.wire().bytes(); + bytes.writeSkip(128000); + bytes.writeLong(1L); + } + } + @Before public void hasDirect() { assumeFalse(Jvm.maxDirectMemory() == 0); @@ -35,7 +44,7 @@ public void testMappedBytesClose() throws Exception { tmp.deleteOnExit(); // Initialize and verify initial reference counts. - MappedBytes mb0; + final MappedBytes mb0; @NotNull MappedBytes mb = MappedBytes.mappedBytes(tmp, 64 * 1024); assertEquals(1, mb.mappedFile().refCount()); assertEquals(1, mb.refCount()); @@ -73,7 +82,7 @@ public void testMappedBytesWireRelease() throws Exception { tmp.deleteOnExit(); // Initialize the mapped bytes and verify the initial reference counts. - Wire wire; + final Wire wire; @NotNull MappedBytes mb = MappedBytes.mappedBytes(tmp, 64 * 1024); assertEquals(1, mb.mappedFile().refCount()); assertEquals(1, mb.refCount()); @@ -162,15 +171,6 @@ public void testMappedBytesWireRelease2() throws Exception { assertEquals(0, mappedFile(wire).refCount()); } - // Helper method to write a message into the given wire. - private static void writeMessage(@NotNull Wire wire) { - try (DocumentContext dc = wire.writingDocument()) { - final Bytes bytes = dc.wire().bytes(); - bytes.writeSkip(128000); - bytes.writeLong(1L); - } - } - // Helper method to retrieve the MappedFile associated with the given wire. @NotNull private MappedFile mappedFile(@NotNull Wire wire) { diff --git a/src/test/java/net/openhft/chronicle/wire/WireRoundTripParamTest.java b/src/test/java/net/openhft/chronicle/wire/WireRoundTripParamTest.java index a12fb3cb35..eccde417f9 100644 --- a/src/test/java/net/openhft/chronicle/wire/WireRoundTripParamTest.java +++ b/src/test/java/net/openhft/chronicle/wire/WireRoundTripParamTest.java @@ -6,8 +6,6 @@ import net.openhft.chronicle.bytes.Bytes; import org.junit.Test; -import java.util.Arrays; - import static org.junit.Assert.*; /** diff --git a/src/test/java/net/openhft/chronicle/wire/WireScalarEdgeCasesTest.java b/src/test/java/net/openhft/chronicle/wire/WireScalarEdgeCasesTest.java index 1d92e7ac5d..d292b47c3b 100644 --- a/src/test/java/net/openhft/chronicle/wire/WireScalarEdgeCasesTest.java +++ b/src/test/java/net/openhft/chronicle/wire/WireScalarEdgeCasesTest.java @@ -11,6 +11,7 @@ /** * Covers scalar edge cases across common wire types to exercise ValueIn/ValueOut branches. */ +@SuppressWarnings({"deprecation", "removal"}) public class WireScalarEdgeCasesTest extends WireTestCommon { private static final WireType[] TYPES = new WireType[]{ diff --git a/src/test/java/net/openhft/chronicle/wire/WireStringCollectionTest.java b/src/test/java/net/openhft/chronicle/wire/WireStringCollectionTest.java index 7ed6475490..dba426a61a 100644 --- a/src/test/java/net/openhft/chronicle/wire/WireStringCollectionTest.java +++ b/src/test/java/net/openhft/chronicle/wire/WireStringCollectionTest.java @@ -51,7 +51,9 @@ public void readAndWrite() { // Definition for ContainsList class private static class ContainsList extends AbstractEventCfg { - @NotNull List list = new ArrayList<>(); - @NotNull Map map = new HashMap<>(); + @NotNull + final List list = new ArrayList<>(); + @NotNull + final Map map = new HashMap<>(); } } diff --git a/src/test/java/net/openhft/chronicle/wire/WireTests.java b/src/test/java/net/openhft/chronicle/wire/WireTests.java index 7601e0f6a8..afb1baba41 100644 --- a/src/test/java/net/openhft/chronicle/wire/WireTests.java +++ b/src/test/java/net/openhft/chronicle/wire/WireTests.java @@ -350,7 +350,7 @@ private Wire createWire(Bytes b) { // Inner class to represent a test object with a Class field static class TestClass extends SelfDescribingMarshallable { - Class o; + final Class o; TestClass(Class o) { this.o = o; @@ -362,6 +362,6 @@ Class clazz() { } // Inner class to represent a Circle, implements Marshallable for serialization - private class Circle implements Marshallable { + private static class Circle implements Marshallable { } } diff --git a/src/test/java/net/openhft/chronicle/wire/WireToOutputStreamTest.java b/src/test/java/net/openhft/chronicle/wire/WireToOutputStreamTest.java index b7995dcd12..3f7d15ce07 100644 --- a/src/test/java/net/openhft/chronicle/wire/WireToOutputStreamTest.java +++ b/src/test/java/net/openhft/chronicle/wire/WireToOutputStreamTest.java @@ -23,28 +23,10 @@ import static org.junit.Assert.assertEquals; @RunWith(Parameterized.class) +@SuppressWarnings({"deprecation", "removal"}) public class WireToOutputStreamTest extends WireTestCommon { - // Serializable class for testing - public static class AnObject implements Serializable { - private static final long serialVersionUID = 0L; - long value; - String text; - - Timestamp timestamp = new Timestamp(1234567890000L); - - @Override - public String toString() { - // Override toString for easier debugging - return "AnObject{" + - "value=" + value + - ", text='" + text + '\'' + - ", timestamp=" + timestamp + - '}'; - } - } - - private WireType currentWireType; + private final WireType currentWireType; // Constructor to initialize the parameter public WireToOutputStreamTest(WireType currentWireType) { @@ -72,10 +54,9 @@ public static Collection data() { @Test // Test to ensure the Timestamp object can be serialized and deserialized correctly public void testTimestamp() { - Wire wire = currentWireType.apply(Bytes.allocateElasticOnHeap(128)); - Timestamp ts = new Timestamp(1234567890000L); + final Wire wire = currentWireType.apply(Bytes.allocateElasticOnHeap(128)); + final Timestamp ts = new Timestamp(1234567890000L); wire.write().object(ts); - // System.out.println(wire); Timestamp ts2 = wire.read() .object(Timestamp.class); @@ -85,9 +66,8 @@ public void testTimestamp() { @Test // Test serialization and deserialization without a socket public void testNoSocket() { - Wire wire = currentWireType.apply(Bytes.allocateElasticOnHeap(128)); - AnObject ao = writeAnObject(wire); - // System.out.println(wire); + final Wire wire = currentWireType.apply(Bytes.allocateElasticOnHeap(128)); + final AnObject ao = writeAnObject(wire); Object ao2 = readAnObject(wire); assertEquals(ao.toString(), ao2.toString()); @@ -99,16 +79,15 @@ public void testVisSocket() throws IOException { try (ServerSocket ss = new ServerSocket(0); Socket s = new Socket("localhost", ss.getLocalPort()); Socket s2 = ss.accept()) { - WireToOutputStream wtos = new WireToOutputStream(currentWireType, s.getOutputStream()); + final WireToOutputStream wtos = new WireToOutputStream(currentWireType, s.getOutputStream()); - Wire wire = wtos.getWire(); - AnObject ao = writeAnObject(wire); + final Wire wire = wtos.getWire(); + final AnObject ao = writeAnObject(wire); wtos.flush(); - InputStreamToWire istw = new InputStreamToWire(currentWireType, s2.getInputStream()); - Wire wire2 = istw.readOne(); - Object ao2 = readAnObject(wire2); - // System.out.println(ao2); + final InputStreamToWire istw = new InputStreamToWire(currentWireType, s2.getInputStream()); + final Wire wire2 = istw.readOne(); + final Object ao2 = readAnObject(wire2); assertEquals(ao.toString(), ao2.toString()); } } @@ -135,4 +114,23 @@ private AnObject writeAnObject(Wire wire) { Wires.writeMarshallable(ao, wire); return ao; } + + // Serializable class for testing + public static class AnObject implements Serializable { + private static final long serialVersionUID = 0L; + long value; + String text; + + final Timestamp timestamp = new Timestamp(1234567890000L); + + @Override + public String toString() { + // Override toString for easier debugging + return "AnObject{" + + "value=" + value + + ", text='" + text + '\'' + + ", timestamp=" + timestamp + + '}'; + } + } } diff --git a/src/test/java/net/openhft/chronicle/wire/WireTypeConverterTest.java b/src/test/java/net/openhft/chronicle/wire/WireTypeConverterTest.java index e399b07406..b9a4e2c1f3 100644 --- a/src/test/java/net/openhft/chronicle/wire/WireTypeConverterTest.java +++ b/src/test/java/net/openhft/chronicle/wire/WireTypeConverterTest.java @@ -8,6 +8,7 @@ import static junit.framework.TestCase.assertEquals; +@SuppressWarnings({"deprecation", "removal"}) public class WireTypeConverterTest extends net.openhft.chronicle.wire.WireTestCommon { private final String json = @@ -38,7 +39,7 @@ public void testJsonToYaml() { } @Test - public void testYamlToJsonUnknownClass() throws Exception { + public void testYamlToJsonUnknownClass() { Assert.assertEquals(jsonUnknownClass, new WireTypeConverter().yamlToJson(yamlUnknownClass).toString()); Assert.assertEquals(yamlUnknownClass, new WireTypeConverter().jsonToYaml(jsonUnknownClass).toString()); } diff --git a/src/test/java/net/openhft/chronicle/wire/WireTypeTest.java b/src/test/java/net/openhft/chronicle/wire/WireTypeTest.java index 0c09511877..ec5fec3c95 100644 --- a/src/test/java/net/openhft/chronicle/wire/WireTypeTest.java +++ b/src/test/java/net/openhft/chronicle/wire/WireTypeTest.java @@ -48,8 +48,7 @@ public void testAsString() { " count: 1\n" + "}\n", WireType.TEXT.asString(tm)); // Test Binary-based WireType - assertEquals("" + - "00000000 b6 10 54 65 73 74 4d 61 72 73 68 61 6c 6c 61 62 ··TestMa rshallab\n" + + assertEquals("00000000 b6 10 54 65 73 74 4d 61 72 73 68 61 6c 6c 61 62 ··TestMa rshallab\n" + "00000010 6c 65 82 12 00 00 00 c4 6e 61 6d 65 e4 6e 61 6d le······ name·nam\n" + "00000020 65 c5 63 6f 75 6e 74 a1 01 e·count· · \n", WireType.BINARY.asString(tm)); @@ -81,12 +80,6 @@ public void testFromString() { "00000020 65 C5 63 6F 75 6E 74 01 e·count· \n"; // Validate Binary-based WireType assertEquals(tm, WireType.BINARY.fromString(asBinary)); - -/* NOT Supported - String asRaw = "00000000 10 54 65 73 74 4D 61 72 73 68 61 6C 6C 61 62 6C ·TestMar shallabl\n" + - "00000010 65 09 00 00 00 04 6E 61 6D 65 01 00 00 00 e·····na me···· \n"; - assertEquals(tm, WireType.RAW.fromString(asRaw)); -*/ } // Test WireType's ability to write and read from a file diff --git a/src/test/java/net/openhft/chronicle/wire/WiresFromFileTest.java b/src/test/java/net/openhft/chronicle/wire/WiresFromFileTest.java index b52ff991a2..6de3e9b212 100644 --- a/src/test/java/net/openhft/chronicle/wire/WiresFromFileTest.java +++ b/src/test/java/net/openhft/chronicle/wire/WiresFromFileTest.java @@ -13,6 +13,7 @@ import static org.junit.Assert.assertEquals; +@SuppressWarnings({"deprecation", "removal"}) public class WiresFromFileTest extends WireTestCommon { @Test public void testFromFile() throws IOException { diff --git a/src/test/java/net/openhft/chronicle/wire/WiresTest.java b/src/test/java/net/openhft/chronicle/wire/WiresTest.java index 5588b158a1..f0dbb1b536 100644 --- a/src/test/java/net/openhft/chronicle/wire/WiresTest.java +++ b/src/test/java/net/openhft/chronicle/wire/WiresTest.java @@ -18,14 +18,15 @@ import java.io.IOException; import java.io.PrintStream; import java.lang.reflect.Field; -import java.nio.charset.StandardCharsets; import java.util.List; +import static java.nio.charset.StandardCharsets.ISO_8859_1; import static java.util.Arrays.asList; import static net.openhft.chronicle.wire.WireType.TEXT; import static org.junit.Assert.*; import static org.junit.jupiter.api.Assumptions.assumeFalse; +@SuppressWarnings({"deprecation", "removal"}) public class WiresTest extends WireTestCommon { private final BytesContainer container1 = new BytesContainer(); @@ -194,18 +195,18 @@ public void recordAsYaml() { says.say("Two"); says.say("Three"); - assertEquals("" + - "---\n" + - "say: One\n" + - "...\n" + - "---\n" + - "say: Two\n" + - "...\n" + - "---\n" + - "say: Three\n" + - "...\n", - new String(baos.toByteArray(), StandardCharsets.ISO_8859_1)); + assertEquals("---\n" + + "say: One\n" + + "...\n" + + "---\n" + + "say: Two\n" + + "...\n" + + "---\n" + + "say: Three\n" + + "...\n", + new String(baos.toByteArray(), ISO_8859_1)); } + @Test public void replay() throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -221,10 +222,9 @@ public void replay() throws IOException { "...\n" + "---\n" + "say: Three\n" + - "...\n",says); + "...\n", says); - assertEquals("" + - "---\n" + + assertEquals("---\n" + "say: zero\n" + "...\n" + "---\n" + @@ -235,7 +235,7 @@ public void replay() throws IOException { "...\n" + "---\n" + "say: Three\n" + - "...\n", new String(baos.toByteArray(), StandardCharsets.ISO_8859_1)); + "...\n", new String(baos.toByteArray(), ISO_8859_1)); } @Test @@ -248,32 +248,6 @@ public void deepCopyNotBoundToThread() { assertNull(Jvm.getValue(bcm2.bytesField, "usedByThread")); } - interface ThreeValues { - ThreeValues string(String s); - - String string(); - - ThreeValues num(int n); - - int num(); - - ThreeValues big(double d); - - double big(); - } - - private static final class BytesContainer { - Bytes bytesField = Bytes.allocateElasticOnHeap(64); - } - - private static final class BytesContainerMarshallable extends SelfDescribingMarshallable { - Bytes bytesField = Bytes.allocateElasticOnHeap(64); - } - - private static final class StringBuilderContainer { - StringBuilder stringBuilder = new StringBuilder(); - } - @Test public void copyTo() { OneTwoFour o124 = new OneTwoFour(11, 222, 44444); @@ -292,16 +266,14 @@ public void copyTo() { public void copyToIncompleteValidation() { OneTwoFour o124 = new OneTwoFour(11, 222, 44444); TwoFourThreeValidatable o243 = new TwoFourThreeValidatable(2, 4, 3); - assertEquals("" + - "!net.openhft.chronicle.wire.WiresTest$TwoFourThreeValidatable {\n" + + assertEquals("!net.openhft.chronicle.wire.WiresTest$TwoFourThreeValidatable {\n" + " two: 2,\n" + " four: 4,\n" + " three: 3\n" + "}\n", o243.toString()); // Using copyTo to partially hydrate an object is perfectly valid Wires.copyTo(o124, o243); - assertEquals("" + - "!net.openhft.chronicle.wire.WiresTest$TwoFourThreeValidatable {\n" + + assertEquals("!net.openhft.chronicle.wire.WiresTest$TwoFourThreeValidatable {\n" + " two: 222,\n" + " four: 44444,\n" + " three: 0\n" + @@ -322,7 +294,7 @@ public void copyToContainsBytesMarshallable() { public void deepCopyWillWorkWhenDynamicEnumIsAnnotatedAsMarshallable() { Assume.assumeFalse(Jvm.maxDirectMemory() == 0); - ClassAliasPool.CLASS_ALIASES.addAlias(Thing.class, EnumThing.class); + ClassAliasPool.CLASS_ALIASES.addAlias(Thing.class, EnumThing.class); Thing thing2 = Marshallable.fromString( "!Thing {" + @@ -336,6 +308,42 @@ public void deepCopyWillWorkWhenDynamicEnumIsAnnotatedAsMarshallable() { assertEquals(thing2, thingCopy); } + @SuppressWarnings("deprecation") + enum EnumThing implements DynamicEnum { + ONE, + TWO + } + + interface ThreeValues { + ThreeValues string(String s); + + String string(); + + ThreeValues num(int n); + + int num(); + + ThreeValues big(double d); + + double big(); + } + + interface Says { + void say(String word); + } + + private static final class BytesContainer { + final Bytes bytesField = Bytes.allocateElasticOnHeap(64); + } + + private static final class BytesContainerMarshallable extends SelfDescribingMarshallable { + final Bytes bytesField = Bytes.allocateElasticOnHeap(64); + } + + private static final class StringBuilderContainer { + final StringBuilder stringBuilder = new StringBuilder(); + } + @SuppressWarnings("deprecation") static class Thing extends AbstractEventCfg { @AsMarshallable @@ -343,14 +351,10 @@ static class Thing extends AbstractEventCfg { String someString; } - @SuppressWarnings("deprecation") - enum EnumThing implements DynamicEnum { - ONE, - TWO; - } - static class OneTwoFour extends BytesInBinaryMarshallable { - long one, two, four; + final long one; + final long two; + final long four; OneTwoFour(long one, long two, long four) { this.one = one; @@ -360,7 +364,9 @@ static class OneTwoFour extends BytesInBinaryMarshallable { } static class TwoFourThree extends BytesInBinaryMarshallable { - long two, four, three; + final long two; + final long four; + final long three; TwoFourThree(long two, long four, long three) { this.two = two; @@ -383,7 +389,7 @@ public void validate() throws InvalidMarshallableException { } static class BasicBytesMarshallable implements BytesMarshallable { - String name; + final String name; BasicBytesMarshallable(String name) { this.name = name; @@ -391,14 +397,10 @@ static class BasicBytesMarshallable implements BytesMarshallable { } static class ContainsBM extends BytesInBinaryMarshallable { - BasicBytesMarshallable inner; + final BasicBytesMarshallable inner; ContainsBM(BasicBytesMarshallable inner) { this.inner = inner; } } - - interface Says { - void say(String word); - } } diff --git a/src/test/java/net/openhft/chronicle/wire/YamlAnchorCoverageTest.java b/src/test/java/net/openhft/chronicle/wire/YamlAnchorCoverageTest.java index d8aeb400c3..e8d53c69f9 100644 --- a/src/test/java/net/openhft/chronicle/wire/YamlAnchorCoverageTest.java +++ b/src/test/java/net/openhft/chronicle/wire/YamlAnchorCoverageTest.java @@ -9,6 +9,7 @@ import static org.junit.Assert.*; +@SuppressWarnings({"deprecation", "removal"}) public class YamlAnchorCoverageTest extends WireTestCommon { @Test(expected = UnsupportedOperationException.class) diff --git a/src/test/java/net/openhft/chronicle/wire/YamlSpecTest.java b/src/test/java/net/openhft/chronicle/wire/YamlSpecTest.java index 794674a7bf..c54f7932d0 100644 --- a/src/test/java/net/openhft/chronicle/wire/YamlSpecTest.java +++ b/src/test/java/net/openhft/chronicle/wire/YamlSpecTest.java @@ -11,13 +11,12 @@ @Deprecated(/* Should be fully covered by YamlSpecificationTest */) public class YamlSpecTest extends WireTestCommon { - private static String DIR = "/yaml/spec/"; + private static final String DIR = "/yaml/spec/"; private static void doTest(String file, String expected) { Bytes b = Bytes.allocateElasticOnHeap(); try { - InputStream is = YamlSpecTest.class.getResourceAsStream - (DIR + file); + InputStream is = YamlSpecTest.class.getResourceAsStream(DIR + file); Object o = Marshallable.fromString(is); Assert.assertNotNull(o); @@ -33,8 +32,7 @@ private static void doTest(String file, String expected) { public void test2_18Multi_lineFlowScalarsFixed() { Bytes b = Bytes.allocateElasticOnHeap(); try { - InputStream is = YamlSpecTest.class.getResourceAsStream - (DIR + "2_18Multi_lineFlowScalarsFixed.yaml"); + InputStream is = YamlSpecTest.class.getResourceAsStream(DIR + "2_18Multi_lineFlowScalarsFixed.yaml"); Object o = Marshallable.fromString(is); Assert.assertNotNull(o); diff --git a/src/test/java/net/openhft/chronicle/wire/YamlSpecificationTest.java b/src/test/java/net/openhft/chronicle/wire/YamlSpecificationTest.java index 0401df5732..f8fc1a1a60 100644 --- a/src/test/java/net/openhft/chronicle/wire/YamlSpecificationTest.java +++ b/src/test/java/net/openhft/chronicle/wire/YamlSpecificationTest.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertEquals; @RunWith(Parameterized.class) +@SuppressWarnings({"deprecation", "removal"}) public class YamlSpecificationTest extends WireTestCommon { // Register class aliases for String, Circle, Shape, Line, and Label diff --git a/src/test/java/net/openhft/chronicle/wire/YamlSpecificationTextWireTest.java b/src/test/java/net/openhft/chronicle/wire/YamlSpecificationTextWireTest.java index 4ab76993d5..ebf8ea1fb3 100644 --- a/src/test/java/net/openhft/chronicle/wire/YamlSpecificationTextWireTest.java +++ b/src/test/java/net/openhft/chronicle/wire/YamlSpecificationTextWireTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals; @RunWith(Parameterized.class) +@SuppressWarnings({"deprecation", "removal"}) public class YamlSpecificationTextWireTest extends WireTestCommon { // Holds the input data for each test case diff --git a/src/test/java/net/openhft/chronicle/wire/YamlTokeniserTest.java b/src/test/java/net/openhft/chronicle/wire/YamlTokeniserTest.java index e92a3b76f7..06c518655b 100644 --- a/src/test/java/net/openhft/chronicle/wire/YamlTokeniserTest.java +++ b/src/test/java/net/openhft/chronicle/wire/YamlTokeniserTest.java @@ -49,8 +49,7 @@ public static String doTest(String resource) { @Test public void morseCode() { // The expected tokenized representation of the morse-code.yaml file - assertEquals("" + - "DIRECTIVES_END \n" + + assertEquals("DIRECTIVES_END \n" + "MAPPING_START \n" + "MAPPING_KEY \n" + "TEXT A\n" + @@ -135,12 +134,11 @@ public void morseCode() { doTest("morse-code.yaml")); // Invoke the tokenization utility and verify the output } - // Test case for tokenizing YAML content with mixed quotes + // Test case for tokenising YAML content with mixed quotes @Test public void mixedQuotes() { // The expected tokenized representation of the mixed-quotes.yaml file - assertEquals("" + - "DIRECTIVES_END \n" + + assertEquals("DIRECTIVES_END \n" + "SEQUENCE_START \n" + "TEXT \" \\\"\n" + "TEXT ' \"\n" + diff --git a/src/test/java/net/openhft/chronicle/wire/YamlValueOutFormattingBranchesTest.java b/src/test/java/net/openhft/chronicle/wire/YamlValueOutFormattingBranchesTest.java index 783f1b0079..39a7722ead 100644 --- a/src/test/java/net/openhft/chronicle/wire/YamlValueOutFormattingBranchesTest.java +++ b/src/test/java/net/openhft/chronicle/wire/YamlValueOutFormattingBranchesTest.java @@ -15,6 +15,7 @@ * Drives YamlValueOut formatting paths (strings needing quoting, multi-line, sequences, maps) * and validates via round-trip parsing. */ +@SuppressWarnings({"deprecation", "removal"}) public class YamlValueOutFormattingBranchesTest extends WireTestCommon { @Test @@ -25,7 +26,10 @@ public void writeAndReadComplexYaml() { w.write("quoted").text("needs: quoting [brackets]"); w.write("multiline").text("line1\nline2"); w.write("empty").text(""); - w.write("seq").sequence(v -> { v.text("x"); v.text("y"); }); + w.write("seq").sequence(v -> { + v.text("x"); + v.text("y"); + }); Map m = new LinkedHashMap<>(); m.put("k1", "v1"); m.put("k2", 2L); @@ -39,7 +43,10 @@ public void writeAndReadComplexYaml() { assertEquals("line1\nline2", r.read("multiline").text()); assertEquals("", r.read("empty").text()); final Object[] seq = new Object[2]; - r.read("seq").sequence(seq, (arr, in) -> { arr[0] = in.text(); arr[1] = in.text(); }); + r.read("seq").sequence(seq, (arr, in) -> { + arr[0] = in.text(); + arr[1] = in.text(); + }); assertArrayEquals(new Object[]{"x", "y"}, seq); Map out = r.read("map").marshallableAsMap(String.class, Object.class); assertEquals(m, out); diff --git a/src/test/java/net/openhft/chronicle/wire/YamlWireOutOfOrderReadMarshallableTest.java b/src/test/java/net/openhft/chronicle/wire/YamlWireOutOfOrderReadMarshallableTest.java new file mode 100644 index 0000000000..9a495605db --- /dev/null +++ b/src/test/java/net/openhft/chronicle/wire/YamlWireOutOfOrderReadMarshallableTest.java @@ -0,0 +1,94 @@ +/* + * Copyright 2013-2025 chronicle.software; SPDX-License-Identifier: Apache-2.0 + */ +package net.openhft.chronicle.wire; + +import net.openhft.chronicle.bytes.Bytes; +import net.openhft.chronicle.core.io.IORuntimeException; +import org.jetbrains.annotations.NotNull; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class YamlWireOutOfOrderReadMarshallableTest extends WireTestCommon { + + @Test + public void flowMappingKeepsManualReadMarshallableInOrder() { + assertOutOfOrderManualReadMarshallable( + flowYaml("c", "b", "a"), + flowYaml("b", "c", "a"), + flowYaml("c", "a", "b")); + } + + @Test + public void indentedMappingKeepsManualReadMarshallableInOrder() { + assertOutOfOrderManualReadMarshallable( + indentedYaml("c", "b", "a"), + indentedYaml("b", "c", "a"), + indentedYaml("c", "a", "b")); + } + + private static void assertOutOfOrderManualReadMarshallable(String... yamls) { + for (String yaml : yamls) { + YamlWire wire = new YamlWire(Bytes.from(yaml)).useTextDocuments(); + + try (DocumentContext dc = wire.readingDocument()) { + assertTrue(dc.isPresent()); + OutOfOrderRM dto = new OutOfOrderRM(); + dc.wire().read("rm").marshallable(dto); + assertEquals("aye2", dto.a); + assertEquals("bee2", dto.b); + assertEquals("cee2", dto.c); + } + } + } + + private static String flowYaml(String... order) { + StringBuilder sb = new StringBuilder("---\nrm: {\n"); + for (int i = 0; i < order.length; i++) { + sb.append(" ").append(order[i]).append(": ").append(valueFor(order[i])); + if (i < order.length - 1) + sb.append(",\n"); + else + sb.append("\n"); + } + sb.append("}\n...\n"); + return sb.toString(); + } + + private static String indentedYaml(String... order) { + StringBuilder sb = new StringBuilder("---\nrm:\n"); + for (String key : order) { + sb.append(" ").append(key).append(": ").append(valueFor(key)).append("\n"); + } + sb.append("...\n"); + return sb.toString(); + } + + private static String valueFor(String key) { + switch (key) { + case "a": + return "aye2"; + case "b": + return "bee2"; + case "c": + return "cee2"; + default: + throw new IllegalArgumentException("Unexpected key " + key); + } + } + + private static final class OutOfOrderRM implements ReadMarshallable { + String a; + String b; + String c; + + @Override + public void readMarshallable(@NotNull WireIn wire) throws IORuntimeException { + a = wire.read("a").text(); + b = wire.read("b").text(); + c = wire.read("c").text(); + } + } +} diff --git a/src/test/java/net/openhft/chronicle/wire/YamlWireTest.java b/src/test/java/net/openhft/chronicle/wire/YamlWireTest.java index aefe0f8eff..b399543028 100644 --- a/src/test/java/net/openhft/chronicle/wire/YamlWireTest.java +++ b/src/test/java/net/openhft/chronicle/wire/YamlWireTest.java @@ -48,10 +48,10 @@ import static org.junit.Assert.*; import static org.junit.Assume.assumeFalse; -@SuppressWarnings({"rawtypes", "unchecked", "try", "serial"}) +@SuppressWarnings({"rawtypes", "unchecked", "try", "serial", "deprecation", "removal"}) @RunWith(value = Parameterized.class) public class YamlWireTest extends WireTestCommon { - private static Wire wire = Wire.newYamlWireOnHeap(); // Initialize a static YAML wire + private static final Wire wire = Wire.newYamlWireOnHeap(); // Initialize a static YAML wire private final boolean usePadding; // Flag to indicate if padding should be used // Constructor for initializing the usePadding flag @@ -630,7 +630,10 @@ public void float64() { // Custom object to hold floating-point value for verification class Floater { double f; - void set(double d) { f = d; } + + void set(double d) { + f = d; + } } @NotNull Floater n = new Floater(); IntStream.rangeClosed(1, 3).forEach(e -> { @@ -798,7 +801,7 @@ public void testZonedDateTime() { @Test public void testDate() { - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); LocalDate now = LocalDate.now(); wire.write().date(now) .write().date(LocalDate.MAX) @@ -810,7 +813,7 @@ public void testDate() { @Test public void testUuid() { - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); UUID uuid = UUID.randomUUID(); wire.write().uuid(uuid) .write().uuid(new UUID(0, 0)) @@ -822,7 +825,7 @@ public void testUuid() { @Test public void testTypeWithoutSpace() { - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); wire.bytes().append("A: !").append(MyTypes.class.getName()).append("{}"); @NotNull MyTypes mt = (MyTypes) wire.read("A") @@ -928,9 +931,9 @@ public void testABCDBytes() { public void testABCStringBuilder() { assumeFalse(Jvm.maxDirectMemory() == 0); - String A = "A: \"hi\", # This is an A\n"; - String B = "B: 'hi', # This is a B\n"; - String C = "C: hi, # And that's a C\n"; + String stringA = "A: \"hi\", # This is an A\n"; + String stringB = "B: 'hi', # This is a B\n"; + String stringC = "C: hi, # And that's a C\n"; // Create a wire and append values for A, B, and C @NotNull Wire wire = createWire(); @@ -939,7 +942,13 @@ public void testABCStringBuilder() { ABC abc = new ABC(); // Read from wire and assert its value for all permutations - for (String input : new String[] { A + B + C, B + A + C, C + A + B, A + C + B, B + C + A, C + B + A }) { + for (String input : new String[]{ + stringA + stringB + stringC, + stringB + stringA + stringC, + stringC + stringA + stringB, + stringA + stringC + stringB, + stringB + stringC + stringA, + stringC + stringB + stringA}) { wire.reset(); wire.bytes().append(input); assertEquals(input, "!net.openhft.chronicle.wire.TextWireTest$ABC {\n" + @@ -976,7 +985,7 @@ public void testBytes() { @Test public void testWriteMarshallable() { - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); @NotNull MyTypesCustom mtA = new MyTypesCustom(); mtA.flag = true; mtA.d = 123.456; @@ -1023,7 +1032,7 @@ public void testWriteMarshallable() { @Test public void testWriteMarshallableAndFieldLength() { - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); @NotNull MyTypesCustom mtA = new MyTypesCustom(); mtA.flag = true; mtA.d = 123.456; @@ -1032,9 +1041,9 @@ public void testWriteMarshallableAndFieldLength() { @NotNull ValueOut write = wire.write(() -> "A"); - long start = wire.bytes().writePosition() + 1; // including one space for "sep". + final long start = wire.bytes().writePosition() + 1; // including one space for "sep". write.marshallable(mtA); - long fieldLen = wire.bytes().lengthWritten(start); + final long fieldLen = wire.bytes().lengthWritten(start); expectWithSnakeYaml("{A={B_FLAG=true, S_NUM=12345, D_NUM=123.456, L_NUM=0, I_NUM=-12345789, TEXT=}}", wire); @@ -1682,8 +1691,8 @@ public void testObjectKeys() { "? { MyField: parent }: {\n" + " ? !net.openhft.chronicle.wire.MyMarshallable { MyField: key1 }: value1,\n" + " ? !net.openhft.chronicle.wire.MyMarshallable { MyField: key2 }: value2\n" + - "}\n" - , Wires.fromSizePrefixedBlobs(wire.bytes())); + "}\n", + Wires.fromSizePrefixedBlobs(wire.bytes())); wire.readDocument(null, w -> { Map map1 = w.getValueIn().marshallableAsMap(MyMarshallable.class, Map.class); @@ -1697,14 +1706,14 @@ public void testObjectKeys() { } @Test(expected = IllegalArgumentException.class) - public void writeUnserializable() throws IOException { + public void writeUnserializable() { assumeFalse(Jvm.maxDirectMemory() == 0); System.out.println(WireType.YAML_ONLY.asString(Thread.currentThread())); } @Test(expected = IllegalArgumentException.class) - public void writeUnserializable2() throws IOException { + public void writeUnserializable2() { assumeFalse(Jvm.maxDirectMemory() == 0); @NotNull Socket s = new Socket(); @@ -1732,7 +1741,7 @@ public void writeCharacter() { @Test public void testSortedSet() { - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); @NotNull SortedSet set = new TreeSet<>(); set.add("one"); set.add("two"); @@ -1750,7 +1759,7 @@ public void testSortedSet() { @Test public void testSortedMap() { - @NotNull Wire wire = createWire(); + final Wire wire = createWire(); @NotNull SortedMap set = new TreeMap<>(); set.put("one", 1L); set.put("two", 2L); @@ -1771,13 +1780,13 @@ public void testStringArray() { assumeFalse(Jvm.maxDirectMemory() == 0); @NotNull Wire wire = createWire(); - wire.bytes().append("!" + StringArray.class.getName() + " { strings: [ a, b, c ] }"); + wire.bytes().append("!").append(StringArray.class.getName()).append(" { strings: [ a, b, c ] }"); StringArray sa = wire.getValueIn() .object(StringArray.class); assertEquals("[a, b, c]", Arrays.toString(sa.strings)); @NotNull Wire wire2 = createWire(); - wire2.bytes().append("!" + StringArray.class.getName() + " { strings: abc }"); + wire2.bytes().append("!").append(StringArray.class.getName()).append(" { strings: abc }"); StringArray sa2 = wire2.getValueIn() .object(StringArray.class); assertEquals("[abc]", Arrays.toString(sa2.strings)); @@ -1848,7 +1857,7 @@ public void readMarshallableAsEnum() { public void nestedWithEnumSet() { assumeFalse(Jvm.maxDirectMemory() == 0); - Wire wire = createWire(); + final Wire wire = createWire(); YNestedWithEnumSet n = new YNestedWithEnumSet(); n.list.add(new WithEnumSet("none")); n.list.add(new WithEnumSet("one", EnumSet.of(TimeUnit.DAYS))); @@ -1880,7 +1889,7 @@ public void testDoublePrecisionOverYamlWire() { final YamlWire wire2 = YamlWire.from(bytes.toString()); final double d2 = wire2.getValueIn().float64(); - Assert.assertEquals(d2, d, 0); + Assert.assertEquals(d, d2, 0); bytes.releaseLast(); } @@ -1897,7 +1906,7 @@ public void readsComment() { wire.commentListener(cs -> sb.append(cs).append("\n")); } - final MethodReader reader = wire.methodReader((BinaryWireTest.IDTO) dto -> sb.append("dto: " + dto + "\n")); + final MethodReader reader = wire.methodReader((BinaryWireTest.IDTO) dto -> sb.append("dto: ").append(dto).append("\n")); assertTrue(reader.readOne()); assertFalse(reader.readOne()); assertEquals("one\n" + @@ -1958,21 +1967,21 @@ public void testNestedListInterleavedComments() { "}\n" + " # fin\n"); - assertArrayEquals(new String[] { "bar", "quux" }, obj.strings); + assertArrayEquals(new String[]{"bar", "quux"}, obj.strings); } @Test public void testListInterleavedComments() { List obj = WireType.YAML.fromString( - " # first\n" + - "[\n" + - " # foo\n" + - " 'bar',\n" + - " # baz\n" + - " 'quux'\n" + - " # thud\n" + - "]\n" + - " # fin\n"); + " # first\n" + + "[\n" + + " # foo\n" + + " 'bar',\n" + + " # baz\n" + + " 'quux'\n" + + " # thud\n" + + "]\n" + + " # fin\n"); assertEquals(Arrays.asList("bar", "quux"), obj); } @@ -2065,7 +2074,7 @@ static class TwoFields extends AbstractMarshallableCfg { int d; int notThere; - transient Map others = new LinkedHashMap<>(); + final transient Map others = new LinkedHashMap<>(); @Override public void unexpectedField(Object event, ValueIn valueIn) { @@ -2079,6 +2088,7 @@ static class StringArray implements Marshallable { static class BytesWrapper extends SelfDescribingMarshallable { @NotNull + final Bytes bytes = allocateElasticDirect(); void bytes(@NotNull CharSequence cs) { @@ -2088,7 +2098,7 @@ void bytes(@NotNull CharSequence cs) { } static class YNestedWithEnumSet extends SelfDescribingMarshallable { - List list = new ArrayList<>(); + final List list = new ArrayList<>(); } static class Data extends SelfDescribingMarshallable { @@ -2098,6 +2108,6 @@ static class Data extends SelfDescribingMarshallable { byte[] data; } - private class Circle implements Marshallable { + private static class Circle implements Marshallable { } } diff --git a/src/test/java/net/openhft/chronicle/wire/bytesmarshallable/BytesMarshallableTest.java b/src/test/java/net/openhft/chronicle/wire/bytesmarshallable/BytesMarshallableTest.java index 47a5571335..94bd5dc86a 100644 --- a/src/test/java/net/openhft/chronicle/wire/bytesmarshallable/BytesMarshallableTest.java +++ b/src/test/java/net/openhft/chronicle/wire/bytesmarshallable/BytesMarshallableTest.java @@ -51,7 +51,6 @@ private Wire createWire() { // Test method to verify the (de)serialization of primitive data transfer objects (DTOs) // with the wire, also validating against expected string representations - @SuppressWarnings("incomplete-switch") @Test public void primitiveDto() { assumeFalse(Jvm.maxDirectMemory() == 0); @@ -70,14 +69,14 @@ public void primitiveDto() { // based on the current `wireType` being tested String expected = "Unknown wire type"; switch (wireType) { - // Cases define the expected debug string output of the wire bytes - // based on the different wire types case TEXT: expected = "[pos: 0, rlim: 159, wlim: 2147483632, cap: 2147483632 ] ǁprim: {⒑ flag: true,⒑ s8: 1,⒑ ch: \"\\x01\",⒑ s16: 1,⒑ s32: 1,⒑ s64: 1,⒑ f32: 1.0,⒑ f64: 1.0⒑}⒑scalar: {⒑ text: Hello1,⒑ buffer: bye 1,⒑ bytes: hi 1⒑}⒑‡٠٠٠٠٠٠٠٠"; break; case BINARY_LIGHT: expected = "[pos: 0, rlim: 69, wlim: 2147483632, cap: 2147483632 ] ǁÄprim\\u0082\\u001D٠٠٠Y⒈⒈⒈٠⒈٠٠٠⒈٠٠٠٠٠٠٠٠٠\\u0080?٠٠٠٠٠٠ð?Æscalar\\u0082⒙٠٠٠⒍Hello1⒌bye 1⒋hi 1‡٠٠٠٠٠٠٠٠٠٠٠"; break; + default: + throw new IllegalStateException("Unsupported wire type " + wireType); } // Asserting that the expected string equals the debug string output of the wire bytes assertEquals(expected, wire.bytes().toDebugString()); @@ -100,7 +99,6 @@ public void primitiveDto() { } // Another test method similar to the above, but using different DTO types (PrimDto2 and ScalarDto2) - @SuppressWarnings("incomplete-switch") @Test public void primitiveDto2() { assumeFalse(Jvm.maxDirectMemory() == 0); @@ -125,6 +123,9 @@ public void primitiveDto2() { case BINARY_LIGHT: expected = "[pos: 0, rlim: 50, wlim: 2147483632, cap: 2147483632 ] ǁÄprim\\u0082⒑٠٠٠Y⒈⒈⒈⒈⒈\\u009F|\\u009F|Æscalar\\u0082⒙٠٠٠⒍Hello1⒌bye 1⒋hi 1‡٠٠٠٠٠٠٠٠٠٠٠٠٠٠"; break; + + default: + throw new IllegalStateException("Unsupported wire type " + wireType); } // Asserting that the expected string equals the debug string output of the wire bytes assertEquals(expected, wire.bytes().toDebugString()); @@ -187,7 +188,7 @@ static T init(int i, T d) { d.ch = (char) i; d.s16 = (short) i; d.s32 = i; - d.s64 = i * i * i; + d.s64 = (long) i * i * i; d.f32 = d.s32; d.f64 = d.s64; return d; diff --git a/src/test/java/net/openhft/chronicle/wire/bytesmarshallable/NestedGenericTest.java b/src/test/java/net/openhft/chronicle/wire/bytesmarshallable/NestedGenericTest.java index d01e8f2589..cf688c64bf 100644 --- a/src/test/java/net/openhft/chronicle/wire/bytesmarshallable/NestedGenericTest.java +++ b/src/test/java/net/openhft/chronicle/wire/bytesmarshallable/NestedGenericTest.java @@ -108,8 +108,8 @@ public int hashCode() { // Class A implementing BytesMarshallable interface to enable serialization/deserialization using Chronicle Wire private static class A implements BytesMarshallable { - int x; - String y; + final int x; + final String y; A(int x, String y) { this.x = x; diff --git a/src/test/java/net/openhft/chronicle/wire/bytesmarshallable/PerfRegressionHolder.java b/src/test/java/net/openhft/chronicle/wire/bytesmarshallable/PerfRegressionHolder.java index 5ce9f6344c..1457d6aecf 100644 --- a/src/test/java/net/openhft/chronicle/wire/bytesmarshallable/PerfRegressionHolder.java +++ b/src/test/java/net/openhft/chronicle/wire/bytesmarshallable/PerfRegressionHolder.java @@ -20,43 +20,33 @@ import static net.openhft.chronicle.core.UnsafeMemory.MEMORY; public class PerfRegressionHolder { - // A set of test strings split into an array - private String[] s = "1,12,12345,123456789,123456789012,12345678901234567890123".split(","); - // Various field initializations using different constructors or default constructors - // for different types of BytesFields and StringFields - private BytesFields bf1 = new BytesFields(s); - private BytesFields bf2 = new BytesFields(); - - private DefaultBytesFields df1 = new DefaultBytesFields(s); - private DefaultBytesFields df2 = new DefaultBytesFields(); - - private ReferenceBytesFields rf1 = new ReferenceBytesFields(s); - private ReferenceBytesFields rf2 = new ReferenceBytesFields(); - - private StringFields sf1 = new StringFields(s); - private StringFields sf2 = new StringFields(); - - private DefaultStringFields dsf1 = new DefaultStringFields(s); - private DefaultStringFields dsf2 = new DefaultStringFields(); - - private ArrayStringFields asf1 = new ArrayStringFields(s); - private ArrayStringFields asf2 = new ArrayStringFields(); - - private DefaultUtf8StringFields dusf1 = new DefaultUtf8StringFields(s); - private DefaultUtf8StringFields dusf2 = new DefaultUtf8StringFields(); - - private DefaultStringFields dsf0 = new DefaultStringFields(new String[6]); - + // A volatile integer barrier utilized possibly for ensuring visibility between threads + private static volatile int barrier; // Initializing byte buffers: one direct (off-heap) and one on heap private final Bytes direct = Bytes.allocateElasticDirect(); private final Bytes onHeap = Bytes.allocateElasticOnHeap(); - + // A set of test strings split into an array + private final String[] s = "1,12,12345,123456789,123456789012,12345678901234567890123".split(","); + // Various field initializations using different constructors or default constructors + // for different types of BytesFields and StringFields + private final BytesFields bf1 = new BytesFields(s); + private final BytesFields bf2 = new BytesFields(); + private final DefaultBytesFields df1 = new DefaultBytesFields(s); + private final DefaultBytesFields df2 = new DefaultBytesFields(); + private final ReferenceBytesFields rf1 = new ReferenceBytesFields(s); + private final ReferenceBytesFields rf2 = new ReferenceBytesFields(); + private final StringFields sf1 = new StringFields(s); + private final StringFields sf2 = new StringFields(); + private final DefaultStringFields dsf1 = new DefaultStringFields(s); + private final DefaultStringFields dsf2 = new DefaultStringFields(); + private final ArrayStringFields asf1 = new ArrayStringFields(s); + private final ArrayStringFields asf2 = new ArrayStringFields(); + private final DefaultUtf8StringFields dusf1 = new DefaultUtf8StringFields(s); + private final DefaultUtf8StringFields dusf2 = new DefaultUtf8StringFields(); + private final DefaultStringFields dsf0 = new DefaultStringFields(new String[6]); // MappedBytes will be used to map files into memory for testing private MappedBytes mapped; - // A volatile integer barrier utilized possibly for ensuring visibility between threads - private static volatile int barrier; - // Method to perform a performance test using a provided Runnable public void doTest(Runnable runnable) { // Creating a temporary file and ensuring it will be deleted upon JVM exit @@ -97,15 +87,88 @@ public void doTest(Runnable runnable) { } } + // Example test method for benchmarking a specific type of object + public void benchNull() { + testAll2(this.dsf0, this.dsf2); // Utilizing a variant of the testing method + } + + public void benchBytes() { + testAll(this.df1, this.df2); + } + + public void benchFields() { + testAll(this.bf1, this.bf2); + } + + public void benchRefBytes() { + testAll(this.rf1, this.rf2); + } + + public void benchString() { + testAll(this.dsf1, this.dsf2); + } + + public void benchArrayString() { + testAll(this.asf1, this.asf2); + } + + public void benchUtf8String() { + testAll(this.dusf1, this.dusf2); + } + + public void benchRefString() { + testAll(this.sf1, this.sf2); + } + + // Method to perform a basic test, writing and then reading data for various buffer types + private void testAll(BytesMarshallable from, BytesMarshallable to) { + onHeap.clear(); + from.writeMarshallable(onHeap); + to.readMarshallable(onHeap); + + direct.clear(); + from.writeMarshallable(direct); + to.readMarshallable(direct); + + mapped.clear(); + from.writeMarshallable(mapped); + to.readMarshallable(mapped); + } + + // Method to perform a variation of the basic test, performing multiple read operations + // after a single write for each buffer type + private void testAll2(BytesMarshallable from, BytesMarshallable to) { + onHeap.clear(); + from.writeMarshallable(onHeap); + for (int j = 0; j < 4; j++) { + onHeap.readPosition(0); + to.readMarshallable(onHeap); + } + + direct.clear(); + from.writeMarshallable(direct); + for (int j = 0; j < 4; j++) { + direct.readPosition(0); + to.readMarshallable(direct); + } + + mapped.clear(); + from.writeMarshallable(mapped); + for (int j = 0; j < 4; j++) { + mapped.readPosition(0); + to.readMarshallable(mapped); + } + } + // Inner class representing a type of marshallable byte fields for testing static class BytesFields extends BytesInBinaryMarshallable { // Several Bytes objects used for testing purposes - Bytes a = Bytes.allocateElasticOnHeap(); - Bytes b = Bytes.allocateElasticOnHeap(); - Bytes c = Bytes.allocateElasticOnHeap(); - Bytes d = Bytes.allocateElasticOnHeap(); - Bytes e = Bytes.allocateElasticOnHeap(); - Bytes f = Bytes.allocateElasticOnHeap(); + final Bytes a = Bytes.allocateElasticOnHeap(); + final Bytes b = Bytes.allocateElasticOnHeap(); + final Bytes c = Bytes.allocateElasticOnHeap(); + final Bytes d = Bytes.allocateElasticOnHeap(); + final Bytes e = Bytes.allocateElasticOnHeap(); + final Bytes f = Bytes.allocateElasticOnHeap(); // Default constructor BytesFields() { @@ -291,10 +354,6 @@ static class ArrayStringFields extends StringFields { ArrayStringFields(String... s) { super(s); } - // UU 2340 - // 8U 3110 - // U8 3060 - // 88 3510 // Read marshallable data from a byte sequence into String fields // using memory offsets for potentially enhanced performance. @@ -390,79 +449,4 @@ public void writeMarshallable(BytesOut bytes) throws IllegalStateException, B bytes.writeUtf8(f); } } - - // Example test method for benchmarking a specific type of object - public void benchNull() { - final DefaultStringFields from = this.dsf0; - final DefaultStringFields to = this.dsf2; - testAll2(from, to); // Utilizing a variant of the testing method - } - - public void benchBytes() { - testAll(this.df1, this.df2); - } - - public void benchFields() { - testAll(this.bf1, this.bf2); - } - - public void benchRefBytes() { - testAll(this.rf1, this.rf2); - } - - public void benchString() { - testAll(this.dsf1, this.dsf2); - } - - public void benchArrayString() { - testAll(this.asf1, this.asf2); - } - - public void benchUtf8String() { - testAll(this.dusf1, this.dusf2); - } - - public void benchRefString() { - testAll(this.sf1, this.sf2); - } - - // Method to perform a basic test, writing and then reading data for various buffer types - private void testAll(BytesMarshallable from, BytesMarshallable to) { - onHeap.clear(); - from.writeMarshallable(onHeap); - to.readMarshallable(onHeap); - - direct.clear(); - from.writeMarshallable(direct); - to.readMarshallable(direct); - - mapped.clear(); - from.writeMarshallable(mapped); - to.readMarshallable(mapped); - } - - // Method to perform a variation of the basic test, performing multiple read operations - // after a single write for each buffer type - private void testAll2(BytesMarshallable from, BytesMarshallable to) { - onHeap.clear(); - from.writeMarshallable(onHeap); - for (int j = 0; j < 4; j++) { - onHeap.readPosition(0); - to.readMarshallable(onHeap); - } - - direct.clear(); - from.writeMarshallable(direct); - for (int j = 0; j < 4; j++) { - direct.readPosition(0); - to.readMarshallable(direct); - } - - mapped.clear(); - from.writeMarshallable(mapped); - for (int j = 0; j < 4; j++) { - mapped.readPosition(0); - to.readMarshallable(mapped); - } - } } diff --git a/src/test/java/net/openhft/chronicle/wire/bytesmarshallable/PerfRegressionTest.java b/src/test/java/net/openhft/chronicle/wire/bytesmarshallable/PerfRegressionTest.java index 4cc3ea2c73..46be15dd78 100644 --- a/src/test/java/net/openhft/chronicle/wire/bytesmarshallable/PerfRegressionTest.java +++ b/src/test/java/net/openhft/chronicle/wire/bytesmarshallable/PerfRegressionTest.java @@ -26,7 +26,6 @@ public class PerfRegressionTest extends WireTestCommon { @Test public void regressionTests() throws Exception { final URL location = PerfRegressionTest.class.getProtectionDomain().getCodeSource().getLocation(); -// System.getProperties().forEach((k,v) -> System.out.println(k+"= "+v)); File file = new File(location.getFile()); // Navigate the directory structure to the "target" directory. @@ -36,12 +35,8 @@ public void regressionTests() throws Exception { // Array of classes that appear to be subjected to the benchmark test. Class[] classes = { -// BenchBytesMain.class, BenchStringMain.class, BenchArrayStringMain.class, -// BenchNullMain.class, -// BenchFieldsMain.class, -// BenchRefBytesMain.class, BenchRefStringMain.class, BenchUtf8StringMain.class, }; @@ -117,8 +112,7 @@ private Process getProcess(File file, Class aClass) throws IOException { pb.directory(file.getParentFile()); // Start the process and return it - final Process process = pb.start(); - return process; + return pb.start(); } // Retrieve and return the execution result from the output stream of a given process @@ -144,16 +138,13 @@ private long getResult(Class aClass, long result, Process process) throws IOE process.destroy(); return result; } -// doTest( -// times -> timesOk(times[0], times[1], times[2])); -// } // Determine if execution times for a set of tests are within acceptable ranges private boolean timesOk(double d, double ds, double dn) { // Validate times against predefined thresholds depending on the CPU class if (cpuClass.equals("AMD Ryzen 5 3600 6-Core Processor") || - cpuClass.startsWith("ARM") || - cpuClass.contains(" Xeon")) { + cpuClass.startsWith("ARM") || + cpuClass.contains(" Xeon")) { // Check if times are within the defined ranges for general CPUs if ((0.7 <= d && d <= 0.92) && diff --git a/src/test/java/net/openhft/chronicle/wire/converter/Base64Test.java b/src/test/java/net/openhft/chronicle/wire/converter/Base64Test.java index b6641ba8dd..dd68856521 100644 --- a/src/test/java/net/openhft/chronicle/wire/converter/Base64Test.java +++ b/src/test/java/net/openhft/chronicle/wire/converter/Base64Test.java @@ -89,12 +89,16 @@ interface UsesBase64 { */ static class Data64 extends SelfDescribingMarshallable { @Base64 + final byte b; @Base64 + final short s; @Base64 + final int i; @Base64 + final long data; /** diff --git a/src/test/java/net/openhft/chronicle/wire/converter/LongConvertorFieldsTest.java b/src/test/java/net/openhft/chronicle/wire/converter/LongConvertorFieldsTest.java index 497a76b84f..703005ae39 100644 --- a/src/test/java/net/openhft/chronicle/wire/converter/LongConvertorFieldsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/converter/LongConvertorFieldsTest.java @@ -3,7 +3,6 @@ */ package net.openhft.chronicle.wire.converter; -import net.openhft.chronicle.bytes.Bytes; import net.openhft.chronicle.wire.*; import org.junit.Test; @@ -19,14 +18,19 @@ public class LongConvertorFieldsTest { */ static class Base16DTO extends SelfDescribingMarshallable { @Base16 + final byte b; @Base16 + final char ch; @Base16 + final short s; @Base16 + final int i; @Base16 + final long l; /** @@ -78,14 +82,19 @@ public void base16() { */ static class Base64DTO extends SelfDescribingMarshallable { @Base64 + final byte b; @Base64 + final char ch; @Base64 + final short s; @Base64 + final int i; @Base64 + final long l; /** @@ -137,14 +146,19 @@ public void base64() { */ static class Base85DTO extends SelfDescribingMarshallable { @Base85 + final byte b; @Base85 + final char ch; @Base85 + final short s; @Base85 + final int i; @Base85 + final long l; /** @@ -209,14 +223,19 @@ public void detectSpecialCharBase85() { static class ShortTextDTO extends SelfDescribingMarshallable { @ShortText + final byte b; @ShortText + final char ch; @ShortText + final short s; @ShortText + final int i; @ShortText + final long l; ShortTextDTO(byte b, char ch, short s, int i, long l) { @@ -267,14 +286,19 @@ public void detectSpecialChar() { static class WordsDTO extends SelfDescribingMarshallable { @Words + final byte b; @Words + final char ch; @Words + final short s; @Words + final int i; @Words + final long l; /** diff --git a/src/test/java/net/openhft/chronicle/wire/converter/NanoTimeTest.java b/src/test/java/net/openhft/chronicle/wire/converter/NanoTimeTest.java index 1b28502df2..e278689ffa 100644 --- a/src/test/java/net/openhft/chronicle/wire/converter/NanoTimeTest.java +++ b/src/test/java/net/openhft/chronicle/wire/converter/NanoTimeTest.java @@ -3,6 +3,7 @@ */ package net.openhft.chronicle.wire.converter; +import net.openhft.chronicle.core.annotation.UsedViaReflection; import net.openhft.chronicle.wire.SelfDescribingMarshallable; import net.openhft.chronicle.wire.Wire; import org.junit.Test; @@ -62,6 +63,7 @@ interface UseNanoTime { * that automatically provides serialization and deserialization functionality for the object. */ static class Event extends SelfDescribingMarshallable { + @UsedViaReflection @NanoTime private long start; diff --git a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/CreateUtil.java b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/CreateUtil.java index b0663e9be1..9281f4fc7f 100644 --- a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/CreateUtil.java +++ b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/CreateUtil.java @@ -45,19 +45,6 @@ public static Wire createThenWritingDocuments(@NotNull final Consumer mutator) { - final Consumer queueMutator = q -> { - ExcerptAppender excerptAppender = q.acquireAppender(); - mutator.accept(excerptAppender); - }; - return createThen(name, queueMutator); - } -*/ - // Create a Wire and then apply a single Wire mutator to it @NotNull public static Wire createThen(@NotNull final Consumer wireMutator) { diff --git a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/StreamsTest.java b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/StreamsTest.java index d234c27106..936138cb62 100644 --- a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/StreamsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/StreamsTest.java @@ -17,6 +17,7 @@ import static net.openhft.chronicle.wire.domestic.streaming.CreateUtil.createThenValueOuts; import static org.junit.jupiter.api.Assertions.*; +@SuppressWarnings({"deprecation", "removal"}) class StreamsTest extends net.openhft.chronicle.wire.WireTestCommon { @Test diff --git a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/CollectorTest.java b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/CollectorTest.java index 304679894a..b460580d5c 100644 --- a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/CollectorTest.java +++ b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/CollectorTest.java @@ -23,6 +23,7 @@ import static net.openhft.chronicle.wire.domestic.reduction.ConcurrentCollectors.replacingMerger; import static org.junit.Assert.assertEquals; +@SuppressWarnings({"deprecation", "removal"}) public class CollectorTest extends WireTestCommon { private static final String Q_NAME = CollectorTest.class.getSimpleName(); diff --git a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/CountAccumulationTest.java b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/CountAccumulationTest.java index 9f2e36ab8d..107c811c54 100644 --- a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/CountAccumulationTest.java +++ b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/CountAccumulationTest.java @@ -17,6 +17,7 @@ import static net.openhft.chronicle.wire.domestic.reduction.ConcurrentCollectors.throwingMerger; import static org.junit.jupiter.api.Assertions.assertEquals; +@SuppressWarnings({"deprecation", "removal"}) public class CountAccumulationTest extends WireTestCommon { @Test diff --git a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/LastIndexSeenTailerTest.java b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/LastIndexSeenTailerTest.java index 7c14040829..e2766bd8a6 100644 --- a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/LastIndexSeenTailerTest.java +++ b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/LastIndexSeenTailerTest.java @@ -15,6 +15,7 @@ import static net.openhft.chronicle.wire.domestic.streaming.CreateUtil.createThenValueOuts; import static org.junit.jupiter.api.Assertions.assertTrue; +@SuppressWarnings({"deprecation", "removal"}) public class LastIndexSeenTailerTest extends WireTestCommon { @Test diff --git a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/LastIndexSeenTest.java b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/LastIndexSeenTest.java index 4c01135f65..eb4d7e65c0 100644 --- a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/LastIndexSeenTest.java +++ b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/LastIndexSeenTest.java @@ -15,6 +15,7 @@ import static net.openhft.chronicle.wire.domestic.streaming.CreateUtil.createThenValueOuts; import static org.junit.Assert.assertEquals; +@SuppressWarnings({"deprecation", "removal"}) public class LastIndexSeenTest extends WireTestCommon { @Test diff --git a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/LastMarketDataPerSymbolTest.java b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/LastMarketDataPerSymbolTest.java index 0b51d4f440..6384a2bcea 100644 --- a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/LastMarketDataPerSymbolTest.java +++ b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/LastMarketDataPerSymbolTest.java @@ -19,6 +19,7 @@ import static net.openhft.chronicle.wire.domestic.reduction.ConcurrentCollectors.toConcurrentSet; import static org.junit.jupiter.api.Assertions.assertEquals; +@SuppressWarnings({"deprecation", "removal"}) public class LastMarketDataPerSymbolTest extends WireTestCommon { private static final List MARKET_DATA_SET = Arrays.asList( diff --git a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/MethodWriterTest.java b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/MethodWriterTest.java index 81fe4d8e1b..f075f13720 100644 --- a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/MethodWriterTest.java +++ b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/MethodWriterTest.java @@ -21,6 +21,7 @@ import static net.openhft.chronicle.wire.domestic.reduction.ConcurrentCollectors.throwingMerger; import static org.junit.Assert.assertEquals; +@SuppressWarnings({"deprecation", "removal"}) public class MethodWriterTest extends WireTestCommon { private static final List MARKET_DATA_SET = Arrays.asList( diff --git a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/MinMaxLastMarketDataPerSymbolTest.java b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/MinMaxLastMarketDataPerSymbolTest.java index db1cea0d66..9d103a51c5 100644 --- a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/MinMaxLastMarketDataPerSymbolTest.java +++ b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/MinMaxLastMarketDataPerSymbolTest.java @@ -19,6 +19,7 @@ import static net.openhft.chronicle.wire.domestic.reduction.ConcurrentCollectors.*; import static org.junit.jupiter.api.Assertions.assertEquals; +@SuppressWarnings({"deprecation", "removal"}) public class MinMaxLastMarketDataPerSymbolTest extends WireTestCommon { private static final List MARKET_DATA_SET = Arrays.asList( diff --git a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/StreamingDemoMain.java b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/StreamingDemoMain.java index 8bbadf26f4..e5e340f560 100644 --- a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/StreamingDemoMain.java +++ b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/reduction/StreamingDemoMain.java @@ -26,6 +26,7 @@ import static net.openhft.chronicle.wire.domestic.extractor.ToLongDocumentExtractor.extractingIndex; import static net.openhft.chronicle.wire.domestic.reduction.ConcurrentCollectors.replacingMerger; +@SuppressWarnings({"deprecation", "removal"}) public class StreamingDemoMain { public static void main(String[] args) { @@ -146,7 +147,7 @@ public interface MarketDataProvider { void action(Action action); enum Action { - OPEN, CLOSE; + OPEN, CLOSE } } } diff --git a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/streams/StreamsDemoTest.java b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/streams/StreamsDemoTest.java index 64e5edf918..dd25236f01 100644 --- a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/streams/StreamsDemoTest.java +++ b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/streams/StreamsDemoTest.java @@ -13,6 +13,7 @@ import net.openhft.chronicle.wire.domestic.stream.Streams; import net.openhft.chronicle.wire.domestic.streaming.reduction.MarketData; import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -28,10 +29,10 @@ import static java.util.stream.Collectors.toList; import static net.openhft.chronicle.wire.domestic.extractor.DocumentExtractor.builder; import static net.openhft.chronicle.wire.domestic.streaming.CreateUtil.*; -import static org.junit.Assert.fail; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +@SuppressWarnings({"deprecation", "removal"}) final class StreamsDemoTest extends net.openhft.chronicle.wire.WireTestCommon { @Test @@ -95,7 +96,7 @@ void streamTypeMarketDataSimpleWIthInvalid() { vo -> vo.object(invalid) ); - fail(wire.toString()); + Assertions.fail(wire.toString()); } catch (InvalidMarshallableException expected) { // expected } diff --git a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/streams/StreamsTest.java b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/streams/StreamsTest.java index 6dc75dedbf..4cb942989f 100644 --- a/src/test/java/net/openhft/chronicle/wire/domestic/streaming/streams/StreamsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/domestic/streaming/streams/StreamsTest.java @@ -27,6 +27,7 @@ import static java.util.stream.Collectors.toList; import static org.junit.jupiter.api.Assertions.assertEquals; +@SuppressWarnings({"deprecation", "removal"}) final class StreamsTest extends net.openhft.chronicle.wire.WireTestCommon { @TestFactory diff --git a/src/test/java/net/openhft/chronicle/wire/dynenum/WireDynamicEnumTest.java b/src/test/java/net/openhft/chronicle/wire/dynenum/WireDynamicEnumTest.java index f103ab5367..b6ae7d218c 100644 --- a/src/test/java/net/openhft/chronicle/wire/dynenum/WireDynamicEnumTest.java +++ b/src/test/java/net/openhft/chronicle/wire/dynenum/WireDynamicEnumTest.java @@ -258,35 +258,35 @@ public void deserialize2() { // Implement the 'push' method to capture the name, nice, and value of the WDENums enum. @Override public void push(WDENums nums) { - sw.append(nums.name() + " ~ " + nums.nice + " ~ " + nums.value + "\n"); + sw.append(nums.name()).append(" ~ ").append(nums.nice).append(" ~ ").append(String.valueOf(nums.value)).append("\n"); } // Implement the 'holds' method to capture and print the held WDENums. @Override public void holds(HoldsWDENum holdsWDENum) { sw.append(holdsWDENum.toString()); - sw.append("# " + holdsWDENum.a.value + ", " + holdsWDENum.b.value + "\n"); + sw.append("# ").append(String.valueOf(holdsWDENum.a.value)).append(", ").append(String.valueOf(holdsWDENum.b.value)).append("\n"); } // Implement the 'unwraps' method to mark a WDENums enum as updated and then call the 'updateEnum' method. @Override public void unwraps(UnwrapsWDENum unwrapsWDENum) { WDENums c = unwrapsWDENum.c; - sw.append("Update " + c + "\n"); + sw.append("Update ").append(String.valueOf(c)).append("\n"); net.openhft.chronicle.wire.DynamicEnum.updateEnum(c); } // Implement the 'push2' method to capture the name, nice, and value of the WDENum2 enum. @Override public void push2(WDENum2 nums) { - sw.append(nums.name() + " = " + nums.nice + " = " + nums.value + "\n"); + sw.append(nums.name()).append(" = ").append(nums.nice).append(" = ").append(String.valueOf(nums.value)).append("\n"); } // Implement the 'unwrap2' method to mark a WDENum2 as updated and then call the 'updateEnum' method. @Override public void unwrap2(UnwrapsWDENum2 unwrapsWDENum2) { WDENum2 d = unwrapsWDENum2.d; - sw.append("Update " + d + "\n"); + sw.append("Update ").append(String.valueOf(d)).append("\n"); net.openhft.chronicle.wire.DynamicEnum.updateEnum(d); } }); @@ -430,7 +430,8 @@ public int ordinal() { // Class to hold two instances of WDENums static class HoldsWDENum extends SelfDescribingMarshallable { - WDENums a, b; // The two instances of WDENums + final WDENums a; + final WDENums b; // The two instances of WDENums // Constructor initializes the holder with two WDENums values HoldsWDENum(WDENums a, WDENums b) { @@ -442,6 +443,7 @@ static class HoldsWDENum extends SelfDescribingMarshallable { // Class to wrap and unwrap an instance of WDENums for marshalling purposes static class UnwrapsWDENum extends SelfDescribingMarshallable { @AsMarshallable + final WDENums c; // The wrapped instance of WDENums // Constructor initializes the wrapper with a WDENums value @@ -453,6 +455,7 @@ static class UnwrapsWDENum extends SelfDescribingMarshallable { // Class to wrap and unwrap an instance of WDENum2 for marshalling purposes static class UnwrapsWDENum2 extends SelfDescribingMarshallable { @AsMarshallable + final WDENum2 d; // The wrapped instance of WDENum2 // Constructor initializes the wrapper with a WDENum2 value diff --git a/src/test/java/net/openhft/chronicle/wire/examples/MessageRoutingExample.java b/src/test/java/net/openhft/chronicle/wire/examples/MessageRoutingExample.java index 55bc8977dc..31171a384a 100644 --- a/src/test/java/net/openhft/chronicle/wire/examples/MessageRoutingExample.java +++ b/src/test/java/net/openhft/chronicle/wire/examples/MessageRoutingExample.java @@ -47,7 +47,7 @@ interface ProductHandler { * A example of a simple business event */ static class Product extends SelfDescribingMarshallable { - String name; + final String name; Product(String name) { this.name = name; diff --git a/src/test/java/net/openhft/chronicle/wire/examples/WireExamples1.java b/src/test/java/net/openhft/chronicle/wire/examples/WireExamples1.java index 340cd7fcce..20c865a3d6 100644 --- a/src/test/java/net/openhft/chronicle/wire/examples/WireExamples1.java +++ b/src/test/java/net/openhft/chronicle/wire/examples/WireExamples1.java @@ -37,12 +37,8 @@ private static void example2() { } static class Car implements Marshallable { - private int number; - private String driver; Car(String driver, int number) { - this.driver = driver; - this.number = number; } } } diff --git a/src/test/java/net/openhft/chronicle/wire/examples/WireExamples2.java b/src/test/java/net/openhft/chronicle/wire/examples/WireExamples2.java index c5513b4a21..eb5fd697a0 100644 --- a/src/test/java/net/openhft/chronicle/wire/examples/WireExamples2.java +++ b/src/test/java/net/openhft/chronicle/wire/examples/WireExamples2.java @@ -42,11 +42,11 @@ public static void main(String... args) { */ static class TextObject extends SelfDescribingMarshallable { // Temporary buffer for conversion purposes - transient StringBuilder temp = new StringBuilder(); + final transient StringBuilder temp = new StringBuilder(); // Represents the text in Base64 encoded format @LongConversion(Base64LongConverter.class) - private long text; + private final long text; /** * Constructor to initialize the `TextObject` with the given text. diff --git a/src/test/java/net/openhft/chronicle/wire/internal/MethodWriterClassNameGeneratorTest.java b/src/test/java/net/openhft/chronicle/wire/internal/MethodWriterClassNameGeneratorTest.java index 0f9c14f404..5646e4e3d8 100644 --- a/src/test/java/net/openhft/chronicle/wire/internal/MethodWriterClassNameGeneratorTest.java +++ b/src/test/java/net/openhft/chronicle/wire/internal/MethodWriterClassNameGeneratorTest.java @@ -81,7 +81,7 @@ public void testTruncatedClassNamesDifferWhenOnlyTruncatedPortionDiffers() { NewOrderSingleListenerOmsHedgerTradeListenerOpenOrdersListenerPaidGivenTickListener2.class); String cn2 = generatedClassName(null, false, false, WireType.TEXT, NewOrderSingleListenerOmsHedgerTradeListenerOpenOrdersListenerPaidGivenTickListener1.class, - NewOrderSingleListenerOmsHedgerTradeListenerOpenOrdersListenerPaidGi_DiffersInTheTruncatedPortion.class); + NewOrderSingleListenerOmsHedgerTradeListenerOpenOrdersListenerPaidGiDiffersInTheTruncatedPortion.class); Jvm.startup().on(MethodWriterClassNameGeneratorTest.class, "Must differ:\n" + cn1 + "\n" + cn2); assertNotEquals(cn1, cn2); } @@ -104,6 +104,6 @@ private interface NewOrderSingleListenerOmsHedgerTradeListenerOpenOrdersListener private interface NewOrderSingleListenerOmsHedgerTradeListenerOpenOrdersListenerPaidGivenTickListener2 { } - private interface NewOrderSingleListenerOmsHedgerTradeListenerOpenOrdersListenerPaidGi_DiffersInTheTruncatedPortion { + private interface NewOrderSingleListenerOmsHedgerTradeListenerOpenOrdersListenerPaidGiDiffersInTheTruncatedPortion { } } diff --git a/src/test/java/net/openhft/chronicle/wire/internal/stream/StreamsUtilTest.java b/src/test/java/net/openhft/chronicle/wire/internal/stream/StreamsUtilTest.java index 7826f936c0..de6a6b4f16 100644 --- a/src/test/java/net/openhft/chronicle/wire/internal/stream/StreamsUtilTest.java +++ b/src/test/java/net/openhft/chronicle/wire/internal/stream/StreamsUtilTest.java @@ -18,17 +18,18 @@ import static org.junit.Assert.*; +@SuppressWarnings({"deprecation", "removal"}) public class StreamsUtilTest extends net.openhft.chronicle.wire.WireTestCommon { @Test - public void VanillaSpliterator_estimateSize_alwaysReturnsLongMaxValue() { + public void vanillaSpliteratorEstimateSizeAlwaysReturnsLongMaxValue() { Collection collection = Collections.emptyList(); StreamsUtil.VanillaSpliterator spliterator = new StreamsUtil.VanillaSpliterator<>(collection.iterator()); assertEquals(Long.MAX_VALUE, spliterator.estimateSize()); } @Test - public void VanillaSpliterator_trySplit_iteratorWithNoContentsShouldYieldNullSpliterator() { + public void vanillaSpliteratorTrySplitIteratorWithNoContentsShouldYieldNullSpliterator() { Collection collection = Collections.emptyList(); StreamsUtil.VanillaSpliterator spliterator = new StreamsUtil.VanillaSpliterator<>(collection.iterator()); Spliterator split = spliterator.trySplit(); @@ -36,7 +37,7 @@ public void VanillaSpliterator_trySplit_iteratorWithNoContentsShouldYieldNullSpl } @Test - public void VanillaSpliterator_trySplit_batchSizeShouldBeCappedByTwoTimesBatchUnitIncrease() { + public void vanillaSpliteratorTrySplitBatchSizeShouldBeCappedByTwoTimesBatchUnitIncrease() { Collection collection = Stream.generate(() -> 1).limit(16777216).collect(Collectors.toList()); StreamsUtil.VanillaSpliterator spliterator = new StreamsUtil.VanillaSpliterator<>(collection.iterator()); Spliterator split = spliterator.trySplit(); @@ -44,7 +45,7 @@ public void VanillaSpliterator_trySplit_batchSizeShouldBeCappedByTwoTimesBatchUn } @Test - public void VanillaSpliterator_trySplit_batchSizeSmallerThanMatchMaxSizeShouldBeReleased() { + public void vanillaSpliteratorTrySplitBatchSizeSmallerThanMatchMaxSizeShouldBeReleased() { Collection collection = Stream.generate(() -> 1).limit(10).collect(Collectors.toList()); StreamsUtil.VanillaSpliterator spliterator = new StreamsUtil.VanillaSpliterator<>(collection.iterator()); Spliterator split = spliterator.trySplit(); @@ -52,21 +53,21 @@ public void VanillaSpliterator_trySplit_batchSizeSmallerThanMatchMaxSizeShouldBe } @Test - public void VanillaSpliteratorOfLong_split() { + public void vanillaSpliteratorOfLongSplit() { PrimitiveIterator.OfLong iterator = LongStream.of(1, 2).iterator(); StreamsUtil.VanillaSpliteratorOfLong spliterator = new StreamsUtil.VanillaSpliteratorOfLong(iterator); assertEquals(1, spliterator.split(1).getExactSizeIfKnown()); } @Test - public void VanillaSpliteratorOfDouble_split() { + public void vanillaSpliteratorOfDoubleSplit() { PrimitiveIterator.OfDouble iterator = DoubleStream.of(1, 2).iterator(); StreamsUtil.VanillaSpliteratorOfDouble spliterator = new StreamsUtil.VanillaSpliteratorOfDouble(iterator); assertEquals(1, spliterator.split(1).getExactSizeIfKnown()); } @Test - public void VanillaSpliteratorOfDouble_trySplit_iteratorWithNoContentsShouldYieldNullSpliterator() { + public void vanillaSpliteratorOfDoubleTrySplitIteratorWithNoContentsShouldYieldNullSpliterator() { PrimitiveIterator.OfDouble iterator = DoubleStream.empty().iterator(); StreamsUtil.VanillaSpliteratorOfDouble spliterator = new StreamsUtil.VanillaSpliteratorOfDouble(iterator); Spliterator.OfDouble split = spliterator.trySplit(); @@ -74,7 +75,7 @@ public void VanillaSpliteratorOfDouble_trySplit_iteratorWithNoContentsShouldYiel } @Test - public void VanillaSpliteratorOfDouble_trySplit_batchSizeShouldBeCappedByTwoTimesBatchUnitIncrease() { + public void vanillaSpliteratorOfDoubleTrySplitBatchSizeShouldBeCappedByTwoTimesBatchUnitIncrease() { PrimitiveIterator.OfDouble iterator = DoubleStream.generate(() -> 1).limit(16777216).iterator(); StreamsUtil.VanillaSpliteratorOfDouble spliterator = new StreamsUtil.VanillaSpliteratorOfDouble(iterator); Spliterator.OfDouble split = spliterator.trySplit(); @@ -82,7 +83,7 @@ public void VanillaSpliteratorOfDouble_trySplit_batchSizeShouldBeCappedByTwoTime } @Test - public void VanillaSpliteratorOfDouble_tryAdvance_nextValueShouldBeYielded() { + public void vanillaSpliteratorOfDoubleTryAdvanceNextValueShouldBeYielded() { PrimitiveIterator.OfDouble iterator = DoubleStream.generate(() -> 1).limit(16777216).iterator(); StreamsUtil.VanillaSpliteratorOfDouble spliterator = new StreamsUtil.VanillaSpliteratorOfDouble(iterator); @@ -93,7 +94,7 @@ public void VanillaSpliteratorOfDouble_tryAdvance_nextValueShouldBeYielded() { } @Test - public void VanillaSpliteratorOfDouble_tryAdvance_noValueYieldedForEmptyStream() { + public void vanillaSpliteratorOfDoubleTryAdvanceNoValueYieldedForEmptyStream() { PrimitiveIterator.OfDouble iterator = DoubleStream.empty().iterator(); StreamsUtil.VanillaSpliteratorOfDouble spliterator = new StreamsUtil.VanillaSpliteratorOfDouble(iterator); @@ -104,7 +105,7 @@ public void VanillaSpliteratorOfDouble_tryAdvance_noValueYieldedForEmptyStream() } @Test - public void VanillaSpliteratorOfDouble_estimateSize_alwaysReturnsLongMaxValue() { + public void vanillaSpliteratorOfDoubleEstimateSizeAlwaysReturnsLongMaxValue() { PrimitiveIterator.OfDouble iterator = DoubleStream.empty().iterator(); StreamsUtil.VanillaSpliteratorOfDouble spliterator = new StreamsUtil.VanillaSpliteratorOfDouble(iterator); assertEquals(Long.MAX_VALUE, spliterator.estimateSize()); diff --git a/src/test/java/net/openhft/chronicle/wire/issue/ClassAliasPool840Test.java b/src/test/java/net/openhft/chronicle/wire/issue/ClassAliasPool840Test.java index 18e7714a90..e66cf358ea 100644 --- a/src/test/java/net/openhft/chronicle/wire/issue/ClassAliasPool840Test.java +++ b/src/test/java/net/openhft/chronicle/wire/issue/ClassAliasPool840Test.java @@ -24,38 +24,43 @@ public void typeIsLoadedByClassLookup() { @Override public Class forName(CharSequence name) throws ClassNotFoundRuntimeException { switch (name.toString()) { - case "Dto": return Dto.class; - case "Type" : return Type.class; - case "type" : return Class.class; - default: throw new IllegalStateException(); + case "Dto": + return Dto.class; + case "Type": + return Type.class; + case "type": + return Class.class; + default: + throw new IllegalStateException(); } } @Override public String nameFor(Class clazz) throws IllegalArgumentException { if (clazz.equals(Dto.class)) return "Dto"; - if (clazz.equals(Type.class)) return "Type"; - if (clazz.equals(Class.class)) return "type"; + if (clazz.equals(Type.class)) return "Type"; + if (clazz.equals(Class.class)) return "type"; throw new IllegalStateException(); } @Override - public void addAlias(Class... classes) {} + public void addAlias(Class... classes) { + } @Override - public void addAlias(Class clazz, String names) {} + public void addAlias(Class clazz, String names) { + } }; Wire wire = WireType.YAML_ONLY.apply(Bytes.allocateElasticOnHeap()); wire.classLookup(customClassLookup); wire.reset(); - wire.bytes().clear().append( - "{ " + - "obj: !Dto { value: 1 }, " + - "clazz: !type Type " + - "}"); + wire.bytes().clear().append("{ " + + "obj: !Dto { value: 1 }, " + + "clazz: !type Type " + + "}"); StringBuilder name = new StringBuilder(); while (wire.hasMore()) { diff --git a/src/test/java/net/openhft/chronicle/wire/issue/Issue272Test.java b/src/test/java/net/openhft/chronicle/wire/issue/Issue272Test.java index e34b58cd4b..352e86a182 100644 --- a/src/test/java/net/openhft/chronicle/wire/issue/Issue272Test.java +++ b/src/test/java/net/openhft/chronicle/wire/issue/Issue272Test.java @@ -18,6 +18,7 @@ /** * Test class to validate the behavior and serialization of Wire objects with arrays. */ +@SuppressWarnings({"deprecation", "removal"}) public class Issue272Test { /** diff --git a/src/test/java/net/openhft/chronicle/wire/issue/Issue277Test.java b/src/test/java/net/openhft/chronicle/wire/issue/Issue277Test.java index 6ab9fa2c0b..db8b58a2f8 100644 --- a/src/test/java/net/openhft/chronicle/wire/issue/Issue277Test.java +++ b/src/test/java/net/openhft/chronicle/wire/issue/Issue277Test.java @@ -19,6 +19,7 @@ * Test class to validate behaviors associated with class aliases in the context of Wire. * This test extends the WireTestCommon for utility behaviors related to Wire tests. */ +@SuppressWarnings({"deprecation", "removal"}) public class Issue277Test extends WireTestCommon { /** diff --git a/src/test/java/net/openhft/chronicle/wire/issue/Issue609Test.java b/src/test/java/net/openhft/chronicle/wire/issue/Issue609Test.java index 933b470f25..dc36a39f15 100644 --- a/src/test/java/net/openhft/chronicle/wire/issue/Issue609Test.java +++ b/src/test/java/net/openhft/chronicle/wire/issue/Issue609Test.java @@ -3,7 +3,6 @@ */ package net.openhft.chronicle.wire.issue; -import net.openhft.chronicle.bytes.Bytes; import net.openhft.chronicle.bytes.BytesUtil; import net.openhft.chronicle.core.io.IORuntimeException; import net.openhft.chronicle.wire.*; @@ -19,6 +18,7 @@ /** * Test class extending `WireTestCommon` to verify the deserialization of `ChronicleServicesCfg` from YAML. */ +@SuppressWarnings({"deprecation", "removal"}) public class Issue609Test extends WireTestCommon { /** @@ -29,8 +29,8 @@ public class Issue609Test extends WireTestCommon { */ @Test public void testServices() throws IOException { - // Deserializes the ChronicleServicesCfg from a YAML file - ChronicleServicesCfg obj = WireType.YAML.fromString(ChronicleServicesCfg.class, BytesUtil.readFile("yaml/services.yaml")); + // Deserialises the ChronicleServicesCfg from a YAML file + final ChronicleServicesCfg obj = WireType.YAML.fromString(ChronicleServicesCfg.class, BytesUtil.readFile("yaml/services.yaml")); // Creates an expected configuration manually ChronicleServicesCfg expected = new ChronicleServicesCfg(); @@ -65,8 +65,7 @@ public void toYamlAndBackIssue824() { assertEquals(expected, WireType.YAML_ONLY.fromString(yaml)); - String withString = "" + - "!net.openhft.chronicle.wire.issue.Issue609Test$ChronicleServicesCfg {\n" + + String withString = "!net.openhft.chronicle.wire.issue.Issue609Test$ChronicleServicesCfg {\n" + " services: {\n" + " fix-web-gateway: { inputs: [ 'web-gateway-periodic-updates' ] }\n" + " }\n" + diff --git a/src/test/java/net/openhft/chronicle/wire/issue/Issue739Test.java b/src/test/java/net/openhft/chronicle/wire/issue/Issue739Test.java index 12db60b3fd..640a617a9d 100644 --- a/src/test/java/net/openhft/chronicle/wire/issue/Issue739Test.java +++ b/src/test/java/net/openhft/chronicle/wire/issue/Issue739Test.java @@ -19,7 +19,7 @@ public class Issue739Test extends WireTestCommon { static class One extends SelfDescribingMarshallable { - String text; + final String text; public One(String text) { this.text = text; @@ -27,7 +27,7 @@ public One(String text) { } static class Two extends SelfDescribingMarshallable { - String text; + final String text; public Two(String text) { this.text = text; diff --git a/src/test/java/net/openhft/chronicle/wire/issue/Issue751Test.java b/src/test/java/net/openhft/chronicle/wire/issue/Issue751Test.java index f9c6422b05..d43659c308 100644 --- a/src/test/java/net/openhft/chronicle/wire/issue/Issue751Test.java +++ b/src/test/java/net/openhft/chronicle/wire/issue/Issue751Test.java @@ -3,7 +3,6 @@ */ package net.openhft.chronicle.wire.issue; -import net.openhft.chronicle.bytes.Bytes; import net.openhft.chronicle.core.Jvm; import net.openhft.chronicle.wire.*; import org.jetbrains.annotations.NotNull; @@ -15,7 +14,7 @@ public class Issue751Test extends WireTestCommon { public static class One extends SelfDescribingMarshallable { - Comparable text; + final Comparable text; One(Comparable text) { this.text = text; @@ -23,7 +22,7 @@ public static class One extends SelfDescribingMarshallable { } public static class Two implements Comparable, Marshallable { - Comparable text; + final Comparable text; Two(Comparable text) { this.text = text; @@ -36,8 +35,8 @@ public int compareTo(@NotNull Issue751Test.Two o) { } static class Three extends SelfDescribingMarshallable { - One one; - Two two; + final One one; + final Two two; Three(One one, Two two) { this.one = one; diff --git a/src/test/java/net/openhft/chronicle/wire/issue/Issue844Test.java b/src/test/java/net/openhft/chronicle/wire/issue/Issue844Test.java index df71c052f7..5beeb53ad8 100644 --- a/src/test/java/net/openhft/chronicle/wire/issue/Issue844Test.java +++ b/src/test/java/net/openhft/chronicle/wire/issue/Issue844Test.java @@ -9,6 +9,7 @@ import static org.junit.Assert.assertEquals; +@SuppressWarnings({"deprecation", "removal"}) public class Issue844Test extends WireTestCommon { @Test diff --git a/src/test/java/net/openhft/chronicle/wire/issue/Issue886Test.java b/src/test/java/net/openhft/chronicle/wire/issue/Issue886Test.java index 6e87eff025..3603c54d36 100644 --- a/src/test/java/net/openhft/chronicle/wire/issue/Issue886Test.java +++ b/src/test/java/net/openhft/chronicle/wire/issue/Issue886Test.java @@ -33,7 +33,7 @@ public static Collection combinations() { } @Test - public void test() throws IOException { + public void test() { String data = "{\n" + " \"a\": 1.234,\n" + " \"a1\": '1.234'\n" + diff --git a/src/test/java/net/openhft/chronicle/wire/issue/JSON222IndividualTest.java b/src/test/java/net/openhft/chronicle/wire/issue/JSON222IndividualTest.java index 705e8778ef..6c17a772f5 100644 --- a/src/test/java/net/openhft/chronicle/wire/issue/JSON222IndividualTest.java +++ b/src/test/java/net/openhft/chronicle/wire/issue/JSON222IndividualTest.java @@ -15,6 +15,7 @@ import java.io.StringReader; import java.util.Arrays; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -46,7 +47,7 @@ public void testSpecial() { @Test public void nestedSeq() { @SuppressWarnings("rawtypes") - @NotNull List list = Arrays.asList(3L, Arrays.asList(4L)); + @NotNull List list = Arrays.asList(3L, Collections.singletonList(4L)); checkSerialized("[\n" + " 3,\n" + " [\n" + @@ -92,8 +93,6 @@ private void checkDeserialized(String expected, @NotNull String input) { try { @NotNull Yaml yaml = new Yaml(); Object o = yaml.load(new StringReader(input)); - // Debugging output commented out - // System.out.println(o); } catch (Exception e) { throw e; } diff --git a/src/test/java/net/openhft/chronicle/wire/issue/JSON222Test.java b/src/test/java/net/openhft/chronicle/wire/issue/JSON222Test.java index a7cc67a25d..ce60a490a6 100644 --- a/src/test/java/net/openhft/chronicle/wire/issue/JSON222Test.java +++ b/src/test/java/net/openhft/chronicle/wire/issue/JSON222Test.java @@ -19,11 +19,13 @@ import org.yaml.snakeyaml.Yaml; import java.io.*; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.List; +import static java.nio.charset.StandardCharsets.*; import static org.junit.Assert.assertEquals; @RunWith(value = Parameterized.class) @@ -57,6 +59,16 @@ public static Collection combinations() { return list; } + // Utility method to parse a string using the SnakeYaml library + private static void parseWithSnakeYaml(@NotNull String s) { + try { + @NotNull Yaml yaml = new Yaml(); + yaml.load(new StringReader(s)); + } catch (Exception e) { + throw e; + } + } + // Test the JSON content using TextWire type @Test public void testJSONAsTextWire() throws IOException { @@ -74,7 +86,7 @@ private void testJSON(WireType wireType) throws IOException { // Read the file content into a byte array int len = Maths.toUInt31(file.length()); @NotNull byte[] bytes = new byte[len]; - try (@NotNull InputStream in = new FileInputStream(file)) { + try (@NotNull InputStream in = Files.newInputStream(file.toPath())) { in.read(bytes); } // System.out.println(file + " " + new String(bytes, "UTF-8")); @@ -115,21 +127,13 @@ private void testJSON(WireType wireType) throws IOException { // If the test iteration is expected to fail, we check the expected output against a reference file @NotNull String path = file.getPath(); @NotNull final File file2 = new File(path.replaceAll("\\b._", "e-").replaceAll("\\.json", ".yaml")); - -/* - // System.out.println(file2 + "\n" + new String(bytes, "UTF-8") + "\n" + bytes2); - try (OutputStream out2 = new FileOutputStream(file2)) { - out2.write(bytes2.toByteArray()); - } -*/ - if (!file2.exists()) throw new AssertionError("Expected to fail\n" + bytes2); @NotNull byte[] bytes4 = new byte[(int) file2.length()]; - try (@NotNull InputStream in = new FileInputStream(file2)) { + try (@NotNull InputStream in = Files.newInputStream(file2.toPath())) { in.read(bytes4); } - String expected = new String(bytes4, "UTF-8"); + String expected = new String(bytes4, UTF_8); if (expected.contains("\r\n")) expected = expected.replaceAll("\r\n", "\n"); String actual = bytes2.toString(); @@ -146,14 +150,4 @@ private void testJSON(WireType wireType) throws IOException { bytes3.releaseLast(); } } - - // Utility method to parse a string using the SnakeYaml library - private static void parseWithSnakeYaml(@NotNull String s) { - try { - @NotNull Yaml yaml = new Yaml(); - yaml.load(new StringReader(s)); - } catch (Exception e) { - throw e; - } - } } diff --git a/src/test/java/net/openhft/chronicle/wire/issue/JSON322Test.java b/src/test/java/net/openhft/chronicle/wire/issue/JSON322Test.java index 5a019795c9..b46f5d4233 100644 --- a/src/test/java/net/openhft/chronicle/wire/issue/JSON322Test.java +++ b/src/test/java/net/openhft/chronicle/wire/issue/JSON322Test.java @@ -23,39 +23,6 @@ */ public class JSON322Test extends WireTestCommon { - static class One extends SelfDescribingMarshallable { - String text; - - One(String text) { - this.text = text; - } - } - - static class Two extends SelfDescribingMarshallable { - String text; - - Two(String text) { - this.text = text; - } - } - - static class Four extends Two { - String text; - - Four(String text) { - super(text); - this.text = text; - } - } - - static class Three extends SelfDescribingMarshallable { - private One one; - private Two two; - - Three() { - } - } - @Test public void supportNestedTypes() { assumeFalse(Jvm.maxDirectMemory() == 0); @@ -86,9 +53,6 @@ public void supportNestedTypes() { final Three parsedThree = (Three) parsed; -/* bytes.clear(); - wire.getValueOut().object(parsed);*/ - assertEquals(One.class, parsedThree.one.getClass()); assertEquals(Four.class, parsedThree.two.getClass()); assertEquals(three, parsed); @@ -112,8 +76,7 @@ public void supportTypes() { wire.getValueOut() .object(c); - assertEquals("" + - "{\"@Combined322\":{" + + assertEquals("{\"@Combined322\":{" + "\"t1\":{\"@TypeOne322\":{\"text\":\"one-one\"}}," + "\"t2\":{\"@TypeTwo322\":{\"id\":222,\"value\":2020}}," + "\"list\":[ {\"@TypeOne322\":{\"text\":\"one\"}},{\"@TypeTwo322\":{\"id\":2,\"value\":22}} ]}}", @@ -128,7 +91,7 @@ public void supportTypes() { assertNotNull(parsed); assertEquals(Combined322.class, parsed.getClass()); - final Combined322 combined322 = (Combined322)parsed; + final Combined322 combined322 = (Combined322) parsed; assertEquals(TypeOne322.class, combined322.t1.getClass()); assertEquals(TypeTwo322.class, combined322.t2.getClass()); @@ -140,6 +103,39 @@ public void supportTypes() { assertEquals(c, combined322); } + static class One extends SelfDescribingMarshallable { + final String text; + + One(String text) { + this.text = text; + } + } + + static class Two extends SelfDescribingMarshallable { + final String text; + + Two(String text) { + this.text = text; + } + } + + static class Four extends Two { + final String text; + + Four(String text) { + super(text); + this.text = text; + } + } + + static class Three extends SelfDescribingMarshallable { + private One one; + private Two two; + + Three() { + } + } + static class Combined322 extends SelfDescribingMarshallable { TypeOne322 t1; TypeTwo322 t2; @@ -147,7 +143,7 @@ static class Combined322 extends SelfDescribingMarshallable { } static class TypeOne322 extends SelfDescribingMarshallable { - String text; + final String text; TypeOne322(String one) { text = one; @@ -155,8 +151,8 @@ static class TypeOne322 extends SelfDescribingMarshallable { } static class TypeTwo322 extends SelfDescribingMarshallable { - int id; - long value; + final int id; + final long value; TypeTwo322(int id, long value) { this.id = id; diff --git a/src/test/java/net/openhft/chronicle/wire/issue/WireBug35Test.java b/src/test/java/net/openhft/chronicle/wire/issue/WireBug35Test.java index 9c81b749ed..275e3a777f 100644 --- a/src/test/java/net/openhft/chronicle/wire/issue/WireBug35Test.java +++ b/src/test/java/net/openhft/chronicle/wire/issue/WireBug35Test.java @@ -17,6 +17,7 @@ /** * @author ryanlea */ +@SuppressWarnings({"deprecation", "removal"}) public class WireBug35Test extends WireTestCommon { @Test diff --git a/src/test/java/net/openhft/chronicle/wire/issue/WireBug37Test.java b/src/test/java/net/openhft/chronicle/wire/issue/WireBug37Test.java index e032b3aee9..64591528c6 100644 --- a/src/test/java/net/openhft/chronicle/wire/issue/WireBug37Test.java +++ b/src/test/java/net/openhft/chronicle/wire/issue/WireBug37Test.java @@ -49,7 +49,6 @@ public void testNewlineInString() { // Convert the bytes back to string final String output = bytes.toString(); - // System.out.println("output: [" + output + "]"); // Deserialize the string back into obj3 and ensure it matches obj2 obj3.readMarshallable(wireType.apply(Bytes.from(output))); @@ -99,7 +98,7 @@ public boolean equals(@Nullable Object o) { @Nullable MarshallableObj that = (MarshallableObj) o; - return builder.toString().equals(that.builder.toString()); + return builder.toString().contentEquals(that.builder); } // Hashcode derived from the content of the builder diff --git a/src/test/java/net/openhft/chronicle/wire/issue/WireBug38Test.java b/src/test/java/net/openhft/chronicle/wire/issue/WireBug38Test.java index e324ce8b40..966656ba84 100644 --- a/src/test/java/net/openhft/chronicle/wire/issue/WireBug38Test.java +++ b/src/test/java/net/openhft/chronicle/wire/issue/WireBug38Test.java @@ -49,7 +49,6 @@ public void testNestedObj() { // Convert the bytes back to string final String output = bytes.toString(); - // System.out.println("output: [" + output + "]"); // Deserialize the string back into obj2 and ensure it matches obj1 obj2.readMarshallable(wireType.apply(Bytes.from(output))); @@ -94,7 +93,7 @@ public boolean equals(@Nullable Object o) { @Nullable MarshallableObj that = (MarshallableObj) o; - return builder.toString().equals(that.builder.toString()); + return builder.toString().contentEquals(that.builder); } @Override diff --git a/src/test/java/net/openhft/chronicle/wire/issue/WireBug39Test.java b/src/test/java/net/openhft/chronicle/wire/issue/WireBug39Test.java index 68506eb4bd..02bd1e3298 100644 --- a/src/test/java/net/openhft/chronicle/wire/issue/WireBug39Test.java +++ b/src/test/java/net/openhft/chronicle/wire/issue/WireBug39Test.java @@ -54,7 +54,6 @@ public void testBinaryEncoding() { // Convert the bytes back to string final String output = bytes.toString(); - // System.out.println("output: [" + output + "]"); // Deserialize the string back into obj3 and ensure it matches obj1 and obj2 obj3.readMarshallable(wireType.apply(Bytes.from(output))); @@ -70,7 +69,7 @@ public void testBinaryEncoding() { * The object mainly manages a StringBuilder data and provides * mechanisms to handle serialization and deserialization using Wire. */ - class MarshallableObj implements Marshallable { + static class MarshallableObj implements Marshallable { private final StringBuilder builder = new StringBuilder(); public void clear() { @@ -99,7 +98,7 @@ public boolean equals(@Nullable Object o) { @NotNull MarshallableObj that = (MarshallableObj) o; - return builder.toString().equals(that.builder.toString()); + return builder.toString().contentEquals(that.builder); } @Override diff --git a/src/test/java/net/openhft/chronicle/wire/java17/Group.java b/src/test/java/net/openhft/chronicle/wire/java17/Group.java index 0be2621291..f3a5ba1d67 100644 --- a/src/test/java/net/openhft/chronicle/wire/java17/Group.java +++ b/src/test/java/net/openhft/chronicle/wire/java17/Group.java @@ -3,6 +3,7 @@ */ package net.openhft.chronicle.wire.java17; +import net.openhft.chronicle.core.annotation.UsedViaReflection; import net.openhft.chronicle.wire.SelfDescribingMarshallable; /** @@ -11,7 +12,7 @@ * self-describing marshalling and unmarshalling. */ class Group extends SelfDescribingMarshallable { - + @UsedViaReflection // The field associated with this group private Field field; diff --git a/src/test/java/net/openhft/chronicle/wire/map/MapCustomTest.java b/src/test/java/net/openhft/chronicle/wire/map/MapCustomTest.java index 0ff037da3b..e8d382d02d 100644 --- a/src/test/java/net/openhft/chronicle/wire/map/MapCustomTest.java +++ b/src/test/java/net/openhft/chronicle/wire/map/MapCustomTest.java @@ -13,7 +13,7 @@ import java.util.*; import java.util.function.Function; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; /** * Test suite for custom map implementations and their serialization. @@ -35,7 +35,14 @@ public void test() { MapsHolder result = Wires.deepCopy(mapsHolder); // Assert that the copied object is equivalent to the original - assertTrue(result.equals(mapsHolder)); + assertEquals(result, mapsHolder); + } + + /** + * Marked map interface that extends Map and Closeable. + */ + interface MarkedMap extends Map, Closeable { + // No-op. } /** @@ -45,11 +52,11 @@ public void test() { @SuppressWarnings("rawtypes") static class MapsHolder extends SelfDescribingMarshallable { // Define custom maps and their instances - IntToStringMap i2sMap = new IntToStringMap(); - IntMap iMap = new IntMap<>(); - IntSuperMap isMap = new IntSuperMap<>(); - TransformingMap transMap = new TransformingMap<>(BigDecimal::new); - GeneralMap gMap = new GeneralMap(); + final IntToStringMap i2sMap = new IntToStringMap(); + final IntMap iMap = new IntMap<>(); + final IntSuperMap isMap = new IntSuperMap<>(); + final TransformingMap transMap = new TransformingMap<>(BigDecimal::new); + final GeneralMap gMap = new GeneralMap(); // ClassCastException: net.openhft.chronicle.core.util.ObjectUtils$$Lambda$73/1401132667 cannot be cast to Map // private MarkedMap mMap = i2sMap; @@ -94,14 +101,14 @@ public void close() { /** * Custom HashMap that contains an additional generic field. */ - public static class IntMap extends HashMap { - public IGNORE me; + public static class IntMap extends HashMap { + public I me; } /** * Extended version of IntMap. */ - public static class IntSuperMap extends IntMap, SUPER> { + public static class IntSuperMap extends IntMap, S> { // No-op. } @@ -109,7 +116,7 @@ public static class IntSuperMap extends IntMap extends LinkedHashMap { - Function transform; + final Function transform; // Constructor to set the transformation function TransformingMap(Function transform) { @@ -134,11 +141,4 @@ public O getTransformed(K key) { public static class GeneralMap extends IntMap { // No-op. } - - /** - * Marked map interface that extends Map and Closeable. - */ - interface MarkedMap extends Map, Closeable { - // No-op. - } } diff --git a/src/test/java/net/openhft/chronicle/wire/marshallable/AClass.java b/src/test/java/net/openhft/chronicle/wire/marshallable/AClass.java index 66dde2ebb9..f62deac008 100644 --- a/src/test/java/net/openhft/chronicle/wire/marshallable/AClass.java +++ b/src/test/java/net/openhft/chronicle/wire/marshallable/AClass.java @@ -9,6 +9,7 @@ import org.jetbrains.annotations.NotNull; // AClass extends the functionality of SelfDescribingMarshallable, providing custom serialization and deserialization for its fields. +@SuppressWarnings({"deprecation", "removal"}) class AClass extends SelfDescribingMarshallable { // Member variables int id; diff --git a/src/test/java/net/openhft/chronicle/wire/marshallable/B2Class.java b/src/test/java/net/openhft/chronicle/wire/marshallable/B2Class.java index 4f203d330e..992e987a51 100644 --- a/src/test/java/net/openhft/chronicle/wire/marshallable/B2Class.java +++ b/src/test/java/net/openhft/chronicle/wire/marshallable/B2Class.java @@ -29,8 +29,7 @@ public void writeMarshallable(BytesOut out) { public void readMarshallable(BytesIn in) { super.readMarshallable(in); int version = (int) in.readStopBit(); - if (version == MASHALLABLE_VERSION) { - } else { + if (version != MASHALLABLE_VERSION) { throw new IllegalStateException("Unknown version " + version); } } diff --git a/src/test/java/net/openhft/chronicle/wire/marshallable/ByteBufferMarshallingTest.java b/src/test/java/net/openhft/chronicle/wire/marshallable/ByteBufferMarshallingTest.java index bc03c99dfa..70e0c3e065 100644 --- a/src/test/java/net/openhft/chronicle/wire/marshallable/ByteBufferMarshallingTest.java +++ b/src/test/java/net/openhft/chronicle/wire/marshallable/ByteBufferMarshallingTest.java @@ -4,6 +4,7 @@ package net.openhft.chronicle.wire.marshallable; import net.openhft.chronicle.bytes.Bytes; +import net.openhft.chronicle.bytes.BytesUtil; import net.openhft.chronicle.core.Jvm; import net.openhft.chronicle.core.util.ObjectUtils; import net.openhft.chronicle.wire.RawWire; diff --git a/src/test/java/net/openhft/chronicle/wire/marshallable/CompareNaNTest.java b/src/test/java/net/openhft/chronicle/wire/marshallable/CompareNaNTest.java index 59ee47dbb2..70b42f0758 100644 --- a/src/test/java/net/openhft/chronicle/wire/marshallable/CompareNaNTest.java +++ b/src/test/java/net/openhft/chronicle/wire/marshallable/CompareNaNTest.java @@ -62,8 +62,8 @@ public void testObjectWrapDTO() { * A Data Transfer Object (DTO) representing primitive data types. */ static class PrimDTO extends SelfDescribingMarshallable { - double d; - float f; + final double d; + final float f; PrimDTO(double d, float f) { this.d = d; @@ -75,8 +75,8 @@ static class PrimDTO extends SelfDescribingMarshallable { * A Data Transfer Object (DTO) representing wrapped data types (e.g., Double, Float). */ static class WrapDTO extends SelfDescribingMarshallable { - Double d; - Float f; + final Double d; + final Float f; WrapDTO(Double d, Float f) { this.d = d; @@ -89,8 +89,8 @@ static class WrapDTO extends SelfDescribingMarshallable { * It can hold various object types, including Double and Float wrappers. */ static class ObjectWrapDTO extends SelfDescribingMarshallable { - Object d; - Object f; + final Object d; + final Object f; ObjectWrapDTO(Object d, Object f) { this.d = d; diff --git a/src/test/java/net/openhft/chronicle/wire/marshallable/EnumWireTest.java b/src/test/java/net/openhft/chronicle/wire/marshallable/EnumWireTest.java index 053bf4398e..046444906e 100644 --- a/src/test/java/net/openhft/chronicle/wire/marshallable/EnumWireTest.java +++ b/src/test/java/net/openhft/chronicle/wire/marshallable/EnumWireTest.java @@ -111,18 +111,18 @@ public MarshAndResolve readResolve() { // DTO with a field of type Marsh. static class Person1 extends SelfDescribingMarshallable { @NotNull - private Marsh field = Marsh.MARSH; + private final Marsh field = Marsh.MARSH; } // DTO with a field of type NoMarsh. static class Person2 extends SelfDescribingMarshallable { @NotNull - private NoMarsh field = NoMarsh.NO_MARSH; + private final NoMarsh field = NoMarsh.NO_MARSH; } // DTO with a field of type MarshAndResolve. static class Person3 extends SelfDescribingMarshallable { @NotNull - private MarshAndResolve field = MarshAndResolve.MARSH_AND_RESOLVE; + private final MarshAndResolve field = MarshAndResolve.MARSH_AND_RESOLVE; } } diff --git a/src/test/java/net/openhft/chronicle/wire/marshallable/JSONWithAMapTest.java b/src/test/java/net/openhft/chronicle/wire/marshallable/JSONWithAMapTest.java index ac9ac09455..8a9ad01343 100644 --- a/src/test/java/net/openhft/chronicle/wire/marshallable/JSONWithAMapTest.java +++ b/src/test/java/net/openhft/chronicle/wire/marshallable/JSONWithAMapTest.java @@ -9,7 +9,6 @@ import net.openhft.chronicle.wire.SelfDescribingMarshallable; import net.openhft.chronicle.wire.Wire; import net.openhft.chronicle.wire.WireType; -import org.jetbrains.annotations.NotNull; import org.junit.Assert; import org.junit.Test; @@ -91,14 +90,14 @@ private void doTest(String expected, String input) { } // check the number of '{' match the number of '}' - Assert.assertTrue("openBracket=" + openBracket + ",closeBracket=" + closeBracket, openBracket == closeBracket); + Assert.assertEquals("openBracket=" + openBracket + ",closeBracket=" + closeBracket, openBracket, closeBracket); // DON'T CHANGE THE EXPECTED JSON IT IS CORRECT ! - please use this website to validate the json - https://jsonformatter.org Assert.assertEquals(expected, actual); } private static class ResponseItem extends SelfDescribingMarshallable { - public @NotNull String index; + public String index; public Bytes key = Bytes.allocateElasticOnHeap(); public Object payload; } diff --git a/src/test/java/net/openhft/chronicle/wire/marshallable/MarshallableWithOverwriteFalseTest.java b/src/test/java/net/openhft/chronicle/wire/marshallable/MarshallableWithOverwriteFalseTest.java index 23d5869777..2704bb7ed4 100644 --- a/src/test/java/net/openhft/chronicle/wire/marshallable/MarshallableWithOverwriteFalseTest.java +++ b/src/test/java/net/openhft/chronicle/wire/marshallable/MarshallableWithOverwriteFalseTest.java @@ -45,7 +45,7 @@ public void test() { // Deserialize the string representation back to a MyDto2 object // System.out.println(cs); - MyDto2 o = (MyDto2) Marshallable.fromString(cs); + MyDto2 o = Marshallable.fromString(cs); // Verify the size of the strings list in the deserialized object assertEquals(2, o.myDto.get("").strings.size()); @@ -56,10 +56,11 @@ public void test() { */ static class MyDto extends SelfDescribingMarshallable { // List to store string values - List strings = new ArrayList<>(); + final List strings = new ArrayList<>(); /** * Reads the data from the provided WireIn object to populate this DTO. + * * @param wire WireIn instance containing serialized data * @throws IORuntimeException If an IO error occurs during reading */ @@ -68,9 +69,6 @@ public void readMarshallable(@NotNull WireIn wire) throws IORuntimeException { // The following line works, but is commented out for this test // Wires.readMarshallable(this, wire, true); - // WORKS - // Wires.readMarshallable(this, wire, true); // WORKS - // FAILS Wires.readMarshallable(this, wire, false); } @@ -81,6 +79,6 @@ public void readMarshallable(@NotNull WireIn wire) throws IORuntimeException { */ static class MyDto2 extends SelfDescribingMarshallable { // Map to store MyDto instances with String keys - Map myDto = new TreeMap(); + final Map myDto = new TreeMap(); } } diff --git a/src/test/java/net/openhft/chronicle/wire/marshallable/MarshallingJSONStringTest.java b/src/test/java/net/openhft/chronicle/wire/marshallable/MarshallingJSONStringTest.java index 98f664f0f6..e7100c9506 100644 --- a/src/test/java/net/openhft/chronicle/wire/marshallable/MarshallingJSONStringTest.java +++ b/src/test/java/net/openhft/chronicle/wire/marshallable/MarshallingJSONStringTest.java @@ -12,7 +12,6 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; public class MarshallingJSONStringTest implements Marshallable { diff --git a/src/test/java/net/openhft/chronicle/wire/marshallable/ScalarValues.java b/src/test/java/net/openhft/chronicle/wire/marshallable/ScalarValues.java index ca06b7b296..6b3f0bc401 100644 --- a/src/test/java/net/openhft/chronicle/wire/marshallable/ScalarValues.java +++ b/src/test/java/net/openhft/chronicle/wire/marshallable/ScalarValues.java @@ -45,7 +45,7 @@ public class ScalarValues extends SelfDescribingMarshallable { private File file; private TestEnum dynamicEnum; - // Path path; + // Path path; public ScalarValues() { } diff --git a/src/test/java/net/openhft/chronicle/wire/marshallable/TriviallyCopyableMarketData.java b/src/test/java/net/openhft/chronicle/wire/marshallable/TriviallyCopyableMarketData.java index 11e690bc39..c8395a9415 100644 --- a/src/test/java/net/openhft/chronicle/wire/marshallable/TriviallyCopyableMarketData.java +++ b/src/test/java/net/openhft/chronicle/wire/marshallable/TriviallyCopyableMarketData.java @@ -7,6 +7,7 @@ import net.openhft.chronicle.bytes.BytesOut; import net.openhft.chronicle.bytes.BytesUtil; import net.openhft.chronicle.bytes.util.BinaryLengthLength; +import net.openhft.chronicle.core.annotation.UsedViaReflection; import net.openhft.chronicle.wire.Base85LongConverter; import net.openhft.chronicle.wire.BytesInBinaryMarshallable; import net.openhft.chronicle.wire.LongConversion; @@ -22,9 +23,9 @@ public class TriviallyCopyableMarketData extends BytesInBinaryMarshallable { private static final int LENGTH = START_END[1] - START_END[0]; // Unique identifier for the security, encoded in Base85 format for compactness + @UsedViaReflection @LongConversion(Base85LongConverter.class) - private - long securityId; + private long securityId; // Timestamp of the market data, encoded to represent microsecond precision @LongConversion(MicroTimestampLongConverter.class) diff --git a/src/test/java/net/openhft/chronicle/wire/marshallable/UnknownDatatimeTest.java b/src/test/java/net/openhft/chronicle/wire/marshallable/UnknownDatatimeTest.java index 0ca0f72a4e..336253aa80 100644 --- a/src/test/java/net/openhft/chronicle/wire/marshallable/UnknownDatatimeTest.java +++ b/src/test/java/net/openhft/chronicle/wire/marshallable/UnknownDatatimeTest.java @@ -22,7 +22,7 @@ public class UnknownDatatimeTest extends WireTestCommon { * Tests if an unknown datetime can be ignored during deserialization. */ @Test - public void ignoreAnUnknownDateTime() throws IOException { + public void ignoreAnUnknownDateTime() { // Deserialize an instance of AClass from a string. // The string contains a datetime field 'eventTime' which is not expected to exist in AClass. AClass aClass = Marshallable.fromString("!" + AClass.class.getName() + " { eventTime: 2019-04-02T11:20:41.616653, id: 123456 }"); diff --git a/src/test/java/net/openhft/chronicle/wire/method/BrokenChainTest.java b/src/test/java/net/openhft/chronicle/wire/method/BrokenChainTest.java index c9bcfe7f60..fb8a3a1232 100644 --- a/src/test/java/net/openhft/chronicle/wire/method/BrokenChainTest.java +++ b/src/test/java/net/openhft/chronicle/wire/method/BrokenChainTest.java @@ -16,14 +16,6 @@ import static org.junit.Assert.*; public class BrokenChainTest extends WireTestCommon { - interface First { - Second pre(String pre); - } - - interface Second { - void msg(String msg); - } - @Test public void brokenChainYaml() { doBrokenChain(WireType.YAML_ONLY); @@ -83,4 +75,12 @@ private void doBrokenChain(WireType wireType) { assertFalse(reader.readOne()); assertEquals("[pre: pre-C, msg: msg-C]", list.toString()); } + + interface First { + Second pre(String pre); + } + + interface Second { + void msg(String msg); + } } diff --git a/src/test/java/net/openhft/chronicle/wire/method/ChronicleEvent.java b/src/test/java/net/openhft/chronicle/wire/method/ChronicleEvent.java index 54ff9e5c71..40c3136292 100644 --- a/src/test/java/net/openhft/chronicle/wire/method/ChronicleEvent.java +++ b/src/test/java/net/openhft/chronicle/wire/method/ChronicleEvent.java @@ -33,6 +33,7 @@ public class ChronicleEvent extends BytesInBinaryMarshallable implements Event { /** * Sets the sending time for the event. + * * @param sendingTimeNS The time the event was sent, in nanoseconds. */ @Override @@ -42,6 +43,7 @@ public void sendingTimeNS(long sendingTimeNS) { /** * Retrieves the sending time for the event. + * * @return The time the event was sent, in nanoseconds. */ @Override @@ -51,6 +53,7 @@ public long sendingTimeNS() { /** * Sets the transaction time for the event. + * * @param transactTimeNS The time the event was processed or transacted, in nanoseconds. */ @Override @@ -60,6 +63,7 @@ public void transactTimeNS(long transactTimeNS) { /** * Retrieves the transaction time for the event. + * * @return The time the event was processed or transacted, in nanoseconds. */ @Override diff --git a/src/test/java/net/openhft/chronicle/wire/method/ChronicleEventHandler.java b/src/test/java/net/openhft/chronicle/wire/method/ChronicleEventHandler.java index c4331377c1..cfb942ae0e 100644 --- a/src/test/java/net/openhft/chronicle/wire/method/ChronicleEventHandler.java +++ b/src/test/java/net/openhft/chronicle/wire/method/ChronicleEventHandler.java @@ -12,6 +12,7 @@ public interface ChronicleEventHandler extends EventHandler { /** * Handles the provided ChronicleEvent. + * * @param event The ChronicleEvent instance to be handled. */ @Override diff --git a/src/test/java/net/openhft/chronicle/wire/method/ClusterCommand.java b/src/test/java/net/openhft/chronicle/wire/method/ClusterCommand.java index b955ee45eb..a83dc85e6e 100644 --- a/src/test/java/net/openhft/chronicle/wire/method/ClusterCommand.java +++ b/src/test/java/net/openhft/chronicle/wire/method/ClusterCommand.java @@ -12,15 +12,13 @@ */ public class ClusterCommand extends SelfDescribingMarshallable { + // The service ID in bytes format, initialized as an elastic byte buffer + private final Bytes serviceId = Bytes.allocateElasticOnHeap(); // Represents the cycle associated with the command private long cycle; - // The Service instance associated with the command private Service service; - // The service ID in bytes format, initialized as an elastic byte buffer - private final Bytes serviceId = Bytes.allocateElasticOnHeap(); - /** * Constructs a ClusterCommand with the given cycle and Service. * @@ -37,13 +35,12 @@ public ClusterCommand(long cycle, Service service) { /** * Constructs a ClusterCommand with the given cycle and service ID. * - * @param cycle The cycle for the command. - * @param serviceId The service ID in CharSequence format. + * @param cycle The cycle for the command. + * @param serviceId The service ID in CharSequence format. */ public ClusterCommand(long cycle, CharSequence serviceId) { this.cycle = cycle; this.serviceId.clear().append(serviceId); - // setUniqueTimeStampNow(); } /** diff --git a/src/test/java/net/openhft/chronicle/wire/method/Event.java b/src/test/java/net/openhft/chronicle/wire/method/Event.java index 6ec71ae567..9e05e4aa10 100644 --- a/src/test/java/net/openhft/chronicle/wire/method/Event.java +++ b/src/test/java/net/openhft/chronicle/wire/method/Event.java @@ -12,24 +12,28 @@ public interface Event { /** * Sets the sending time for the event. + * * @param sendingTimeNS The sending time in nanoseconds. */ void sendingTimeNS(long sendingTimeNS); /** * Retrieves the sending time of the event. + * * @return The sending time in nanoseconds. */ long sendingTimeNS(); /** * Sets the transaction time for the event. + * * @param transactTimeNS The transaction time in nanoseconds. */ void transactTimeNS(long transactTimeNS); /** * Retrieves the transaction time of the event. + * * @return The transaction time in nanoseconds. */ long transactTimeNS(); diff --git a/src/test/java/net/openhft/chronicle/wire/method/HandleSkippedValueReadsTest.java b/src/test/java/net/openhft/chronicle/wire/method/HandleSkippedValueReadsTest.java index a8dd06dc5c..3837a5c96e 100644 --- a/src/test/java/net/openhft/chronicle/wire/method/HandleSkippedValueReadsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/method/HandleSkippedValueReadsTest.java @@ -37,11 +37,14 @@ public static Collection data() { return Arrays.asList( new Object[]{WireType.BINARY_LIGHT}, new Object[]{WireType.TEXT} - // TODO FIX -// new Object[]{WireType.YAML_ONLY} ); } + @NotNull + private static String asString(StringWriter sw) { + return sw.toString().replace("\r", ""); + } + @Test public void test() { doTest(false); @@ -158,11 +161,6 @@ private void doTest(boolean scanning) { assertFalse(reader.readOne()); } - @NotNull - private static String asString(StringWriter sw) { - return sw.toString().replace("\r", ""); - } - @Test public void index2index() { doIndex2index(false); @@ -198,18 +196,16 @@ private void doIndex2index(boolean scanning) { if (!scanning) { // one - assertEquals("M meta[one]\n" - , asString(sw)); + assertEquals("M meta[one]\n", asString(sw)); assertTrue(reader.readOne()); // i2i - assertEquals("M meta[one]\n" - , asString(sw)); + assertEquals("M meta[one]\n", asString(sw)); assertTrue(reader.readOne()); } // data six assertEquals("M meta[one]\n" + - "D data[six]\n" - , asString(sw)); + "D data[six]\n", + asString(sw)); assertFalse(reader.readOne()); } diff --git a/src/test/java/net/openhft/chronicle/wire/method/MarshallableMethodReaderTest.java b/src/test/java/net/openhft/chronicle/wire/method/MarshallableMethodReaderTest.java index 5cecce18b0..913b587b10 100644 --- a/src/test/java/net/openhft/chronicle/wire/method/MarshallableMethodReaderTest.java +++ b/src/test/java/net/openhft/chronicle/wire/method/MarshallableMethodReaderTest.java @@ -99,7 +99,7 @@ interface Saying { // Implementation of the Saying interface, stores said strings static class SayingMicroservice extends SelfDescribingMarshallable implements Saying { - transient List said = new ArrayList<>(); + final transient List said = new ArrayList<>(); @Override public void say(String hi) { diff --git a/src/test/java/net/openhft/chronicle/wire/method/MethodIdTest.java b/src/test/java/net/openhft/chronicle/wire/method/MethodIdTest.java index 384a8e9387..c36bbd6d35 100644 --- a/src/test/java/net/openhft/chronicle/wire/method/MethodIdTest.java +++ b/src/test/java/net/openhft/chronicle/wire/method/MethodIdTest.java @@ -40,8 +40,7 @@ public void methodIdInBinary() { // methods.methodLongMin(Long.MIN_VALUE); // Not supported yet // Asserts the binary representation of the method calls - assertEquals("" + - "04 00 00 00 # msg-length\n" + + assertEquals("04 00 00 00 # msg-length\n" + "ba 40 # methodAt ('@')\n" + "e1 40 # @\n" + "04 00 00 00 # msg-length\n" + @@ -76,8 +75,7 @@ public void methodIdInBinary() { // Read each method call and verify the output for (int i = 0; i < 8; i++) reader.readOne(); - assertEquals("" + - "methodAt: \"@\"\n" + + assertEquals("methodAt: \"@\"\n" + "...\n" + "method_z: z\n" + "...\n" + @@ -99,12 +97,9 @@ public void methodIdInBinary() { // Interface defining various methods with specific method IDs using annotations interface Methods { -// not supported yet -// @MethodId(Long.MIN_VALUE) -// void methodLongMin(long a); - @MethodId('@') void methodAt(char at); + @MethodId('z') void method_z(char z); @@ -117,10 +112,6 @@ interface Methods { @MethodId(Byte.MIN_VALUE) void methodByteMin(long a); -// not supported yet -// @MethodId(Long.MAX_VALUE) -// void methodLongMax(long a); - @MethodId(Integer.MAX_VALUE) void methodIntMax(long a); diff --git a/src/test/java/net/openhft/chronicle/wire/method/MethodReaderWithHistoryTest.java b/src/test/java/net/openhft/chronicle/wire/method/MethodReaderWithHistoryTest.java index 97a4387674..6d5c930ca9 100644 --- a/src/test/java/net/openhft/chronicle/wire/method/MethodReaderWithHistoryTest.java +++ b/src/test/java/net/openhft/chronicle/wire/method/MethodReaderWithHistoryTest.java @@ -56,8 +56,6 @@ private void doTest(WireType wireType) { history.addSource(2, 22); historySays.history(history).say("bye"); -// System.out.println(wire); - String[] says = {null}; MethodReader reader = wire.methodReader((RecordHistorySays) h -> { assertEquals(1, h.sourceId(0)); diff --git a/src/test/java/net/openhft/chronicle/wire/method/MethodWriter2Test.java b/src/test/java/net/openhft/chronicle/wire/method/MethodWriter2Test.java index e974581835..9aa87e4b03 100644 --- a/src/test/java/net/openhft/chronicle/wire/method/MethodWriter2Test.java +++ b/src/test/java/net/openhft/chronicle/wire/method/MethodWriter2Test.java @@ -21,14 +21,9 @@ import static org.junit.Assert.*; // Test class for verifying the behavior of a method writer with different argument types and update interceptor +// run with -DdumpCode to see the generated code public class MethodWriter2Test extends WireTestCommon { - // Static block - can be used for setting properties like code dumping - static { - // Uncomment to enable dumping of generated code - // System.setProperty("dumpCode", "true"); - } - // Test to verify that method calls with DTO arguments are allowed through @Test public void allowThrough() { diff --git a/src/test/java/net/openhft/chronicle/wire/method/MethodWriterByInterfaceTest.java b/src/test/java/net/openhft/chronicle/wire/method/MethodWriterByInterfaceTest.java index 2716b51248..5c22e78ce6 100644 --- a/src/test/java/net/openhft/chronicle/wire/method/MethodWriterByInterfaceTest.java +++ b/src/test/java/net/openhft/chronicle/wire/method/MethodWriterByInterfaceTest.java @@ -18,6 +18,7 @@ import static org.junit.Assert.*; // Test class extending WireTestCommon to test method writing and reading via interface implementations +@SuppressWarnings({"deprecation", "removal"}) public class MethodWriterByInterfaceTest extends WireTestCommon { // Setup method to configure default object creation for interfaces before each test @@ -105,8 +106,9 @@ interface MWBI0 { // Implementation of MWBI with name and time fields static class MWBImpl extends SelfDescribingMarshallable implements MWBI { - String name; + final String name; @LongConversion(MicroTimestampLongConverter.class) + final long time; // Constructor to initialize name and time diff --git a/src/test/java/net/openhft/chronicle/wire/method/SkipsIgnoresEveryThingTest.java b/src/test/java/net/openhft/chronicle/wire/method/SkipsIgnoresEveryThingTest.java index f3a34e7f37..071d19224d 100644 --- a/src/test/java/net/openhft/chronicle/wire/method/SkipsIgnoresEveryThingTest.java +++ b/src/test/java/net/openhft/chronicle/wire/method/SkipsIgnoresEveryThingTest.java @@ -48,7 +48,7 @@ public void selective() { // Create a method reader that routes messages to different handlers based on the ID final MethodReader reader = wire.methodReader(new Selective() { - DontSayBad dsb = new DontSayBad(); + final DontSayBad dsb = new DontSayBad(); @Override public Saying to(long id) { diff --git a/src/test/java/net/openhft/chronicle/wire/method/VanillaMethodReaderHierarchyTest.java b/src/test/java/net/openhft/chronicle/wire/method/VanillaMethodReaderHierarchyTest.java index d2cd593ef5..290f8ff4af 100644 --- a/src/test/java/net/openhft/chronicle/wire/method/VanillaMethodReaderHierarchyTest.java +++ b/src/test/java/net/openhft/chronicle/wire/method/VanillaMethodReaderHierarchyTest.java @@ -22,7 +22,7 @@ * with different levels of class/interface hierarchy in Chronicle Wire. */ public class VanillaMethodReaderHierarchyTest extends WireTestCommon { - private BlockingQueue queue = new ArrayBlockingQueue<>(10); + private final BlockingQueue queue = new ArrayBlockingQueue<>(10); /** * Tests method writing and reading using a simple interface implementation. @@ -82,6 +82,7 @@ public void testDuckTyping() { /** * Helper method to check the method writing and reading functionality. + * * @param simple An implementation of the Simple interface. */ private void checkWriteRead(Simple simple) throws InvalidMarshallableException { @@ -122,9 +123,11 @@ interface SimpleDescendant extends Simple { */ private static class SimpleDescendantClass implements SimpleDescendant { private final BlockingQueue queue; + SimpleDescendantClass(BlockingQueue queue) { this.queue = queue; } + @Override public void hello(String name) { queue.add(name); @@ -134,7 +137,7 @@ public void hello(String name) { /** * Abstract class implementing SimpleDescendant. */ - private static abstract class SimpleAbstractDescendantClass implements SimpleDescendant { + private abstract static class SimpleAbstractDescendantClass implements SimpleDescendant { } /** @@ -142,9 +145,11 @@ private static abstract class SimpleAbstractDescendantClass implements SimpleDes */ private static class SimpleDescendantClass2 extends SimpleAbstractDescendantClass { private final BlockingQueue queue; + SimpleDescendantClass2(BlockingQueue queue) { this.queue = queue; } + @Override public void hello(String name) { queue.add(name); diff --git a/src/test/java/net/openhft/chronicle/wire/method/VanillaMethodReaderTest.java b/src/test/java/net/openhft/chronicle/wire/method/VanillaMethodReaderTest.java index 3e46667c29..89d86f40dd 100644 --- a/src/test/java/net/openhft/chronicle/wire/method/VanillaMethodReaderTest.java +++ b/src/test/java/net/openhft/chronicle/wire/method/VanillaMethodReaderTest.java @@ -29,6 +29,11 @@ public class VanillaMethodReaderTest extends WireTestCommon { private A instance; + @NotNull + private static String asString(StringWriter out) { + return out.toString().replace("\r", ""); + } + @Test public void testMethodReaderWriterMetadata() { assumeFalse(Jvm.maxDirectMemory() == 0); @@ -424,11 +429,6 @@ private void doParseMetaData(boolean scanning) { wire.bytes().releaseLast(); } - @NotNull - private static String asString(StringWriter out) { - return out.toString().replace("\r", ""); - } - private void checkReaderType(MethodReader reader) { assertFalse(Proxy.isProxyClass(reader.getClass())); } diff --git a/src/test/java/net/openhft/chronicle/wire/method/YamlTextWireTest.java b/src/test/java/net/openhft/chronicle/wire/method/YamlTextWireTest.java index 8d45602c7f..cca02dc368 100644 --- a/src/test/java/net/openhft/chronicle/wire/method/YamlTextWireTest.java +++ b/src/test/java/net/openhft/chronicle/wire/method/YamlTextWireTest.java @@ -25,6 +25,7 @@ * between YamlWire and TextWire in processing YAML formatted text. */ @RunWith(value = Parameterized.class) +@SuppressWarnings({"deprecation", "removal"}) public class YamlTextWireTest extends WireTestCommon { // Static block to register class alias for Fields @@ -32,7 +33,6 @@ public class YamlTextWireTest extends WireTestCommon { ClassAliasPool.CLASS_ALIASES.addAlias(Fields.class); } - private final String name; // Name of the test scenario private final String s; // YAML formatted text to be tested /** @@ -42,7 +42,7 @@ public class YamlTextWireTest extends WireTestCommon { * @param text YAML formatted text to be used in the test. */ public YamlTextWireTest(String name, String text) { - this.name = name; + // Name of the test scenario this.s = text; } diff --git a/src/test/java/net/openhft/chronicle/wire/passthrough/GenericPassTest.java b/src/test/java/net/openhft/chronicle/wire/passthrough/GenericPassTest.java index 84367ed18c..b77b8c051d 100644 --- a/src/test/java/net/openhft/chronicle/wire/passthrough/GenericPassTest.java +++ b/src/test/java/net/openhft/chronicle/wire/passthrough/GenericPassTest.java @@ -29,8 +29,7 @@ public void sayingBroker() { sayingBroker.via("queue1").say("hello"); // Assert the contents written to wire1 - assertEquals("" + - "via: queue1\n" + + assertEquals("via: queue1\n" + "say: hello\n" + "...\n", wire1.toString()); @@ -43,8 +42,7 @@ public void sayingBroker() { final MethodReader reader = wire1.methodReader(microService); assertTrue(reader.readOne()); // Read one message assertFalse(reader.readOne()); // Assert no more messages - assertEquals("" + - "via: queue1\n" + + assertEquals("via: queue1\n" + "say: hello\n" + "...\n", wire2.toString()); @@ -83,8 +81,7 @@ public void passingOpaqueMessage() { assertTrue(reader.readOne()); // Read one message assertFalse(reader.readOne()); // Assert no more messages // the ... is added by the wire format. - assertEquals("" + - "via: pass\n" + + assertEquals("via: pass\n" + "\u0082\n" + "...\n", wire2.toString()); @@ -119,8 +116,7 @@ public void passingOpaqueMessageBinary() { } // Assert the written data in wire1 - assertEquals("" + - "0b 00 00 00 # msg-length\n" + + assertEquals("0b 00 00 00 # msg-length\n" + "b9 03 76 69 61 # via: (event)\n" + "e4 70 61 73 73 # pass\n" + "82 # opaque message\n", @@ -134,8 +130,7 @@ public void passingOpaqueMessageBinary() { final MethodReader reader = wire1.methodReader(microService); assertTrue(reader.readOne()); // Read one message assertFalse(reader.readOne()); // Assert no more messages - assertEquals("" + - "0b 00 00 00 # msg-length\n" + + assertEquals("0b 00 00 00 # msg-length\n" + "b9 03 76 69 61 # via: (event)\n" + "e4 70 61 73 73 # pass\n" + "82 # passed-through\n", @@ -144,6 +139,7 @@ public void passingOpaqueMessageBinary() { /** * Interface representing a broker with a method to route actions via a named path. + * * @param The type of action or behavior being routed. */ interface Broker { @@ -152,6 +148,7 @@ interface Broker { /** * Interface for routing actions using an alternative method. + * * @param The type of action or behavior being routed. */ interface Another { diff --git a/src/test/java/net/openhft/chronicle/wire/reordered/NestedClass.java b/src/test/java/net/openhft/chronicle/wire/reordered/NestedClass.java index 1b4d2879d8..7f4ea673a8 100644 --- a/src/test/java/net/openhft/chronicle/wire/reordered/NestedClass.java +++ b/src/test/java/net/openhft/chronicle/wire/reordered/NestedClass.java @@ -13,6 +13,7 @@ * Class representing a nested structure for testing serialization and deserialization in Chronicle Wire. * It demonstrates custom read and write logic for marshalling, handling nested objects and different data types. */ +@SuppressWarnings({"deprecation", "removal"}) public class NestedClass implements Marshallable { private String text; private String text2; diff --git a/src/test/java/net/openhft/chronicle/wire/reordered/OuterClass.java b/src/test/java/net/openhft/chronicle/wire/reordered/OuterClass.java index 6dff595382..283d5575e1 100644 --- a/src/test/java/net/openhft/chronicle/wire/reordered/OuterClass.java +++ b/src/test/java/net/openhft/chronicle/wire/reordered/OuterClass.java @@ -14,6 +14,7 @@ * OuterClass extends SelfDescribingMarshallable to facilitate serialization and deserialization. * It contains multiple lists of NestedClass objects and handles custom serialization logic. */ +@SuppressWarnings({"deprecation", "removal"}) class OuterClass extends SelfDescribingMarshallable { // Lists for maintaining instances of NestedClass and their free pools private final List listAFree = new ArrayList<>(); diff --git a/src/test/java/net/openhft/chronicle/wire/reordered/ReorderedTest.java b/src/test/java/net/openhft/chronicle/wire/reordered/ReorderedTest.java index 7e472e1696..3e01c48e67 100644 --- a/src/test/java/net/openhft/chronicle/wire/reordered/ReorderedTest.java +++ b/src/test/java/net/openhft/chronicle/wire/reordered/ReorderedTest.java @@ -31,6 +31,7 @@ public class ReorderedTest extends WireTestCommon { // Static instances of OuterClass for test setup private static final OuterClass outerClass1 = new OuterClass(); private static final OuterClass outerClass2 = new OuterClass(); + private static final Collection nestedReadSubsets; // Static initialization block to configure the OuterClass instances for testing static { @@ -62,7 +63,6 @@ public class ReorderedTest extends WireTestCommon { // Function to dynamically select the wire type for each test iteration @SuppressWarnings("rawtypes") private final Function, Wire> wireType; - private static final Collection nestedReadSubsets; // Constructor accepting the wire type function @SuppressWarnings("rawtypes") @@ -102,7 +102,6 @@ public void testWithReorderedFields() { wire.bytes().writeUnsignedByte('\n'); wire.writeEventName(() -> "test2").marshallable(outerClass2); - // System.out.println(bytes.readByte(0) < 0 ? bytes.toHexString() : bytes.toString()); @NotNull StringBuilder sb = new StringBuilder(); @NotNull OuterClass outerClass0 = new OuterClass(); @@ -155,8 +154,6 @@ public void testTopLevel() { wire.write("b").int32(i * 11); wire.write("c").int32(i * 111); - // System.out.println(wire); - // Reading back the fields in a different order and asserting assertEquals(i * 111, wire.read(() -> "c").int32()); assertEquals(i, wire.read(() -> "a").int32()); assertEquals(i * 11, wire.read(() -> "b").int32()); diff --git a/src/test/java/net/openhft/chronicle/wire/reuse/ByteArrayResuseTest.java b/src/test/java/net/openhft/chronicle/wire/reuse/ByteArrayResuseTest.java index a9ef787ba9..370e058a11 100644 --- a/src/test/java/net/openhft/chronicle/wire/reuse/ByteArrayResuseTest.java +++ b/src/test/java/net/openhft/chronicle/wire/reuse/ByteArrayResuseTest.java @@ -77,8 +77,7 @@ public void writeReadBytesArrayBinary() { private void doWriteReadBytesArray(String expected) { Data data = new Data(); data.timestamp = 1234567890L; - byte[] bytes = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; - data.bytes = bytes; + data.bytes = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; Wire wire = WireType.BINARY_LIGHT.apply(new HexDumpBytes()); wire.write("data") diff --git a/src/test/java/net/openhft/chronicle/wire/reuse/NestedClassTest.java b/src/test/java/net/openhft/chronicle/wire/reuse/NestedClassTest.java index f5d4d0413c..09b1a03808 100644 --- a/src/test/java/net/openhft/chronicle/wire/reuse/NestedClassTest.java +++ b/src/test/java/net/openhft/chronicle/wire/reuse/NestedClassTest.java @@ -95,8 +95,7 @@ public void testMultipleReads() { wire.bytes().writeUnsignedByte('\n'); wire.writeEventName(() -> "test2").marshallable(outerClass2); - // System.out.println(bytes.readByte(0) < 0 ? bytes.toHexString() : bytes.toString()); - // StringBuilder to capture event names during reading. + // StringBuilder to capture event names during reading. @NotNull StringBuilder sb = new StringBuilder(); @NotNull OuterClass outerClass0 = new OuterClass(); diff --git a/src/test/java/net/openhft/chronicle/wire/reuse/OuterClass.java b/src/test/java/net/openhft/chronicle/wire/reuse/OuterClass.java index 9528b0d998..b4d93c8713 100644 --- a/src/test/java/net/openhft/chronicle/wire/reuse/OuterClass.java +++ b/src/test/java/net/openhft/chronicle/wire/reuse/OuterClass.java @@ -18,6 +18,7 @@ * and deserialization using Chronicle Wire. It contains lists of NestedClass objects * and some basic properties. */ +@SuppressWarnings({"deprecation", "removal"}) class OuterClass implements Marshallable { // Lists for storing NestedClass instances. Separate lists are maintained // for free and used instances to optimize object reuse. diff --git a/src/test/java/net/openhft/chronicle/wire/reuse/WireCollection.java b/src/test/java/net/openhft/chronicle/wire/reuse/WireCollection.java index 4909c10453..df1076bdd7 100644 --- a/src/test/java/net/openhft/chronicle/wire/reuse/WireCollection.java +++ b/src/test/java/net/openhft/chronicle/wire/reuse/WireCollection.java @@ -88,10 +88,10 @@ public void writeMarshallable(@NotNull WireOut wire) { .write(ModelKeys.reference).text(reference) .write(ModelKeys.path).text(path) .write(ModelKeys.name).text(name); - if (properties.size() > 0) { + if (!properties.isEmpty()) { wire.write(ModelKeys.properties).marshallable(properties, String.class, WireProperty.class, true); } - if (collections != null && collections.size() > 0) { + if (collections != null && !collections.isEmpty()) { wire.write(ModelKeys.collections).marshallable(collections, String.class, WireCollection.class, false); } } diff --git a/src/test/java/net/openhft/chronicle/wire/reuse/WireCollectionTest.java b/src/test/java/net/openhft/chronicle/wire/reuse/WireCollectionTest.java index 5a7851f7b6..03da270dbc 100644 --- a/src/test/java/net/openhft/chronicle/wire/reuse/WireCollectionTest.java +++ b/src/test/java/net/openhft/chronicle/wire/reuse/WireCollectionTest.java @@ -83,7 +83,6 @@ public void testMultipleReads() { // Writing the collection to the wire wire.writeDocument(true, collection); - // System.out.println(Wires.fromSizePrefixedBlobs(bytes)); @NotNull WireCollection results = new WireCollection(); // Reading the collection from the wire diff --git a/src/test/java/net/openhft/chronicle/wire/reuse/WireUtils.java b/src/test/java/net/openhft/chronicle/wire/reuse/WireUtils.java index ba7d16f1ad..075c55747f 100644 --- a/src/test/java/net/openhft/chronicle/wire/reuse/WireUtils.java +++ b/src/test/java/net/openhft/chronicle/wire/reuse/WireUtils.java @@ -112,7 +112,7 @@ public static void compareWireCollection(@NotNull WireCollection a, @NotNull Wir if (b.getCollections().containsKey(c.getReference())) { compareWireCollection(c, b.getCollections().get(c.getReference())); } else { - //Assert.fail("Cannot match collection child element WireCollection"); + Assert.fail("Cannot match collection child element WireCollection"); } }); } diff --git a/src/test/java/net/openhft/chronicle/wire/serializable/ScalarValues.java b/src/test/java/net/openhft/chronicle/wire/serializable/ScalarValues.java index 060d37f874..bf3d86e116 100644 --- a/src/test/java/net/openhft/chronicle/wire/serializable/ScalarValues.java +++ b/src/test/java/net/openhft/chronicle/wire/serializable/ScalarValues.java @@ -3,6 +3,7 @@ */ package net.openhft.chronicle.wire.serializable; +import net.openhft.chronicle.core.annotation.UsedViaReflection; import net.openhft.chronicle.core.io.InvalidMarshallableException; import net.openhft.chronicle.core.io.Validatable; import net.openhft.chronicle.core.io.ValidatableUtil; @@ -20,6 +21,7 @@ import static net.openhft.chronicle.wire.WireType.TEXT; @SuppressWarnings({"rawtypes","deprecation"}) +@UsedViaReflection public class ScalarValues implements Serializable, Validatable { private static final long serialVersionUID = 0L; // Primitive data type fields diff --git a/src/test/java/net/openhft/chronicle/wire/serializable/SerializableWireTest.java b/src/test/java/net/openhft/chronicle/wire/serializable/SerializableWireTest.java index 7ae1d63c15..c40420e255 100644 --- a/src/test/java/net/openhft/chronicle/wire/serializable/SerializableWireTest.java +++ b/src/test/java/net/openhft/chronicle/wire/serializable/SerializableWireTest.java @@ -120,5 +120,4 @@ public void testStringBuilderSerialization() { static class TextContainer extends SelfDescribingMarshallable { StringBuilder[] innerBuilders; // Represents inner StringBuilders } - } diff --git a/src/test/java/net/openhft/chronicle/wire/type/conversions/binary/ConventionsTest.java b/src/test/java/net/openhft/chronicle/wire/type/conversions/binary/ConventionsTest.java index ed0132b060..0a6e64a71f 100644 --- a/src/test/java/net/openhft/chronicle/wire/type/conversions/binary/ConventionsTest.java +++ b/src/test/java/net/openhft/chronicle/wire/type/conversions/binary/ConventionsTest.java @@ -29,7 +29,6 @@ public void testTypeConversionsMaxValue() throws NoSuchFieldException, IllegalAc Object extected; // Check if type is a subclass of Number if (Number.class.isAssignableFrom(type)) { - // System.out.println("" + type + ""); // Retrieve the MAX_VALUE field from the type class final Field max_value = type.getField("MAX_VALUE"); extected = max_value.get(type);