From 75215f80f670bfa2c705809f1774543c64115d50 Mon Sep 17 00:00:00 2001 From: Alexander Krimm Date: Wed, 27 Aug 2025 16:01:24 +0200 Subject: [PATCH 1/7] CI: switch to restyled action and bump action versions Signed-off-by: Alexander Krimm --- .github/workflows/codeql.yml | 8 +++---- .github/workflows/coverity.yml | 16 ++++++------- .github/workflows/dispatch_coverity.yml | 2 +- .github/workflows/maven.yml | 25 ++++++++++++--------- .github/workflows/restyled.yml | 30 +++++++++++++++++++++++++ .restyled.yaml | 5 +++-- 6 files changed, 60 insertions(+), 26 deletions(-) create mode 100644 .github/workflows/restyled.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index cb477251..b394503f 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -24,18 +24,18 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} queries: +security-and-quality - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v4 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v4 with: category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index 03a22778..799390cd 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -15,16 +15,16 @@ on: jobs: coverityscan: name: Static analysis with Coverity - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest environment: coverity # environment needs to be manually triggered only use on demand steps: - name: Checkout branch on that the Coverity scan was dispatched - uses: actions/checkout@v2 + uses: actions/checkout@v6 if: ${{ github.event_name == 'workflow_run' }} with: ref: ${{ github.event.workflow_run.head_branch }} fetch-depth: 25 - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 if: ${{ github.event_name != 'workflow_run' }} with: fetch-depth: 25 @@ -33,16 +33,16 @@ jobs: with: versionPattern: '${{ env.JAVA_REFERENCE_VERSION }}.[0-9]*.[0-9]*' - name: Cache the Maven packages to speed up build - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} restore-keys: ${{ runner.os }}-m2 - - name: Set up JDK11 - uses: actions/setup-java@v2.1.0 + - name: Set up JDK17 + uses: actions/setup-java@v5 with: - java-version: 11 - distribution: 'adopt' + java-version: 17 + distribution: 'temurin' - name: Download Coverity Build Tool run: | wget -q https://scan.coverity.com/download/java/Linux --post-data "token=$TOKEN&project=fair-acc/opencmw-java" -O cov-analysis-linux64.tar.gz diff --git a/.github/workflows/dispatch_coverity.yml b/.github/workflows/dispatch_coverity.yml index 7bcebc7a..d02e61ca 100644 --- a/.github/workflows/dispatch_coverity.yml +++ b/.github/workflows/dispatch_coverity.yml @@ -6,7 +6,7 @@ on: workflow_dispatch jobs: dispatch_coverity: name: Dispatch static analysis with coverity - runs-on: ubuntu-18.04 + runs-on: ubuntu-latest steps: - name: Dispatch run: echo "Dispatching Coverity run" \ No newline at end of file diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 406cb94f..adb8dbe3 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -11,7 +11,7 @@ on: release: types: [ created ] env: - JAVA_REFERENCE_VERSION: 11 + JAVA_REFERENCE_VERSION: 17 jobs: test: @@ -19,13 +19,13 @@ jobs: strategy: matrix: os: [ ubuntu-latest ] # TODO add: windows-latest, macOS-latest - java: [ 11, 16-ea ] + java: [ 17, 21 ] fail-fast: false max-parallel: 6 name: Test JDK ${{ matrix.java }}, ${{ matrix.os }} environment: configure coverage steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 with: fetch-depth: 100 - name: Fetch tags @@ -34,15 +34,16 @@ jobs: uses: ./.github/actions/get-version with: versionPattern: '${{ env.JAVA_REFERENCE_VERSION }}.[0-9]*.[0-9]*' - - uses: actions/cache@v1 # cache maven packages to speed up build + - uses: actions/cache@v4 # cache maven packages to speed up build with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} restore-keys: ${{ runner.os }}-m2 - name: Set up JDK ${{matrix.java}} - uses: actions/setup-java@v1.4.3 + uses: actions/setup-java@v5 with: java-version: ${{matrix.java}} + distribution: 'temurin' - name: Test with Maven run: mvn -Dgpg.skip=true --no-transfer-progress --batch-mode -Drevision=${REVISION} -Dsha1=${SHA1} -Dchangelist=${CHANGELIST} package env: @@ -51,10 +52,10 @@ jobs: CHANGELIST: ${{ steps.version.outputs.changelist }} - name: coverage report - send to Codecov if: matrix.java == env.JAVA_REFERENCE_VERSION - uses: codecov/codecov-action@v1.2.1 + uses: codecov/codecov-action@v5 - name: coverage report - send to Codacy if: matrix.java == env.JAVA_REFERENCE_VERSION - uses: codacy/codacy-coverage-reporter-action@0.2.0 + uses: codacy/codacy-coverage-reporter-action@v1.3.0 with: project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} @@ -64,7 +65,7 @@ jobs: runs-on: ubuntu-latest environment: deploy steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - id: version uses: ./.github/actions/get-version with: @@ -72,15 +73,16 @@ jobs: - name: Fetch tags run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* - name: Cache the Maven packages to speed up build - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} restore-keys: ${{ runner.os }}-m2 - name: Set up JDK ${{ env.JAVA_REFERENCE_VERSION }} - uses: actions/setup-java@v1.4.3 + uses: actions/setup-java@v5 with: java-version: ${{ env.JAVA_REFERENCE_VERSION }} + distribution: 'temurin' gpg-private-key: ${{ secrets.GPG_KEY }} gpg-passphrase: GPG_PASS - name: Deploy to Github Packages @@ -92,9 +94,10 @@ jobs: SHA1: ${{ steps.version.outputs.sha1 }} CHANGELIST: ${{ steps.version.outputs.changelist }} - name: Set up JDK to publish to OSSRH - uses: actions/setup-java@v1.4.3 + uses: actions/setup-java@v5 with: java-version: ${{ env.JAVA_REFERENCE_VERSION }} + distribution: 'temurin' server-id: ossrh server-username: SONATYPE_USER server-password: SONATYPE_PASS diff --git a/.github/workflows/restyled.yml b/.github/workflows/restyled.yml new file mode 100644 index 00000000..9c03932a --- /dev/null +++ b/.github/workflows/restyled.yml @@ -0,0 +1,30 @@ +name: Restyled + +on: + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + restyled: + runs-on: ubuntu-latest + steps: + - name: Ensure fork is public + if: ${{ github.event.pull_request.head.repo.private }} + run: | + echo "Private forks are not supported for restyling" >&2 + + - uses: actions/checkout@v6 + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.ref }} + token: ${{ secrets.GITHUB_TOKEN }} + + - uses: restyled-io/actions/setup@v4 + + - id: restyler + uses: restyled-io/actions/run@v4 + with: + fail-on-differences: true diff --git a/.restyled.yaml b/.restyled.yaml index 5ef9edb9..8347c50f 100644 --- a/.restyled.yaml +++ b/.restyled.yaml @@ -93,7 +93,7 @@ ignore_labels: # re-specify the default in your own config if you prefer to avoid update # surprises. # -restylers_version: "20191031" +# restylers_version: "v0.643.0" # Restylers to run, and how # @@ -182,7 +182,8 @@ restylers_version: "20191031" # https://github.com/restyled-io/restylers/tree/main/clang-format restylers: - name: clang-format - image: 'restyled/restyler-clang-format:12.0.0' + image: + tag: v18 command: - clang-format - "-i" From 09fcb46c77641f31a07e0bdb5a25bf8d83948210 Mon Sep 17 00:00:00 2001 From: Alexander Krimm Date: Mon, 25 Aug 2025 16:06:32 +0200 Subject: [PATCH 2/7] Bump Dependencies and JDK language level Signed-off-by: Alexander Krimm --- client/pom.xml | 2 +- .../opencmw/utils/SystemPropertiesTest.java | 2 +- pom.xml | 48 +++++++++---------- .../serialiser/spi/FastByteBuffer.java | 32 ++++++++----- 4 files changed, 45 insertions(+), 39 deletions(-) diff --git a/client/pom.xml b/client/pom.xml index 964b53cf..b2b9514a 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -53,7 +53,7 @@ com.github.oshi oshi-core - 5.8.2 + 6.4.1 test diff --git a/core/src/test/java/io/opencmw/utils/SystemPropertiesTest.java b/core/src/test/java/io/opencmw/utils/SystemPropertiesTest.java index cdfff6d0..391009d8 100644 --- a/core/src/test/java/io/opencmw/utils/SystemPropertiesTest.java +++ b/core/src/test/java/io/opencmw/utils/SystemPropertiesTest.java @@ -121,7 +121,7 @@ void testHierarchy() { } @AutoService(Settings.class) - private static class TestOptionClass { + private static class TestOptionClass implements Settings { public static final String TEST_OPTION_DOC = "TestOptionClass.TEST_OPTION="; @MetaInfo(unit = "int", description = "test option documentation") public static final Integer TEST_OPTION = 0; diff --git a/pom.xml b/pom.xml index dde26d5b..82de3bfb 100644 --- a/pom.xml +++ b/pom.xml @@ -26,27 +26,27 @@ -SNAPSHOT UTF-8 - 11 - 11 - 2.0.0-alpha5 - 1.0 - 22.0.0 + 17 + 17 + 2.0.17 + 1.1.1 + 26.0.2 0.5.2 3.4.4 - 3.13.11 - 9.4.43.v20210629 + 3.13.13 + 9.4.51.v20230217 0.9.23 - 8.5.4 - 3.28.0-GA - 4.9.1 + 8.5.16 + 3.30.2-GA + 5.1.0 3.12.0 - 5.7.2 - 4.1.0 - 0.5.1 - 1.33 - 1.7.4 + 5.13.4 + 4.3.0 + 0.5.5 + 1.37 + 1.15.3 2.3 - 11.2.5 + 11.2.7 0.6.0.20150202 @@ -101,7 +101,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.1 + 3.14.0 ${maven.compiler.source} ${maven.compiler.target} @@ -142,7 +142,7 @@ org.apache.maven.plugins maven-source-plugin - 3.2.1 + 3.3.1 attach-sources @@ -155,7 +155,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.3.0 + 3.11.3 attach-javadocs @@ -168,7 +168,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.0.0-M5 + 3.5.3 @@ -202,7 +202,7 @@ org.jacoco jacoco-maven-plugin - 0.8.7 + 0.8.13 @@ -309,7 +309,7 @@ org.apache.maven.plugins maven-gpg-plugin - 3.0.1 + 3.2.8 sign-artifacts @@ -350,7 +350,7 @@ org.apache.maven.plugins maven-gpg-plugin - 3.0.1 + 3.2.8 sign-artifacts @@ -371,7 +371,7 @@ org.sonatype.plugins nexus-staging-maven-plugin - 1.6.8 + 1.7.0 true ossrh diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/FastByteBuffer.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/FastByteBuffer.java index 734d2831..0d820890 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/FastByteBuffer.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/FastByteBuffer.java @@ -53,18 +53,24 @@ public class FastByteBuffer implements IoBuffer { static { // get an instance of the otherwise private 'Unsafe' class try { - @SuppressWarnings("Java9ReflectionClassVisibility") - Class cls = Class.forName("jdk.internal.module.IllegalAccessLogger"); // NOSONAR NOPMD - Field logger = cls.getDeclaredField("logger"); - final Field field = Unsafe.class.getDeclaredField("theUnsafe"); - field.setAccessible(true); //NOSONAR + field.setAccessible(true); // NOSONAR unsafe = (Unsafe) field.get(null); - unsafe.putObjectVolatile(cls, unsafe.staticFieldOffset(logger), null); - - } catch (NoSuchFieldException | SecurityException | IllegalAccessException | ClassNotFoundException e) { // NOPMD + } catch (NoSuchFieldException | IllegalAccessException e) { // NOPMD + // If we cannot obtain Unsafe, fail fast as the implementation depends on it throw new SecurityException(e); // NOPMD } + + // Best-effort: try to disable IllegalAccessLogger if present on this JDK. + // This is optional and should never prevent class initialization. + try { + Class cls = Class.forName("jdk.internal.module.IllegalAccessLogger"); // NOSONAR NOPMD + Field logger = cls.getDeclaredField("logger"); + unsafe.putObjectVolatile(cls, unsafe.staticFieldOffset(logger), null); + } catch (Throwable t) { + // Ignore: class may not exist or may be inaccessible on this JDK (e.g., JDK 21+). + // This is purely an optimization to reduce noise; do not break initialization. + } } private final ReadWriteLock internalLock = new ReentrantReadWriteLock(); @@ -172,7 +178,7 @@ public void ensureCapacity(final int newCapacity) { if (!autoResize) { throw new IndexOutOfBoundsException("required capacity: " + newCapacity + " out of bounds: " + capacity() + " and autoResize is disabled"); } - //TODO: add smarter enlarging algorithm (ie. increase fast for small arrays, + n% for medium sized arrays, byte-by-byte for large arrays) + // TODO: add smarter enlarging algorithm (ie. increase fast for small arrays, + n% for medium sized arrays, byte-by-byte for large arrays) final int addCapacity = Math.min(Math.max(DEFAULT_MIN_CAPACITY_INCREASE, newCapacity >> 3), DEFAULT_MAX_CAPACITY_INCREASE); // min, +12.5%, max // if we are reading, limit() marks valid data, when writing, position() marks end of valid data, limit() is safe bet because position <= limit forceCapacity(newCapacity + addCapacity, limit()); @@ -481,7 +487,7 @@ public String[] getStringArray(final String[] dst, final int length) { public String getStringISO8859() { final int arraySize = getInt(); // for C++ zero terminated string checkAvailable(arraySize); - //alt safe-fallback final String str = new String(buffer, position, arraySize - 1, StandardCharsets.ISO_8859_1) + // alt safe-fallback final String str = new String(buffer, position, arraySize - 1, StandardCharsets.ISO_8859_1) @SuppressWarnings("deprecation") final String str = new String(buffer, 0, intPos, arraySize - 1); // NOSONAR NOPMD fastest alternative that is public API // final String str = FastStringBuilder.iso8859BytesToString(buffer, position, arraySize - 1) @@ -918,7 +924,7 @@ private static void copyMemory(final Object srcBase, final int srcOffset, final // Fast UTF-8 byte-array to String(Builder) decode - code originally based on Google's ProtoBuffer implementation and since modified @SuppressWarnings("PMD") - private static void decodeUTF8(byte[] bytes, int offset, int size, StringBuilder result) { //NOSONAR + private static void decodeUTF8(byte[] bytes, int offset, int size, StringBuilder result) { // NOSONAR // Bitwise OR combines the sign bits so any negative value fails the check. // N.B. many code snippets are in-lined for performance reasons (~10% performance improvement) ... this is a JIT hot spot. if ((offset | size | bytes.length - offset - size) < 0) { @@ -987,7 +993,7 @@ private static void decodeUTF8(byte[] bytes, int offset, int size, StringBuilder final byte byte3 = unsafe.getByte(bytes, readPos++); final int resultPos1 = resultPos++; if (byte2 > (byte) 0xBF // is not trailing byte - // overlong? 5 most significant bits must not all be zero + // overlong? 5 most significant bits must not all be zero || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) // check for illegal surrogate codepoints || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) @@ -1043,7 +1049,7 @@ private static int encodeISO8859(final String sequence, final byte[] bytes, fina // Fast UTF-8 String (CharSequence) to byte-array encoder - code originally based on Google's ProtoBuffer implementation and since modified @SuppressWarnings("PMD") - private static int encodeUTF8(final CharSequence sequence, final byte[] bytes, final int offset, final int length) { //NOSONAR + private static int encodeUTF8(final CharSequence sequence, final byte[] bytes, final int offset, final int length) { // NOSONAR int utf16Length = sequence.length(); int base = ARRAY_BYTE_BASE_OFFSET + offset; int i = 0; From cf9822cfad1a88b75dd1d860c61e1b3856594068 Mon Sep 17 00:00:00 2001 From: Alexander Krimm Date: Mon, 25 Aug 2025 16:15:10 +0200 Subject: [PATCH 3/7] Serialiser: remove field name hash The field name hash has been removed from opencmw-cpp [1]. This removes the hash from the field to make the serialisation formats compatible again. [1] https://github.com/fair-acc/opencmw-cpp/pull/318 Signed-off-by: Alexander Krimm --- .../client/cmwlight/CmwLightProtocol.java | 13 +- .../opencmw/serialiser/FieldDescription.java | 7 - .../opencmw/serialiser/FieldSerialiser.java | 19 +- .../opencmw/serialiser/IoClassSerialiser.java | 14 +- .../serialiser/spi/BinarySerialiser.java | 180 +++++++++--------- .../serialiser/spi/ClassFieldDescription.java | 30 +-- .../serialiser/spi/CmwLightSerialiser.java | 19 +- .../serialiser/spi/JsonSerialiser.java | 8 +- .../opencmw/serialiser/spi/ProtocolInfo.java | 2 +- .../spi/WireDataFieldDescription.java | 39 +--- .../spi/iobuffer/DataSetSerialiser.java | 6 +- .../SerialiserAnnotationTests.java | 8 +- .../serialiser/spi/BinarySerialiserTests.java | 10 +- .../serialiser/spi/JsonSerialiserTests.java | 12 +- .../serialiser/utils/CmwLightHelper.java | 8 +- .../opencmw/serialiser/utils/JsonHelper.java | 12 +- .../serialiser/utils/SerialiserHelper.java | 12 +- 17 files changed, 164 insertions(+), 235 deletions(-) diff --git a/client/src/main/java/io/opencmw/client/cmwlight/CmwLightProtocol.java b/client/src/main/java/io/opencmw/client/cmwlight/CmwLightProtocol.java index f059630f..01e40387 100644 --- a/client/src/main/java/io/opencmw/client/cmwlight/CmwLightProtocol.java +++ b/client/src/main/java/io/opencmw/client/cmwlight/CmwLightProtocol.java @@ -25,7 +25,7 @@ * Serializes CmwLightMessage to ZeroMQ messages and vice versa. */ @SuppressWarnings("PMD.UnusedLocalVariable") // Unused variables are taken from the protocol and should be available for reference -public class CmwLightProtocol { //NOPMD -- nomen est omen +public class CmwLightProtocol { // NOPMD -- nomen est omen private static final String CONTEXT_ACQ_STAMP = "ContextAcqStamp"; private static final String CONTEXT_CYCLE_STAMP = "ContextCycleStamp"; private static final String MESSAGE = "Message"; @@ -421,8 +421,7 @@ private static ZFrame serialiseDataContext(final CmwLightMessage.DataContext dat private static void putMap(final CmwLightSerialiser serialiser, final String fieldName, final Map map) throws RdaLightException { if (map != null) { - final var dataFieldMarker = new WireDataFieldDescription(serialiser, serialiser.getParent(), -1, - fieldName, DataType.START_MARKER, -1, -1, -1); + final var dataFieldMarker = new WireDataFieldDescription(serialiser, serialiser.getParent(), fieldName, DataType.START_MARKER, -1, -1, -1); serialiser.putStartMarker(dataFieldMarker); for (final Map.Entry entry : map.entrySet()) { if (entry.getValue() instanceof String) { @@ -485,10 +484,10 @@ private static Map readMap(final FieldDescription field) { if (result == null) { result = new HashMap<>(); // NOPMD - necessary to allocate inside loop } - //if ( 'condition' ) { - // find out how to see if the field is itself a map - // result.put(dataField.getFieldName(), readMap(dataField)) - // } else { + // if ( 'condition' ) { + // find out how to see if the field is itself a map + // result.put(dataField.getFieldName(), readMap(dataField)) + // } else { result.put(dataField.getFieldName(), ((WireDataFieldDescription) dataField).data()); //} } diff --git a/serialiser/src/main/java/io/opencmw/serialiser/FieldDescription.java b/serialiser/src/main/java/io/opencmw/serialiser/FieldDescription.java index 07a3985f..58d155c6 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/FieldDescription.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/FieldDescription.java @@ -10,8 +10,6 @@ public interface FieldDescription { FieldDescription findChildField(String fieldName); - FieldDescription findChildField(final int fieldNameHashCode, final String fieldName); - List getChildren(); /** @@ -60,11 +58,6 @@ public interface FieldDescription { */ String getFieldName(); - /** - * @return the data field name's hashcode (N.B. used for faster identification of the field) - */ - int getFieldNameHashCode(); - /** * * @return buffer position in byte where the data field header starts diff --git a/serialiser/src/main/java/io/opencmw/serialiser/FieldSerialiser.java b/serialiser/src/main/java/io/opencmw/serialiser/FieldSerialiser.java index 9d40654b..f24937b8 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/FieldSerialiser.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/FieldSerialiser.java @@ -23,7 +23,6 @@ public class FieldSerialiser { private final String name; private final String canonicalName; private final String simpleName; - private final int cachedHashCode; protected TriConsumer readerFunction; protected TriConsumer writerFunction; protected TriFunction returnFunction; @@ -50,7 +49,6 @@ public FieldSerialiser(final TriConsumer reader, final TriFunction returnFunc this.writerFunction = writer; this.classPrototype = classPrototype; this.classGenericArguments = Arrays.asList(classGenericArguments); - cachedHashCode = IoClassSerialiser.computeHashCode(classPrototype, this.classGenericArguments); String genericFieldString = this.classGenericArguments.isEmpty() ? "" : this.classGenericArguments.stream().map(Type::getTypeName).collect(Collectors.joining(", ", "<", ">")); @@ -71,7 +69,7 @@ public boolean equals(Object obj) { } /** - * + * * @return canonical name of the class/interface description */ public String getCanonicalName() { @@ -79,7 +77,7 @@ public String getCanonicalName() { } /** - * + * * @return class reference */ public Class getClassPrototype() { @@ -87,7 +85,7 @@ public Class getClassPrototype() { } /** - * + * * @return class reference to generics arguments */ public List getGenericsPrototypes() { @@ -95,7 +93,7 @@ public List getGenericsPrototypes() { } /** - * + * * @return consumer that is being executed for reading from the back-end serialiser implementation */ public TriConsumer getReaderFunction() { @@ -103,7 +101,7 @@ public TriConsumer getReaderFunction() { } /** - * + * * @return simple name name of the class/interface description */ public String getSimpleName() { @@ -111,7 +109,7 @@ public String getSimpleName() { } /** - * + * * @return consumer that is being executed for writing to the back-end serialiser implementation */ public TriConsumer getWriterFunction() { @@ -126,11 +124,6 @@ public TriFunction getReturnObjectFunction() { return returnFunction; } - @Override - public int hashCode() { - return cachedHashCode; - } - @Override public String toString() { return name; diff --git a/serialiser/src/main/java/io/opencmw/serialiser/IoClassSerialiser.java b/serialiser/src/main/java/io/opencmw/serialiser/IoClassSerialiser.java index fcd1f2df..6e435a31 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/IoClassSerialiser.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/IoClassSerialiser.java @@ -189,7 +189,7 @@ public T deserialiseObject(WireDataFieldDescription fieldRoot, final T obj) // class reference is not known by name (ie. was empty) parse directly dependent children final List fieldRootChildren = fieldRoot.getChildren().get(0).getChildren(); for (final FieldDescription fieldDescription : fieldRootChildren) { - final ClassFieldDescription subFieldDescription = (ClassFieldDescription) clazz.findChildField(fieldDescription.getFieldNameHashCode(), fieldDescription.getFieldName()); + final ClassFieldDescription subFieldDescription = (ClassFieldDescription) clazz.findChildField(fieldDescription.getFieldName()); if (subFieldDescription != null) { deserialise(obj, obj.getClass(), fieldDescription, subFieldDescription, 1); @@ -401,7 +401,7 @@ public void serialiseObject(final Object obj) { // serialise null object matchedIoSerialiser.putHeaderInfo(); final String dataEndMarkerName = "OBJ_ROOT_END"; - final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(matchedIoSerialiser, null, dataEndMarkerName.hashCode(), dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); + final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(matchedIoSerialiser, null, dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); matchedIoSerialiser.putEndMarker(dataEndMarker); return; } @@ -424,7 +424,7 @@ public void serialiseObject(final Object obj) { FieldSerialiser castFieldSerialiser = fieldSerialiser; matchedIoSerialiser.putCustomData(classField, obj, obj.getClass(), castFieldSerialiser); final String dataEndMarkerName = "OBJ_ROOT_END"; - final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(matchedIoSerialiser, null, dataEndMarkerName.hashCode(), dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); + final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(matchedIoSerialiser, null, dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); matchedIoSerialiser.putEndMarker(dataEndMarker); } } @@ -491,14 +491,14 @@ protected void deserialise(final Object obj, Class clazz, final FieldDesc return; } - if (fieldRoot.getFieldNameHashCode() != classField.getFieldNameHashCode() /*|| !fieldRoot.getFieldName().equals(classField.getFieldName())*/) { + if (!fieldRoot.getFieldName().equals(classField.getFieldName())) { // did not find matching (sub-)field in class if (fieldRoot.getChildren().isEmpty()) { return; } // check for potential inner fields for (final FieldDescription fieldDescription : fieldRoot.getChildren()) { - final ClassFieldDescription subFieldDescription = (ClassFieldDescription) classField.findChildField(fieldDescription.getFieldNameHashCode(), fieldDescription.getFieldName()); + final ClassFieldDescription subFieldDescription = (ClassFieldDescription) classField.findChildField(fieldDescription.getFieldName()); if (subFieldDescription != null) { deserialise(obj, obj.getClass(), fieldDescription, subFieldDescription, recursionDepth + 1); @@ -524,7 +524,7 @@ protected void deserialise(final Object obj, Class clazz, final FieldDesc // no specific deserialiser present check for potential inner fields for (final FieldDescription fieldDescription : fieldRoot.getChildren()) { - final ClassFieldDescription subFieldDescription = (ClassFieldDescription) classField.findChildField(fieldDescription.getFieldNameHashCode(), fieldDescription.getFieldName()); + final ClassFieldDescription subFieldDescription = (ClassFieldDescription) classField.findChildField(fieldDescription.getFieldName()); if (subFieldDescription != null) { deserialise(subRef, subRef.getClass(), fieldDescription, subFieldDescription, recursionDepth + 1); @@ -616,7 +616,7 @@ public int hashCode() { @Override public String toString() { return "FieldSerialiserKey{" - + "clazz=" + clazz + ", classGenericArguments=" + classGenericArguments + '}'; + + "clazz=" + clazz + ", classGenericArguments=" + classGenericArguments + '}'; } } diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/BinarySerialiser.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/BinarySerialiser.java index 02e76e2b..b87cf676 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/BinarySerialiser.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/BinarySerialiser.java @@ -24,23 +24,23 @@ * * Generic binary serialiser aimed at efficiently transferring data between server/client and in particular between * Java/C++/web-based programs. For rationale see IoSerialiser.md description. - * + * *

* There are two default backing buffer implementations ({@link FastByteBuffer FastByteBuffer} and {@link ByteBuffer ByteBuffer}), * but can be extended/replaced with any other buffer is also possible provided it implements the {@link IoBuffer IoBuffer} interface. - * + * *

* The default serialisable data types are defined in {@link DataType DataType} and include definitions for *

    - *
  • primitives (byte, short, ..., float, double, and String), and - *
  • arrays thereof (ie. byte[], short[], ..., float[], double[], and String[]), as well as + *
  • primitives (byte, short, ..., float, double, and String), and + *
  • arrays thereof (ie. byte[], short[], ..., float[], double[], and String[]), as well as *
  • complex objects implementing Collections (ie. Set, List, Queues), Enums or Maps. - *
+ * * Any other complex data objects can be stored/extended using the {@link DataType#OTHER OTHER} sub-type. - * + * * N.B. Multi-dimensional arrays are handled through one-dimensional striding arrays with the additional * infos on number of dimensions and size for each individual dimension. - * + * *

* raw-byte level protocol: above data items are stored as follows: *


@@ -53,10 +53,9 @@
  * * String:        [ 4 bytes (int) - length (including termination) ][ n bytes based on ISO-8859 or UTF-8 encoding ]
  * * field header:  # start field header 'p0'
  *                  [ 1 byte - uniqueType ]
- *                  [ 4 bytes - field name hash code] // enables faster field matching
  *                  [ 4 bytes - dataStart = n bytes until data start] // counted w.r.t. field header start
  *                  [ 4 bytes - dataSize = n bytes for data size]
- *                  [ String (ISO-8859) - field name ]             // optional, if there are no field name hash code collisions
+ *                  [ String (ISO-8859) - field name ]
  *                  N.B. following fields are optional (detectable if buffer position smaller than 'p0' + dataStart)
  *                  [ String (UTF-8)    - field unit ]
  *                  [ String (UTF-8)    - field in/out direction ]
@@ -69,14 +68,14 @@
  * * boxed arrays:  as above but each element cast to corresponding primitive type
  * * array header:  [ field header (as above) ] +
  *                      [4 bytes - number of dimensions N_d ] +
- *                      [4 bytes x N_d - vector sizes for each dimension N_i ]  
+ *                      [4 bytes x N_d - vector sizes for each dimension N_i ]
  * * Collection[E]:
  * * List[]:
  * * Queue[E]:
- * * Set[E]:        [ array header (uniqueType= one of the Collection type IDs) ] + 
+ * * Set[E]:        [ array header (uniqueType= one of the Collection type IDs) ] +
  *                      [ 1 byte - uniqueType of E ] + [  n bytes - array of E cast to primitive type and/or string ]
  * * Map[K,V]:      [ array header (uniqueType=0xCB) ] + [ 1 byte - uniqueType of K ] +  [ 1 byte - uniqueType of V ] +
- *                      [ n bytes - array of K cast to primitive type and/or string ] + 
+ *                      [ n bytes - array of K cast to primitive type and/or string ] +
  *                      [ n bytes - array of V cast to primitive type and/or string ]
  * * OTHER          [ field header - uniqueByte = 0xFD ] +
  *                      [ 1 byte - uniqueType -- custom class type definition ]
@@ -84,20 +83,20 @@
  *                      [ n bytes - custom serialisation definition ]
  * * start marker:  [ field header for '0x00' ] // dataSize == # bytes until the corresponding end-marker start
  * * end marker:    [ field header for '0xFE' ]
- * 
+ *
  * * nesting or sub-structures (ie. POJOs with sub-classes) can be achieved via:
- * [  start marker - field name == nesting context1 ] 
+ * [  start marker - field name == nesting context1 ]
  *   [  start marker - field name == nesting context2 ]
- *    ... 
+ *    ...
  *   [  end marker - field name == nesting context2 (optional name) ]
  * [  end marker - field name == nesting context1 (optional name) ]
- * 
+ *
  * with
  * T: being a generic list parameter outlined in {@link DataType DataType}
  * K: being a generic key parameter outlined in {@link DataType DataType}
  * V: being a generic value parameter outlined in {@link DataType DataType}
  * 
- * + * * @author rstein */ @SuppressWarnings({ "PMD.CommentSize", "PMD.TooManyMethods", "PMD.ExcessivePublicCount", "PMD.PrematureDeclaration", "PMD.ExcessiveClassLength", "PMD.NPathComplexity" }) // variables need to be read from stream @@ -402,28 +401,19 @@ public String getEnumTypeList() { return enumTypeList; } - @Override - public WireDataFieldDescription getFieldHeader() { - final int headerStart = buffer.position(); - final byte dataTypeByte = buffer.getByte(); - final int fieldNameHashCode = buffer.getInt(); - final int dataStartOffset = buffer.getInt(); - final int dataStartPosition = headerStart + dataStartOffset; - int dataSize = buffer.getInt(); - final String fieldName; - if (buffer.position() < dataStartPosition) { - fieldName = buffer.getStringISO8859(); - } else { - fieldName = null; + return null; } - final DataType dataType = getDataType(dataTypeByte); - if (dataType == DataType.END_MARKER) { - parent = (WireDataFieldDescription) parent.getParent(); - } - lastFieldHeader = new WireDataFieldDescription(this, parent, fieldNameHashCode, fieldName, dataType, headerStart, dataStartOffset, dataSize); - if (dataType == DataType.START_MARKER) { - parent = lastFieldHeader; + @Override + public String getEnumTypeList() { + // read value vector + buffer.getStringISO8859(); // enumSimpleName + buffer.getStringISO8859(); // enumName + final String enumTypeList = buffer.getStringISO8859(); + buffer.getStringISO8859(); // enumState + buffer.getInt(); // enumOrdinal + + return enumTypeList; } if (this.isPutFieldMetaData()) { @@ -772,16 +762,10 @@ public void setPutFieldMetaData(final boolean putFieldMetaData) { this.putFieldMetaData = putFieldMetaData; } - @Override - public WireDataFieldDescription parseIoStream(final boolean readHeader) { - final WireDataFieldDescription fieldRoot = getRootElement(); - parent = fieldRoot; - final WireDataFieldDescription headerRoot = readHeader ? checkHeaderInfo().getFieldHeader() : getFieldHeader(); - buffer.position(headerRoot.getDataStartPosition()); - parseIoStream(headerRoot, 0); - //updateDataEndMarker(fieldRoot) - return fieldRoot; - } + @Override + public void setPutFieldMetaData(final boolean putFieldMetaData) { + this.putFieldMetaData = putFieldMetaData; + } public void parseIoStream(final WireDataFieldDescription fieldRoot, final int recursionDepth) { if (fieldRoot.getParent() == null) { @@ -1462,14 +1446,37 @@ public WireDataFieldDescription putFieldHeader(final FieldDescription fieldDescr } final boolean isScalar = dataType.isScalar(); - // -- offset 0 vs. field start - final int headerStart = buffer.position(); - buffer.putByte(getDataType(dataType)); // data type ID - buffer.putInt(fieldDescription.getFieldNameHashCode()); - buffer.putInt(-1); // dataStart offset - final int dataSize = isScalar ? dataType.getPrimitiveSize() : -1; - buffer.putInt(dataSize); // dataSize (N.B. 'headerStart' + 'dataStart + dataSize' == start of next field header - buffer.putStringISO8859(fieldDescription.getFieldName()); // full field name + @Override + public WireDataFieldDescription putFieldHeader(final FieldDescription fieldDescription) { + if (fieldDescription == null) { + // early return + return null; + } + final DataType dataType = fieldDescription.getDataType(); + if (isPutFieldMetaData()) { + buffer.ensureAdditionalCapacity(bufferIncrements); + } + final boolean isScalar = dataType.isScalar(); + + // -- offset 0 vs. field start + final int headerStart = buffer.position(); + buffer.putByte(getDataType(dataType)); // data type ID + buffer.putInt(-1); // dataStart offset + final int dataSize = isScalar ? dataType.getPrimitiveSize() : -1; + buffer.putInt(dataSize); // dataSize (N.B. 'headerStart' + 'dataStart + dataSize' == start of next field header + buffer.putStringISO8859(fieldDescription.getFieldName()); // full field name + + if (isPutFieldMetaData() && fieldDescription.isAnnotationPresent() && dataType != DataType.END_MARKER) { + buffer.putString(fieldDescription.getFieldUnit()); + buffer.putString(fieldDescription.getFieldDescription()); + buffer.putString(fieldDescription.getFieldDirection()); + final String[] groups = fieldDescription.getFieldGroups().toArray(new String[0]); + buffer.putStringArray(groups, groups.length); + } + + // -- offset dataStart calculations + final int dataStartOffset = buffer.position() - headerStart; + buffer.putInt(headerStart + 1, dataStartOffset); // write offset to dataStart if (isPutFieldMetaData() && fieldDescription.isAnnotationPresent() && dataType != DataType.END_MARKER) { buffer.putString(fieldDescription.getFieldUnit()); @@ -1479,22 +1486,16 @@ public WireDataFieldDescription putFieldHeader(final FieldDescription fieldDescr buffer.putStringArray(groups, groups.length); } - // -- offset dataStart calculations - final int dataStartOffset = buffer.position() - headerStart; - buffer.putInt(headerStart + 5, dataStartOffset); // write offset to dataStart + @Override + public WireDataFieldDescription putFieldHeader(final String fieldName, final DataType dataType) { + final int addCapacity = ((fieldName.length() + 18) * FastByteBuffer.SIZE_OF_BYTE) + bufferIncrements + dataType.getPrimitiveSize(); + buffer.ensureAdditionalCapacity(addCapacity); + final boolean isScalar = dataType.isScalar(); // from hereon there are data specific structures buffer.ensureAdditionalCapacity(16); // allocate 16 bytes to account for potential array header (safe-bet) - lastFieldHeader = new WireDataFieldDescription(this, parent, fieldDescription.getFieldNameHashCode(), fieldDescription.getFieldName(), dataType, headerStart, dataStartOffset, dataSize); - if (isPutFieldMetaData() && fieldDescription.isAnnotationPresent()) { - lastFieldHeader.setFieldUnit(fieldDescription.getFieldUnit()); - lastFieldHeader.setFieldDescription(fieldDescription.getFieldDescription()); - lastFieldHeader.setFieldDirection(fieldDescription.getFieldDirection()); - lastFieldHeader.setFieldGroups(fieldDescription.getFieldGroups()); - } - return lastFieldHeader; - } + // this putField method cannot add meta-data use 'putFieldHeader(final FieldDescription fieldDescription)' instead @Override public WireDataFieldDescription putFieldHeader(final String fieldName, final DataType dataType) { @@ -1505,7 +1506,6 @@ public WireDataFieldDescription putFieldHeader(final String fieldName, final Dat // -- offset 0 vs. field start final int headerStart = buffer.position(); buffer.putByte(getDataType(dataType)); // data type ID - buffer.putInt(fieldName.hashCode()); // unique hashCode identifier -- TODO: unify across C++/Java & optimise performance buffer.putInt(-1); // dataStart offset final int dataSize = isScalar ? dataType.getPrimitiveSize() : -1; buffer.putInt(dataSize); // dataSize (N.B. 'headerStart' + 'dataStart + dataSize' == start of next field header @@ -1516,12 +1516,12 @@ public WireDataFieldDescription putFieldHeader(final String fieldName, final Dat // -- offset dataStart calculations final int fieldHeaderDataStart = buffer.position(); final int dataStartOffset = (fieldHeaderDataStart - headerStart); - buffer.putInt(headerStart + 5, dataStartOffset); // write offset to dataStart + buffer.putInt(headerStart + 1, dataStartOffset); // write offset to dataStart // from hereon there are data specific structures buffer.ensureAdditionalCapacity(16); // allocate 16 bytes to account for potential array header (safe-bet) - lastFieldHeader = new WireDataFieldDescription(this, parent, fieldName.hashCode(), fieldName, dataType, headerStart, dataStartOffset, dataSize); + lastFieldHeader = new WireDataFieldDescription(this, parent, fieldName, dataType, headerStart, dataStartOffset, dataSize); return lastFieldHeader; } @@ -1562,20 +1562,8 @@ public void putGenericArrayAsPrimitive(final DataType dataType, final Object[] d } } - @Override - public void putHeaderInfo(final FieldDescription... field) { - parent = lastFieldHeader = getRootElement(); - - buffer.ensureAdditionalCapacity(ADDITIONAL_HEADER_INFO_SIZE); - buffer.putInt(VERSION_MAGIC_NUMBER); - buffer.putStringISO8859(PROTOCOL_NAME); - buffer.putByte(VERSION_MAJOR); - buffer.putByte(VERSION_MINOR); - buffer.putByte(VERSION_MICRO); - if (field.length == 0 || field[0] == null) { - putStartMarker(new WireDataFieldDescription(this, null, "OBJ_ROOT_START".hashCode(), "OBJ_ROOT_START", DataType.START_MARKER, -1, -1, -1)); - } else { - putStartMarker(field[0]); + lastFieldHeader = new WireDataFieldDescription(this, parent, fieldName, dataType, headerStart, dataStartOffset, dataSize); + return lastFieldHeader; } } @@ -1598,11 +1586,23 @@ public void updateDataEndMarker(final WireDataFieldDescription fieldHeader) { throw new IllegalStateException("buffer position " + sizeMarkerEnd + " is beyond buffer capacity " + buffer.capacity()); } - final int dataSize = sizeMarkerEnd - fieldHeader.getDataStartPosition(); - if (fieldHeader.getDataSize() != dataSize) { - final int headerStart = fieldHeader.getFieldStart(); - fieldHeader.setDataSize(dataSize); - buffer.putInt(headerStart + 9, dataSize); // 9 bytes = 1 byte for dataType, 4 bytes for fieldNameHashCode, 4 bytes for dataOffset + @Override + public void updateDataEndMarker(final WireDataFieldDescription fieldHeader) { + if (fieldHeader == null) { + // N.B. early return in case field header hasn't been written + return; + } + final int sizeMarkerEnd = buffer.position(); + if (isPutFieldMetaData() && sizeMarkerEnd >= buffer.capacity()) { + throw new IllegalStateException("buffer position " + sizeMarkerEnd + " is beyond buffer capacity " + buffer.capacity()); + } + + final int dataSize = sizeMarkerEnd - fieldHeader.getDataStartPosition(); + if (fieldHeader.getDataSize() != dataSize) { + final int headerStart = fieldHeader.getFieldStart(); + fieldHeader.setDataSize(dataSize); + buffer.putInt(headerStart + 5, dataSize); // 5 bytes = 1 byte for dataType, 4 bytes for dataOffset + } } } @@ -1656,7 +1656,7 @@ protected E[] getGenericArrayAsBoxedPrimitive(final DataType dataType) { private WireDataFieldDescription getRootElement() { final int headerOffset = 1 + PROTOCOL_NAME.length() + 3; // unique byte + protocol length + 3 x byte for version - return new WireDataFieldDescription(this, null, "ROOT".hashCode(), "ROOT", DataType.OTHER, buffer.position() + headerOffset, -1, -1); + return new WireDataFieldDescription(this, null, "ROOT", DataType.OTHER, buffer.position() + headerOffset, -1, -1); } public static byte getDataType(final DataType dataType) { diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/ClassFieldDescription.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/ClassFieldDescription.java index 4a69f98a..dbf56638 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/ClassFieldDescription.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/ClassFieldDescription.java @@ -32,7 +32,6 @@ public class ClassFieldDescription implements FieldDescription { private final int hierarchyDepth; private final Field field; private final String fieldName; - private final int fieldNameHashCode; private final String fieldNameRelative; private final String fieldUnit; private final String fieldDescription; @@ -102,7 +101,6 @@ protected ClassFieldDescription(final Class referenceClass, final Field field if (referenceClass == null) { this.field = Objects.requireNonNull(field, "field must not be null"); classType = field.getType(); - fieldNameHashCode = field.getName().hashCode(); fieldName = field.getName().intern(); fieldNameRelative = this.parent == null ? fieldName : (this.parent.getFieldNameRelative() + "." + fieldName).intern(); @@ -111,7 +109,6 @@ protected ClassFieldDescription(final Class referenceClass, final Field field } else { this.field = null; // NOPMD it's a root, no field definition available classType = referenceClass; - fieldNameHashCode = classType.getName().hashCode(); fieldName = classType.getName().intern(); fieldNameRelative = fieldName; @@ -205,10 +202,6 @@ public boolean equals(final Object obj) { return false; } final FieldDescription other = (FieldDescription) obj; - if (this.getFieldNameHashCode() != other.getFieldNameHashCode()) { - return false; - } - if (this.getDataType() != other.getDataType()) { return false; } @@ -218,18 +211,9 @@ public boolean equals(final Object obj) { @Override public FieldDescription findChildField(final String fieldName) { - return findChildField(fieldName.hashCode(), fieldName); - } - - @Override - public FieldDescription findChildField(final int fieldNameHashCode, final String fieldName) { for (final FieldDescription child : children) { final String name = child.getFieldName(); - //noinspection StringEquality - if (name == fieldName) { //NOSONAR NOPMD early return if the same String object reference - return child; - } - if (child.getFieldNameHashCode() == fieldNameHashCode && name.equals(fieldName)) { + if (name.equals(fieldName)) { // NOSONAR NOPMD early return if the same String object reference return child; } } @@ -331,11 +315,6 @@ public String getFieldName() { return fieldName; } - @Override - public int getFieldNameHashCode() { - return fieldNameHashCode; - } - /** * @return relative field name within class hierarchy (ie. field_level0.field_level1.variable_0) */ @@ -474,11 +453,6 @@ public String getTypeNameSimple() { return typeNameSimple; } - @Override - public int hashCode() { - return fieldNameHashCode; - } - /** * @return the isAbstract */ @@ -662,7 +636,7 @@ protected static void exploreClass(final Class classType, final ClassFieldDes protected static void printClassStructure(final ClassFieldDescription field, final boolean fullView, final int recursionLevel) { final String enumOrClass = field.isEnum() ? "Enum " : "class "; - final String typeCategory = (field.isInterface() ? "interface " : (field.isPrimitive() ? "" : enumOrClass)); //NOSONAR //NOPMD + final String typeCategory = (field.isInterface() ? "interface " : (field.isPrimitive() ? "" : enumOrClass)); // NOSONAR //NOPMD final String typeName = field.getTypeName() + field.getGenericFieldTypeString(); final String mspace = spaces(recursionLevel * ClassUtils.getIndentationNumberOfSpace()); final boolean isSerialisable = field.isSerializable(); diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/CmwLightSerialiser.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/CmwLightSerialiser.java index 5cdc6b7f..206e8ac5 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/CmwLightSerialiser.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/CmwLightSerialiser.java @@ -20,7 +20,7 @@ /** * Light-weight open-source implementation of a (de-)serialiser that is binary-compatible to the serialiser used by CMW, - * a proprietary closed-source middle-ware used in some accelerator laboratories. + * a proprietary closed-source middleware used in some accelerator laboratories. * * N.B. this implementation is intended only for performance/functionality comparison and to enable a backward compatible * transition to the {@link BinarySerialiser} implementation which is a bit more flexible, @@ -111,7 +111,7 @@ public CmwLightSerialiser(final IoBuffer buffer) { public ProtocolInfo checkHeaderInfo() { final var fieldName = ""; final int dataSize = FastByteBuffer.SIZE_OF_INT; - final var headerStartField = new WireDataFieldDescription(this, parent, fieldName.hashCode(), fieldName, DataType.START_MARKER, buffer.position(), buffer.position(), dataSize); // NOPMD - needs to be read here + final var headerStartField = new WireDataFieldDescription(this, parent, fieldName, DataType.START_MARKER, buffer.position(), buffer.position(), dataSize); // NOPMD - needs to be read here final var nEntries = buffer.getInt(); if (nEntries <= 0) { throw new IllegalStateException("nEntries = " + nEntries + " <= 0!"); @@ -216,7 +216,7 @@ public > Enum getEnum(final Enum enumeration) { try { final var values = enumClass.getMethod("values"); final Object[] possibleEnumValues = (Object[]) values.invoke(null); - //noinspection unchecked + // noinspection unchecked return (Enum) possibleEnumValues[ordinal]; // NOSONAR NOPMD } catch (final ReflectiveOperationException e) { LOGGER.atError().setCause(e).addArgument(enumClass).log("could not match 'valueOf(String)' function for class/(supposedly) enum of {}"); @@ -268,9 +268,7 @@ public WireDataFieldDescription getFieldHeader() { throw new IllegalStateException("should not reach here -- format is incompatible with CMW"); } - final int fieldNameHashCode = fieldName.hashCode(); //TODO: verify same hashcode function - - lastFieldHeader = new WireDataFieldDescription(this, parent, fieldNameHashCode, fieldName, dataType, headerStart, dataStartOffset, dataSize); + lastFieldHeader = new WireDataFieldDescription(this, parent, fieldName, dataType, headerStart, dataStartOffset, dataSize); final int dataStartPosition = headerStart + dataStartOffset; buffer.position(dataStartPosition); @@ -1014,7 +1012,7 @@ public WireDataFieldDescription putFieldHeader(final FieldDescription fieldDescr // from hereon there are data specific structures buffer.ensureAdditionalCapacity(16); // allocate 16+ bytes to account for potential array header (safe-bet) } - lastFieldHeader = new WireDataFieldDescription(this, parent, fieldDescription.getFieldNameHashCode(), fieldDescription.getFieldName(), customDataType, headerStart, dataStartOffset, dataSize); + lastFieldHeader = new WireDataFieldDescription(this, parent, fieldDescription.getFieldName(), customDataType, headerStart, dataStartOffset, dataSize); updateDataEntryCount(); return lastFieldHeader; @@ -1042,8 +1040,7 @@ public WireDataFieldDescription putFieldHeader(final String fieldName, final Dat buffer.ensureAdditionalCapacity(16); // allocate 16+ bytes to account for potential array header (safe-bet) } - final int fieldNameHashCode = fieldName.hashCode(); // TODO: check hashCode function - lastFieldHeader = new WireDataFieldDescription(this, parent, fieldNameHashCode, fieldName, dataType, headerStart, dataStartOffset, dataSize); + lastFieldHeader = new WireDataFieldDescription(this, parent, fieldName, dataType, headerStart, dataStartOffset, dataSize); updateDataEntryCount(); return lastFieldHeader; @@ -1054,7 +1051,7 @@ public void putHeaderInfo(final FieldDescription... field) { parent = lastFieldHeader = getRootElement(); final var fieldName = ""; final int dataSize = FastByteBuffer.SIZE_OF_INT; - lastFieldHeader = new WireDataFieldDescription(this, parent, fieldName.hashCode(), fieldName, DataType.START_MARKER, buffer.position(), buffer.position(), dataSize); + lastFieldHeader = new WireDataFieldDescription(this, parent, fieldName, DataType.START_MARKER, buffer.position(), buffer.position(), dataSize); buffer.putInt(0); updateDataEntryCount(); parent = lastFieldHeader; @@ -1085,7 +1082,7 @@ public void updateDataEndMarker(final WireDataFieldDescription fieldHeader) { } private WireDataFieldDescription getRootElement() { - return new WireDataFieldDescription(this, null, "ROOT".hashCode(), "ROOT", DataType.OTHER, buffer.position(), -1, -1); + return new WireDataFieldDescription(this, null, "ROOT", DataType.OTHER, buffer.position(), -1, -1); } private void updateDataEntryCount() { diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/JsonSerialiser.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/JsonSerialiser.java index ef7ac1ad..8538f315 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/JsonSerialiser.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/JsonSerialiser.java @@ -86,7 +86,7 @@ public ProtocolInfo checkHeaderInfo() { throw new IllegalStateException(NOT_A_JSON_COMPATIBLE_PROTOCOL, e); } - final WireDataFieldDescription headerStartField = new WireDataFieldDescription(this, null, JSON_ROOT.hashCode(), JSON_ROOT, DataType.OTHER, buffer.position(), count - 1, -1); + final WireDataFieldDescription headerStartField = new WireDataFieldDescription(this, null, JSON_ROOT, DataType.OTHER, buffer.position(), count - 1, -1); final ProtocolInfo header = new ProtocolInfo(this, headerStartField, JsonSerialiser.class.getCanonicalName(), (byte) 1, (byte) 0, (byte) 0); parent = lastFieldHeader = headerStartField; queryFieldName = JSON_ROOT; @@ -271,7 +271,7 @@ public WireDataFieldDescription parseIoStream(final boolean readHeader) { iter.reset(buffer.elements(), 0, buffer.limit()); tempRoot = root = iter.readAny(); - final WireDataFieldDescription fieldRoot = new WireDataFieldDescription(this, null, "ROOT".hashCode(), "ROOT", DataType.OTHER, buffer.position(), -1, -1); + final WireDataFieldDescription fieldRoot = new WireDataFieldDescription(this, null, "ROOT", DataType.OTHER, buffer.position(), -1, -1); parseIoStream(fieldRoot, tempRoot, ""); return fieldRoot; @@ -906,7 +906,7 @@ private void parseIoStream(final WireDataFieldDescription fieldRoot, final Any a } final Map map = any.asMap(); - final WireDataFieldDescription putStartMarker = new WireDataFieldDescription(this, fieldRoot, fieldName.hashCode(), fieldName, DataType.START_MARKER, 0, -1, -1); + final WireDataFieldDescription putStartMarker = new WireDataFieldDescription(this, fieldRoot, fieldName, DataType.START_MARKER, 0, -1, -1); for (Map.Entry child : map.entrySet()) { final String childName = child.getKey(); final Any childAny = map.get(childName); @@ -914,7 +914,7 @@ private void parseIoStream(final WireDataFieldDescription fieldRoot, final Any a if (data instanceof Map) { parseIoStream(putStartMarker, childAny, childName); } else if (data != null) { - new WireDataFieldDescription(this, putStartMarker, childName.hashCode(), childName, DataType.fromClassType(data.getClass()), 0, -1, -1); // NOPMD - necessary to allocate inside loop + new WireDataFieldDescription(this, putStartMarker, childName, DataType.fromClassType(data.getClass()), 0, -1, -1); // NOPMD - necessary to allocate inside loop } } // add if necessary: diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/ProtocolInfo.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/ProtocolInfo.java index ef2515f1..73225454 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/ProtocolInfo.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/ProtocolInfo.java @@ -10,7 +10,7 @@ public class ProtocolInfo extends WireDataFieldDescription { private final byte versionMicro; public ProtocolInfo(final IoSerialiser source, final WireDataFieldDescription fieldDescription, final String producer, final byte major, final byte minor, final byte micro) { - super(source, null, fieldDescription.hashCode(), fieldDescription.getFieldName(), fieldDescription.getDataType(), fieldDescription.getFieldStart(), fieldDescription.getDataStartOffset(), fieldDescription.getDataSize()); + super(source, null, fieldDescription.getFieldName(), fieldDescription.getDataType(), fieldDescription.getFieldStart(), fieldDescription.getDataStartOffset(), fieldDescription.getDataSize()); this.fieldHeader = fieldDescription; producerName = producer; versionMajor = major; diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/WireDataFieldDescription.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/WireDataFieldDescription.java index 7cc8ee9f..ad76780d 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/WireDataFieldDescription.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/WireDataFieldDescription.java @@ -14,13 +14,12 @@ /** * Field header descriptor - * + * * @author rstein */ public class WireDataFieldDescription implements FieldDescription { private static final Logger LOGGER = LoggerFactory.getLogger(WireDataFieldDescription.class); private final String fieldName; - private final int fieldNameHashCode; private final DataType dataType; private final List children = new ArrayList<>(); private final FieldDescription parent; @@ -40,20 +39,16 @@ public class WireDataFieldDescription implements FieldDescription { * * @param source the referenced IoBuffer (if any) * @param parent the optional parent field header (for cascaded objects) - * @param fieldNameHashCode the fairly-unique hash-code of the field name, - * N.B. checked during 1st iteration against fieldName, if no collisions are present then - * this check is being suppressed * @param fieldName the clear text field name description * @param dataType the data type of that field * @param fieldStart the absolute buffer position from which the field header can be parsed * @param dataStartOffset the position from which the actual data can be parsed onwards * @param dataSize the expected number of bytes to skip the data block */ - public WireDataFieldDescription(final IoSerialiser source, final FieldDescription parent, final int fieldNameHashCode, final String fieldName, final DataType dataType, // + public WireDataFieldDescription(final IoSerialiser source, final FieldDescription parent, final String fieldName, final DataType dataType, // final int fieldStart, final int dataStartOffset, final int dataSize) { ioSerialiser = source; this.parent = parent; - this.fieldNameHashCode = fieldNameHashCode; this.fieldName = fieldName; this.dataType = dataType; this.fieldStart = fieldStart; @@ -75,10 +70,6 @@ public boolean equals(final Object obj) { return false; } FieldDescription other = (FieldDescription) obj; - if (this.getFieldNameHashCode() != other.getFieldNameHashCode()) { - return false; - } - if (this.getDataType() != other.getDataType()) { return false; } @@ -88,18 +79,10 @@ public boolean equals(final Object obj) { @Override public FieldDescription findChildField(final String fieldName) { - return findChildField(fieldName.hashCode(), fieldName); - } - - @Override - public FieldDescription findChildField(final int fieldNameHashCode, final String fieldName) { - for (final FieldDescription field : children) { //NOSONAR - final String name = field.getFieldName(); - if (name == fieldName) { // NOSONAR NOPMD early return if the same String object reference - return field; - } - if (field.hashCode() == fieldNameHashCode && name.equals(fieldName)) { - return field; + for (final FieldDescription child : children) { + final String name = child.getFieldName(); + if (name.equals(fieldName)) { // NOSONAR NOPMD early return if the same String object reference + return child; } } return null; @@ -166,11 +149,6 @@ public String getFieldName() { return fieldName; } - @Override - public int getFieldNameHashCode() { - return fieldNameHashCode; - } - @Override public int getFieldStart() { return fieldStart; @@ -268,11 +246,6 @@ public Class getType() { return dataType.getClassTypes().get(0); } - @Override - public int hashCode() { - return fieldNameHashCode; - } - @Override public boolean isAnnotationPresent() { return fieldUnit != null || fieldDescription != null || fieldDirection != null || (fieldGroups != null && !fieldGroups.isEmpty()); diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/iobuffer/DataSetSerialiser.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/iobuffer/DataSetSerialiser.java index 0768e371..f512ab5d 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/iobuffer/DataSetSerialiser.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/iobuffer/DataSetSerialiser.java @@ -147,7 +147,7 @@ public void write(final DataSet dataSet, final boolean asFloat) { AssertUtils.notNull("dataSet", dataSet); AssertUtils.notNull("ioSerialiser", ioSerialiser); final String dataStartMarkerName = "START_MARKER_DATASET:" + dataSet.getName(); - final WireDataFieldDescription dataStartMarker = new WireDataFieldDescription(ioSerialiser, null, dataStartMarkerName.hashCode(), dataStartMarkerName, DataType.OTHER, -1, -1, -1); + final WireDataFieldDescription dataStartMarker = new WireDataFieldDescription(ioSerialiser, null, dataStartMarkerName, DataType.OTHER, -1, -1, -1); ioSerialiser.putStartMarker(dataStartMarker); writeHeaderDataToStream(dataSet); @@ -168,12 +168,12 @@ public void write(final DataSet dataSet, final boolean asFloat) { } final String dataEndMarkerName = "END_MARKER_DATASET:" + dataSet.getName(); - final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(ioSerialiser, null, dataEndMarkerName.hashCode(), dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); + final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(ioSerialiser, null, dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); ioSerialiser.putEndMarker(dataEndMarker); } protected FieldDescription checkFieldCompatibility(final FieldDescription rootField, final int fieldNameHashCode, final String fieldName, final DataType... requireDataTypes) { - FieldDescription fieldHeader = rootField.findChildField(fieldNameHashCode, fieldName); + FieldDescription fieldHeader = rootField.findChildField(fieldName); if (fieldHeader == null) { return null; } diff --git a/serialiser/src/test/java/io/opencmw/serialiser/annotations/SerialiserAnnotationTests.java b/serialiser/src/test/java/io/opencmw/serialiser/annotations/SerialiserAnnotationTests.java index 3859e6b0..13e1d64c 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/annotations/SerialiserAnnotationTests.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/annotations/SerialiserAnnotationTests.java @@ -29,7 +29,7 @@ void testAnnotationGeneration() { final ClassFieldDescription classFieldDescription = ClassUtils.getFieldDescription(dataClass.getClass()); // classFieldDescription.printFieldStructure(); - final FieldDescription energyField = classFieldDescription.findChildField("energy".hashCode(), "energy"); + final FieldDescription energyField = classFieldDescription.findChildField("energy"); assertNotNull(energyField); assertEquals("GeV/u", energyField.getFieldUnit()); assertEquals("energy description", energyField.getFieldDescription()); @@ -37,7 +37,7 @@ void testAnnotationGeneration() { assertFalse(energyField.getFieldGroups().isEmpty()); assertEquals("A", energyField.getFieldGroups().get(0)); - final FieldDescription temperatureField = classFieldDescription.findChildField("temperature".hashCode(), "temperature"); + final FieldDescription temperatureField = classFieldDescription.findChildField("temperature"); assertNotNull(temperatureField); assertEquals("°C", temperatureField.getFieldUnit()); assertEquals("important temperature reading", temperatureField.getFieldDescription()); @@ -67,7 +67,7 @@ void testCustomSerialiserIdentity(final Class bufferClass) t final WireDataFieldDescription root = ioSerialiser.parseIoStream(true); final FieldDescription serialiserFieldDescriptions = root.getChildren().get(0); - final FieldDescription energyField = serialiserFieldDescriptions.findChildField("energy".hashCode(), "energy"); + final FieldDescription energyField = serialiserFieldDescriptions.findChildField("energy"); assertNotNull(energyField); assertEquals("GeV/u", energyField.getFieldUnit()); assertEquals("energy description", energyField.getFieldDescription()); @@ -75,7 +75,7 @@ void testCustomSerialiserIdentity(final Class bufferClass) t assertFalse(energyField.getFieldGroups().isEmpty()); assertEquals("A", energyField.getFieldGroups().get(0)); - final FieldDescription temperatureField = serialiserFieldDescriptions.findChildField("temperature".hashCode(), "temperature"); + final FieldDescription temperatureField = serialiserFieldDescriptions.findChildField("temperature"); assertNotNull(temperatureField); assertEquals("°C", temperatureField.getFieldUnit()); assertEquals("important temperature reading", temperatureField.getFieldDescription()); diff --git a/serialiser/src/test/java/io/opencmw/serialiser/spi/BinarySerialiserTests.java b/serialiser/src/test/java/io/opencmw/serialiser/spi/BinarySerialiserTests.java index ebc9c750..a336608b 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/spi/BinarySerialiserTests.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/spi/BinarySerialiserTests.java @@ -407,7 +407,7 @@ void testHeaderAndSpecialItems(final Class bufferClass) thro // add start marker positionBefore.add(buffer.position()); final String dataStartMarkerName = "StartMarker"; - final WireDataFieldDescription dataStartMarker = new WireDataFieldDescription(ioSerialiser, null, dataStartMarkerName.hashCode(), dataStartMarkerName, DataType.START_MARKER, -1, -1, -1); + final WireDataFieldDescription dataStartMarker = new WireDataFieldDescription(ioSerialiser, null, dataStartMarkerName, DataType.START_MARKER, -1, -1, -1); ioSerialiser.putStartMarker(dataStartMarker); positionAfter.add(buffer.position()); @@ -444,7 +444,7 @@ void testHeaderAndSpecialItems(final Class bufferClass) thro // add end marker positionBefore.add(buffer.position()); final String dataEndMarkerName = "EndMarker"; - final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(ioSerialiser, null, dataEndMarkerName.hashCode(), dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); + final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(ioSerialiser, null, dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); ioSerialiser.putEndMarker(dataEndMarker); positionAfter.add(buffer.position()); @@ -562,7 +562,7 @@ void testHeaderAndSpecialItems(final Class bufferClass) thro header = ioSerialiser.getFieldHeader(); assertEquals("enum", header.getFieldName(), "enum type retrieval"); buffer.position(header.getDataStartPosition()); - assertDoesNotThrow(ioSerialiser::getEnumTypeList); //skips enum info + assertDoesNotThrow(ioSerialiser::getEnumTypeList); // skips enum info buffer.position(header.getDataStartPosition()); assertEquals(DataType.ENUM, ioSerialiser.getEnum(DataType.OTHER), "enum retrieval"); assertEquals(positionAfter.removeFirst(), buffer.position()); @@ -657,7 +657,7 @@ void testParseIoStream(final Class bufferClass) throws Insta // start nested data final String nestedContextName = "nested context"; - final WireDataFieldDescription nestedContextMarker = new WireDataFieldDescription(ioSerialiser, null, nestedContextName.hashCode(), nestedContextName, DataType.START_MARKER, -1, -1, -1); + final WireDataFieldDescription nestedContextMarker = new WireDataFieldDescription(ioSerialiser, null, nestedContextName, DataType.START_MARKER, -1, -1, -1); ioSerialiser.putStartMarker(nestedContextMarker); // add start marker ioSerialiser.put("booleanArray", new boolean[] { true }, 1); ioSerialiser.put("byteArray", new byte[] { (byte) 0x42 }, 1); @@ -666,7 +666,7 @@ void testParseIoStream(final Class bufferClass) throws Insta // end nested data final String dataEndMarkerName = "Life is good!"; - final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(ioSerialiser, null, dataEndMarkerName.hashCode(), dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); + final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(ioSerialiser, null, dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); ioSerialiser.putEndMarker(dataEndMarker); // add end marker buffer.flip(); diff --git a/serialiser/src/test/java/io/opencmw/serialiser/spi/JsonSerialiserTests.java b/serialiser/src/test/java/io/opencmw/serialiser/spi/JsonSerialiserTests.java index 443fe9bc..369e02dc 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/spi/JsonSerialiserTests.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/spi/JsonSerialiserTests.java @@ -39,7 +39,7 @@ void testHeaderAndSpecialItems(final Class bufferClass) thro ioSerialiser.putHeaderInfo(); // add start marker final String dataStartMarkerName = "StartMarker"; - final WireDataFieldDescription dataStartMarker = new WireDataFieldDescription(ioSerialiser, null, dataStartMarkerName.hashCode(), dataStartMarkerName, DataType.START_MARKER, -1, -1, -1); + final WireDataFieldDescription dataStartMarker = new WireDataFieldDescription(ioSerialiser, null, dataStartMarkerName, DataType.START_MARKER, -1, -1, -1); ioSerialiser.putStartMarker(dataStartMarker); // add Collection - List final List list = Arrays.asList(1, 2, 3); @@ -58,7 +58,7 @@ void testHeaderAndSpecialItems(final Class bufferClass) thro ioSerialiser.put("enum", DataType.ENUM); // add end marker final String dataEndMarkerName = "EndMarker"; - final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(ioSerialiser, null, dataEndMarkerName.hashCode(), dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); + final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(ioSerialiser, null, dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); ioSerialiser.putEndMarker(dataEndMarker); // end start marker ioSerialiser.putEndMarker(dataEndMarker); // end header info @@ -95,7 +95,7 @@ void testHeaderAndSpecialItems(final Class bufferClass) thro @DisplayName("basic primitive array writer tests") @ParameterizedTest(name = "IoBuffer class - {0}") @ValueSource(classes = { ByteBuffer.class, FastByteBuffer.class }) - void testParseIoStream(final Class bufferClass) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { //NOSONAR NOPMD + void testParseIoStream(final Class bufferClass) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { // NOSONAR NOPMD assertNotNull(bufferClass, "bufferClass being not null"); assertNotNull(bufferClass.getConstructor(int.class), "Constructor(Integer) present"); final IoBuffer buffer = bufferClass.getConstructor(int.class).newInstance(2 * BUFFER_SIZE); // a bit larger buffer since we test more cases at once @@ -144,7 +144,7 @@ void testParseIoStream(final Class bufferClass) throws Insta // start nested data final String nestedContextName = "nested context"; - final WireDataFieldDescription nestedContextMarker = new WireDataFieldDescription(ioSerialiser, null, nestedContextName.hashCode(), nestedContextName, DataType.START_MARKER, -1, -1, -1); + final WireDataFieldDescription nestedContextMarker = new WireDataFieldDescription(ioSerialiser, null, nestedContextName, DataType.START_MARKER, -1, -1, -1); ioSerialiser.putStartMarker(nestedContextMarker); // add start marker ioSerialiser.put("booleanArray", new boolean[] { true }, 1); ioSerialiser.put("byteArray", new byte[] { (byte) 0x42 }, 1); @@ -153,7 +153,7 @@ void testParseIoStream(final Class bufferClass) throws Insta // end nested data final String dataEndMarkerName = "Life is good!"; - final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(ioSerialiser, null, dataEndMarkerName.hashCode(), dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); + final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(ioSerialiser, null, dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); ioSerialiser.putEndMarker(dataEndMarker); // add end marker buffer.flip(); @@ -215,7 +215,7 @@ void testObjectAlongPrimitives() { simpleObj2.switches = Collections.emptyList(); ioSerialiser.put("SimpleObjects", List.of(simpleObj, simpleObj2), SimpleClass.class); - ioSerialiser.putEndMarker(new WireDataFieldDescription(ioSerialiser, null, "end marker".hashCode(), "end marker", DataType.END_MARKER, -1, -1, -1)); + ioSerialiser.putEndMarker(new WireDataFieldDescription(ioSerialiser, null, "end marker", DataType.END_MARKER, -1, -1, -1)); ioSerialiser.getBuffer().flip(); diff --git a/serialiser/src/test/java/io/opencmw/serialiser/utils/CmwLightHelper.java b/serialiser/src/test/java/io/opencmw/serialiser/utils/CmwLightHelper.java index aaf8af30..874a80f8 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/utils/CmwLightHelper.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/utils/CmwLightHelper.java @@ -312,7 +312,7 @@ public static void serialiseCustom(final IoSerialiser ioSerialiser, final TestDa // 1D-arrays ioSerialiser.put("boolArray", pojo.boolArray, pojo.boolArray.length); ioSerialiser.put("byteArray", pojo.byteArray, pojo.byteArray.length); - //ioSerialiser.put("charArray", pojo.charArray, pojo.charArray.length); // not supported by CMW + // ioSerialiser.put("charArray", pojo.charArray, pojo.charArray.length); // not supported by CMW ioSerialiser.put("shortArray", pojo.shortArray, pojo.shortArray.length); ioSerialiser.put("intArray", pojo.intArray, pojo.intArray.length); ioSerialiser.put("longArray", pojo.longArray, pojo.longArray.length); @@ -324,7 +324,7 @@ public static void serialiseCustom(final IoSerialiser ioSerialiser, final TestDa ioSerialiser.put("nDimensions", pojo.nDimensions, pojo.nDimensions.length); ioSerialiser.put("boolNdimArray", pojo.boolNdimArray, pojo.nDimensions); ioSerialiser.put("byteNdimArray", pojo.byteNdimArray, pojo.nDimensions); - //ioSerialiser.put("charNdimArray", pojo.nDimensions); // not supported by CMW + // ioSerialiser.put("charNdimArray", pojo.nDimensions); // not supported by CMW ioSerialiser.put("shortNdimArray", pojo.shortNdimArray, pojo.nDimensions); ioSerialiser.put("intNdimArray", pojo.intNdimArray, pojo.nDimensions); ioSerialiser.put("longNdimArray", pojo.longNdimArray, pojo.nDimensions); @@ -333,7 +333,7 @@ public static void serialiseCustom(final IoSerialiser ioSerialiser, final TestDa if (pojo.nestedData != null) { final String dataStartMarkerName = "nestedData"; - final WireDataFieldDescription nestedDataMarker = new WireDataFieldDescription(ioSerialiser, null, dataStartMarkerName.hashCode(), dataStartMarkerName, DataType.START_MARKER, -1, -1, -1); + final WireDataFieldDescription nestedDataMarker = new WireDataFieldDescription(ioSerialiser, null, dataStartMarkerName, DataType.START_MARKER, -1, -1, -1); ioSerialiser.putStartMarker(nestedDataMarker); serialiseCustom(ioSerialiser, pojo.nestedData, false); ioSerialiser.putEndMarker(nestedDataMarker); @@ -341,7 +341,7 @@ public static void serialiseCustom(final IoSerialiser ioSerialiser, final TestDa if (header) { final String dataEndMarkerName = "OBJ_ROOT_END"; - final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(ioSerialiser, null, dataEndMarkerName.hashCode(), dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); + final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(ioSerialiser, null, dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); ioSerialiser.putEndMarker(dataEndMarker); } } diff --git a/serialiser/src/test/java/io/opencmw/serialiser/utils/JsonHelper.java b/serialiser/src/test/java/io/opencmw/serialiser/utils/JsonHelper.java index ffc34800..a92991b6 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/utils/JsonHelper.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/utils/JsonHelper.java @@ -55,8 +55,8 @@ public static int checkSerialiserIdentity(final TestDataClass inputObject, TestD // JsonStream.setMode(EncodingMode.DYNAMIC_MODE); // JsonIterator.setMode(DecodingMode.REFLECTION_MODE); // JsonStream.setIndentionStep(2); // sets line-breaks and indentation (more human readable) - //Base64Support.enable(); - //Base64FloatSupport.enableEncodersAndDecoders(); + // Base64Support.enable(); + // Base64FloatSupport.enableEncodersAndDecoders(); JsonStream.setMode(EncodingMode.DYNAMIC_MODE); try { @@ -119,7 +119,7 @@ public static void serialiseCustom(final IoSerialiser ioSerialiser, final TestDa // 1D-arrays ioSerialiser.put("boolArray", pojo.boolArray, pojo.boolArray.length); ioSerialiser.put("byteArray", pojo.byteArray, pojo.byteArray.length); - //ioSerialiser.put("charArray", pojo.charArray, pojo.charArray.lenght); + // ioSerialiser.put("charArray", pojo.charArray, pojo.charArray.lenght); ioSerialiser.put("shortArray", pojo.shortArray, pojo.shortArray.length); ioSerialiser.put("intArray", pojo.intArray, pojo.intArray.length); ioSerialiser.put("longArray", pojo.longArray, pojo.longArray.length); @@ -131,7 +131,7 @@ public static void serialiseCustom(final IoSerialiser ioSerialiser, final TestDa ioSerialiser.put("nDimensions", pojo.nDimensions, pojo.nDimensions.length); ioSerialiser.put("boolNdimArray", pojo.boolNdimArray, pojo.nDimensions); ioSerialiser.put("byteNdimArray", pojo.byteNdimArray, pojo.nDimensions); - //ioSerialiser.put("charNdimArray", pojo.nDimensions); + // ioSerialiser.put("charNdimArray", pojo.nDimensions); ioSerialiser.put("shortNdimArray", pojo.shortNdimArray, pojo.nDimensions); ioSerialiser.put("intNdimArray", pojo.intNdimArray, pojo.nDimensions); ioSerialiser.put("longNdimArray", pojo.longNdimArray, pojo.nDimensions); @@ -140,7 +140,7 @@ public static void serialiseCustom(final IoSerialiser ioSerialiser, final TestDa if (pojo.nestedData != null) { final String dataStartMarkerName = "nestedData"; - final WireDataFieldDescription nestedDataMarker = new WireDataFieldDescription(ioSerialiser, null, dataStartMarkerName.hashCode(), dataStartMarkerName, DataType.START_MARKER, -1, -1, -1); + final WireDataFieldDescription nestedDataMarker = new WireDataFieldDescription(ioSerialiser, null, dataStartMarkerName, DataType.START_MARKER, -1, -1, -1); ioSerialiser.putStartMarker(nestedDataMarker); serialiseCustom(ioSerialiser, pojo.nestedData, false); ioSerialiser.putEndMarker(nestedDataMarker); @@ -148,7 +148,7 @@ public static void serialiseCustom(final IoSerialiser ioSerialiser, final TestDa if (header) { final String dataEndMarkerName = "OBJ_ROOT_END"; - final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(ioSerialiser, null, dataEndMarkerName.hashCode(), dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); + final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(ioSerialiser, null, dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); ioSerialiser.putEndMarker(dataEndMarker); } } diff --git a/serialiser/src/test/java/io/opencmw/serialiser/utils/SerialiserHelper.java b/serialiser/src/test/java/io/opencmw/serialiser/utils/SerialiserHelper.java index f9fa04f3..ddc79286 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/utils/SerialiserHelper.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/utils/SerialiserHelper.java @@ -130,8 +130,8 @@ public static void deserialiseCustom(IoSerialiser ioSerialiser, final TestDataCl pojo.boolArray = ioSerialiser.getBooleanArray(); getFieldHeader(ioSerialiser); pojo.byteArray = ioSerialiser.getByteArray(); - //getFieldHeader(ioSerialiser); - //pojo.charArray = ioSerialiser.getCharArray(ioSerialiser); + // getFieldHeader(ioSerialiser); + // pojo.charArray = ioSerialiser.getCharArray(ioSerialiser); getFieldHeader(ioSerialiser); pojo.shortArray = ioSerialiser.getShortArray(); getFieldHeader(ioSerialiser); @@ -218,7 +218,7 @@ public static void serialiseCustom(final IoSerialiser ioSerialiser, final TestDa // 1D-arrays ioSerialiser.put("boolArray", pojo.boolArray, pojo.boolArray.length); ioSerialiser.put("byteArray", pojo.byteArray, pojo.byteArray.length); - //ioSerialiser.put("charArray", pojo.charArray, pojo.charArray.lenght); + // ioSerialiser.put("charArray", pojo.charArray, pojo.charArray.lenght); ioSerialiser.put("shortArray", pojo.shortArray, pojo.shortArray.length); ioSerialiser.put("intArray", pojo.intArray, pojo.intArray.length); ioSerialiser.put("longArray", pojo.longArray, pojo.longArray.length); @@ -230,7 +230,7 @@ public static void serialiseCustom(final IoSerialiser ioSerialiser, final TestDa ioSerialiser.put("nDimensions", pojo.nDimensions, pojo.nDimensions.length); ioSerialiser.put("boolNdimArray", pojo.boolNdimArray, pojo.nDimensions); ioSerialiser.put("byteNdimArray", pojo.byteNdimArray, pojo.nDimensions); - //ioSerialiser.put("charNdimArray", pojo.nDimensions); + // ioSerialiser.put("charNdimArray", pojo.nDimensions); ioSerialiser.put("shortNdimArray", pojo.shortNdimArray, pojo.nDimensions); ioSerialiser.put("intNdimArray", pojo.intNdimArray, pojo.nDimensions); ioSerialiser.put("longNdimArray", pojo.longNdimArray, pojo.nDimensions); @@ -239,7 +239,7 @@ public static void serialiseCustom(final IoSerialiser ioSerialiser, final TestDa if (pojo.nestedData != null) { final String dataStartMarkerName = "nestedData"; - final WireDataFieldDescription nestedDataMarker = new WireDataFieldDescription(ioSerialiser, null, dataStartMarkerName.hashCode(), dataStartMarkerName, DataType.START_MARKER, -1, -1, -1); + final WireDataFieldDescription nestedDataMarker = new WireDataFieldDescription(ioSerialiser, null, dataStartMarkerName, DataType.START_MARKER, -1, -1, -1); ioSerialiser.putStartMarker(nestedDataMarker); serialiseCustom(ioSerialiser, pojo.nestedData, false); ioSerialiser.putEndMarker(nestedDataMarker); @@ -247,7 +247,7 @@ public static void serialiseCustom(final IoSerialiser ioSerialiser, final TestDa if (header) { final String dataEndMarkerName = "OBJ_ROOT_END"; - final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(ioSerialiser, null, dataEndMarkerName.hashCode(), dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); + final WireDataFieldDescription dataEndMarker = new WireDataFieldDescription(ioSerialiser, null, dataEndMarkerName, DataType.START_MARKER, -1, -1, -1); ioSerialiser.putEndMarker(dataEndMarker); } } From ed4e95da7bc1221071f921b9286a6c2d9d9f836c Mon Sep 17 00:00:00 2001 From: Alexander Krimm Date: Mon, 25 Aug 2025 16:17:28 +0200 Subject: [PATCH 4/7] Fix simple codestyle issues Fix trivial codestyle issues like typos, simplifying the code with newer language constructs, etc. Signed-off-by: Alexander Krimm --- .../opencmw/serialiser/IoClassSerialiser.java | 10 +- .../serialiser/spi/BinarySerialiser.java | 163 +++++-------- .../serialiser/spi/ClassFieldDescription.java | 3 +- .../serialiser/spi/CmwLightSerialiser.java | 2 +- .../serialiser/spi/FastByteBuffer.java | 10 +- .../java/io/opencmw/serialiser/spi/Field.java | 60 +++-- .../serialiser/spi/JsonSerialiser.java | 8 +- .../opencmw/serialiser/spi/ProtocolInfo.java | 3 +- .../spi/WireDataFieldDescription.java | 89 +++---- .../spi/iobuffer/DataSetSerialiser.java | 221 ++++++++---------- .../serialiser/IoClassSerialiserTests.java | 16 +- .../benchmark/DataSetSerialiserBenchmark.java | 2 +- .../benchmark/JsonSelectionBenchmark.java | 6 +- .../benchmark/ReflectionBenchmark.java | 2 +- .../SerialiserAssumptionsBenchmark.java | 2 +- .../benchmark/SerialiserBenchmark.java | 2 +- .../benchmark/SerialiserQuickBenchmark.java | 14 +- .../serialiser/spi/BinarySerialiserTests.java | 2 +- .../opencmw/serialiser/spi/IoBufferTests.java | 24 +- .../serialiser/spi/JsonSerialiserTests.java | 5 +- .../serialiser/utils/FlatBuffersHelper.java | 4 +- .../serialiser/utils/TestDataClass.java | 29 ++- 22 files changed, 292 insertions(+), 385 deletions(-) diff --git a/serialiser/src/main/java/io/opencmw/serialiser/IoClassSerialiser.java b/serialiser/src/main/java/io/opencmw/serialiser/IoClassSerialiser.java index 6e435a31..c5570ab9 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/IoClassSerialiser.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/IoClassSerialiser.java @@ -56,13 +56,13 @@ public class IoClassSerialiser { private boolean useCustomJsonSerialiser; /** - * Initialises new IoBuffer-backed object serialiser + * Initialises a new IoBuffer-backed object serialiser * - * @param ioBuffer the backing IoBuffer (see e.g. {@link IoBuffer} + * @param ioBuffer the backing IoBuffer (see e.g. {@link IoBuffer}) * @param ioSerialiserTypeClass optional IoSerialiser type class this IoClassSerialiser should start with * (see also e.g. {@link BinarySerialiser}, * {@link CmwLightSerialiser}, or - * {@link JsonSerialiser} + * {@link JsonSerialiser}) */ @SafeVarargs public IoClassSerialiser(final IoBuffer ioBuffer, final Class... ioSerialiserTypeClass) { @@ -170,7 +170,7 @@ public T deserialiseObject(WireDataFieldDescription fieldRoot, final T obj) matchedIoSerialiser.getBuffer().position(startPosition); if (fieldSerialiser != null) { - // return new object + // return a new object final FieldDescription rawObjectFieldDescription = fieldRoot.getChildren().get(0).getChildren().get(0); matchedIoSerialiser.getBuffer().position(rawObjectFieldDescription.getDataStartPosition()); if (rawObjectFieldDescription.getDataType() == DataType.OTHER) { @@ -186,7 +186,7 @@ public T deserialiseObject(WireDataFieldDescription fieldRoot, final T obj) return obj; } - // class reference is not known by name (ie. was empty) parse directly dependent children + // class reference is not known by name (i.e. was empty) parse directly dependent children final List fieldRootChildren = fieldRoot.getChildren().get(0).getChildren(); for (final FieldDescription fieldDescription : fieldRootChildren) { final ClassFieldDescription subFieldDescription = (ClassFieldDescription) clazz.findChildField(fieldDescription.getFieldName()); diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/BinarySerialiser.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/BinarySerialiser.java index b87cf676..48aa09f4 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/BinarySerialiser.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/BinarySerialiser.java @@ -21,7 +21,7 @@ /** * YaS -- Yet another Serialiser implementation - * + *

* Generic binary serialiser aimed at efficiently transferring data between server/client and in particular between * Java/C++/web-based programs. For rationale see IoSerialiser.md description. * @@ -37,7 +37,7 @@ *

  • complex objects implementing Collections (ie. Set, List, Queues), Enums or Maps. * * Any other complex data objects can be stored/extended using the {@link DataType#OTHER OTHER} sub-type. - * + *

    * N.B. Multi-dimensional arrays are handled through one-dimensional striding arrays with the additional * infos on number of dimensions and size for each individual dimension. * @@ -278,19 +278,11 @@ public Collection getCollection(final Collection collection) { final Collection retCollection; if (collection == null) { - switch (collectionType) { - case SET: - retCollection = new HashSet<>(nElements); - break; - case QUEUE: - retCollection = new ArrayDeque<>(nElements); - break; - case LIST: - case COLLECTION: - default: - retCollection = new ArrayList<>(nElements); - break; - } + retCollection = switch (collectionType) { + case SET -> new HashSet<>(nElements); + case QUEUE -> new ArrayDeque<>(nElements); + default -> new ArrayList<>(nElements); + }; } else { retCollection = collection; retCollection.clear(); @@ -596,10 +588,7 @@ public Map getMap(final Map map) { // NOSONAR NOPMD values = getGenericArrayAsBoxedPrimitive(valueDataType); } - // generate new/write into existing Map - final Map retMap = map == null ? new ConcurrentHashMap<>() : map; - if (map != null) { - map.clear(); + return retMap; } for (int i = 0; i < keys.length; i++) { retMap.put(keys[i], values[i]); @@ -771,18 +760,31 @@ public void parseIoStream(final WireDataFieldDescription fieldRoot, final int re if (fieldRoot.getParent() == null) { parent = lastFieldHeader = fieldRoot; } - WireDataFieldDescription field; - while ((field = getFieldHeader()) != null) { - final DataType dataType = field.getDataType(); - if (dataType == DataType.END_MARKER) { - // reached end of (sub-)class - close nested hierarchy - break; + + public void parseIoStream(final WireDataFieldDescription fieldRoot, final int recursionDepth) { + if (fieldRoot.getParent() == null) { + parent = lastFieldHeader = fieldRoot; } - if (dataType == DataType.START_MARKER) { - // detected sub-class start marker - parseIoStream(field, recursionDepth + 1); - continue; + @Override + public void put(final FieldDescription fieldDescription, final Collection collection, final Type valueType) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final Object[] values = collection.toArray(); + final int nElements = collection.size(); + final Class cleanedType = ClassUtils.getRawType(valueType); + final DataType valueDataType = DataType.fromClassType(cleanedType); + final int entrySize = 17; // as an initial estimate + putArraySizeDescriptor(nElements); + buffer.putInt(nElements); + + if (collection instanceof Queue) { + buffer.putByte(getDataType(DataType.QUEUE)); + } else if (collection instanceof Set) { + buffer.putByte(getDataType(DataType.SET)); + } else if (collection instanceof List) { + buffer.putByte(getDataType(DataType.LIST)); + } else { + buffer.putByte(getDataType(DataType.COLLECTION)); } final int dataSize = field.getDataSize(); @@ -848,9 +850,6 @@ public void put(final FieldDescription fieldDescription, final Enum enumerati } @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) final Class> clazz = (Class>) enumeration.getClass(); - if (clazz == null) { - return; - } final Enum[] enumConsts = clazz.getEnumConstants(); if (enumConsts == null) { return; @@ -859,13 +858,8 @@ public void put(final FieldDescription fieldDescription, final Enum enumerati final int nElements = 1; final int entrySize = 17; // as an initial estimate - buffer.ensureAdditionalCapacity((nElements * entrySize) + 9); - final String typeList = Arrays.stream(clazz.getEnumConstants()).map(Object::toString).collect(Collectors.joining(", ", "[", "]")); - buffer.putStringISO8859(clazz.getSimpleName()); - buffer.putStringISO8859(enumeration.getClass().getName()); - buffer.putStringISO8859(typeList); - buffer.putStringISO8859(enumeration.name()); - buffer.putInt(enumeration.ordinal()); + // convert into two linear arrays one of K and the other for V streamer encoding as + // <1 (int)> updateDataEndMarker(fieldHeader); } @@ -1492,38 +1486,20 @@ public WireDataFieldDescription putFieldHeader(final String fieldName, final Dat buffer.ensureAdditionalCapacity(addCapacity); final boolean isScalar = dataType.isScalar(); - // from hereon there are data specific structures - buffer.ensureAdditionalCapacity(16); // allocate 16 bytes to account for potential array header (safe-bet) + // -- offset 0 vs. field start + final int headerStart = buffer.position(); + buffer.putByte(getDataType(dataType)); // data type ID + buffer.putInt(-1); // dataStart offset + final int dataSize = isScalar ? dataType.getPrimitiveSize() : -1; + buffer.putInt(dataSize); // dataSize (N.B. 'headerStart' + 'dataStart + dataSize' == start of next field header + buffer.putStringISO8859(fieldName); // full field name // this putField method cannot add meta-data use 'putFieldHeader(final FieldDescription fieldDescription)' instead - @Override - public WireDataFieldDescription putFieldHeader(final String fieldName, final DataType dataType) { - final int addCapacity = ((fieldName.length() + 18) * FastByteBuffer.SIZE_OF_BYTE) + bufferIncrements + dataType.getPrimitiveSize(); - buffer.ensureAdditionalCapacity(addCapacity); - final boolean isScalar = dataType.isScalar(); - - // -- offset 0 vs. field start - final int headerStart = buffer.position(); - buffer.putByte(getDataType(dataType)); // data type ID - buffer.putInt(-1); // dataStart offset - final int dataSize = isScalar ? dataType.getPrimitiveSize() : -1; - buffer.putInt(dataSize); // dataSize (N.B. 'headerStart' + 'dataStart + dataSize' == start of next field header - buffer.putStringISO8859(fieldName); // full field name - - // this putField method cannot add meta-data use 'putFieldHeader(final FieldDescription fieldDescription)' instead - - // -- offset dataStart calculations - final int fieldHeaderDataStart = buffer.position(); - final int dataStartOffset = (fieldHeaderDataStart - headerStart); - buffer.putInt(headerStart + 1, dataStartOffset); // write offset to dataStart - - // from hereon there are data specific structures - buffer.ensureAdditionalCapacity(16); // allocate 16 bytes to account for potential array header (safe-bet) - - lastFieldHeader = new WireDataFieldDescription(this, parent, fieldName, dataType, headerStart, dataStartOffset, dataSize); - return lastFieldHeader; - } + // -- offset dataStart calculations + final int fieldHeaderDataStart = buffer.position(); + final int dataStartOffset = (fieldHeaderDataStart - headerStart); + buffer.putInt(headerStart + 1, dataStartOffset); // write offset to dataStart public void putGenericArrayAsPrimitive(final DataType dataType, final Object[] data, final int nToCopy) { putArraySizeDescriptor(nToCopy); @@ -1616,41 +1592,22 @@ public BiFunction> getSerialiserLookupFunc return fieldSerialiserLookupFunction; } - @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) - protected E[] getGenericArrayAsBoxedPrimitive(final DataType dataType) { - final Object[] retVal; - getArraySizeDescriptor(); - switch (dataType) { - case BOOL: - retVal = GenericsHelper.toObject(buffer.getBooleanArray()); - break; - case BYTE: - retVal = GenericsHelper.toObject(buffer.getByteArray()); - break; - case CHAR: - retVal = GenericsHelper.toObject(buffer.getCharArray()); - break; - case SHORT: - retVal = GenericsHelper.toObject(buffer.getShortArray()); - break; - case INT: - retVal = GenericsHelper.toObject(buffer.getIntArray()); - break; - case LONG: - retVal = GenericsHelper.toObject(buffer.getLongArray()); - break; - case FLOAT: - retVal = GenericsHelper.toObject(buffer.getFloatArray()); - break; - case DOUBLE: - retVal = GenericsHelper.toObject(buffer.getDoubleArray()); - break; - case STRING: - retVal = buffer.getStringArray(); - break; - default: - throw new IllegalArgumentException("type not implemented - " + dataType); - } + @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) + protected E[] getGenericArrayAsBoxedPrimitive(final DataType dataType) { + final Object[] retVal; + getArraySizeDescriptor(); + retVal = switch (dataType) { + case BOOL -> GenericsHelper.toObject(buffer.getBooleanArray()); + case BYTE -> GenericsHelper.toObject(buffer.getByteArray()); + case CHAR -> GenericsHelper.toObject(buffer.getCharArray()); + case SHORT -> GenericsHelper.toObject(buffer.getShortArray()); + case INT -> GenericsHelper.toObject(buffer.getIntArray()); + case LONG -> GenericsHelper.toObject(buffer.getLongArray()); + case FLOAT -> GenericsHelper.toObject(buffer.getFloatArray()); + case DOUBLE -> GenericsHelper.toObject(buffer.getDoubleArray()); + case STRING -> buffer.getStringArray(); + default -> throw new IllegalArgumentException("type not implemented - " + dataType); + }; return (E[]) retVal; } diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/ClassFieldDescription.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/ClassFieldDescription.java index dbf56638..d0437853 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/ClassFieldDescription.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/ClassFieldDescription.java @@ -198,10 +198,9 @@ public boolean equals(final Object obj) { if (this == obj) { return true; } - if (!(obj instanceof FieldDescription)) { + if (!(obj instanceof FieldDescription other)) { return false; } - final FieldDescription other = (FieldDescription) obj; if (this.getDataType() != other.getDataType()) { return false; } diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/CmwLightSerialiser.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/CmwLightSerialiser.java index 206e8ac5..6742dff4 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/CmwLightSerialiser.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/CmwLightSerialiser.java @@ -21,7 +21,7 @@ /** * Light-weight open-source implementation of a (de-)serialiser that is binary-compatible to the serialiser used by CMW, * a proprietary closed-source middleware used in some accelerator laboratories. - * + *

    * N.B. this implementation is intended only for performance/functionality comparison and to enable a backward compatible * transition to the {@link BinarySerialiser} implementation which is a bit more flexible, * has some additional (optional) features, and a better IO performance. See the corresponding benchmarks for details; diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/FastByteBuffer.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/FastByteBuffer.java index 0d820890..fec64c78 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/FastByteBuffer.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/FastByteBuffer.java @@ -17,15 +17,15 @@ /** * FastByteBuffer implementation based on JVM 'Unsafe' Class. based on: - * https://mechanical-sympathy.blogspot.com/2012/07/native-cc-like-performance-for-java.html - * http://java-performance.info/various-methods-of-binary-serialization-in-java/ - * + * ... + * ... + *

    * All accesses are range checked, because the performance impact was determined to be negligible. - * + *

    * Read operations return "IndexOutOfBoundsException" if there are not enough bytes left in the buffer. * For primitive types, the check can be done before, but for arrays and strings the size field has to be read first. * Therefore, the position after a failed non-primitive read is not necessarily the position before the read attempt. - * + *

    * When there is not enough space for a write operation, the behaviour depends on the autoRange and byteArrayCache * variables. If autoRange is false, the operation returns an IndexOutOfBounds exception and the position is set to the * position before the operation. For Strings there is a worst case space estimate being done, so an operation might diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/Field.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/Field.java index 98a4a648..1e9827ae 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/Field.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/Field.java @@ -225,72 +225,100 @@ public short getShort(final Object classReference) { } } - /** @return {@code Class} object that identifies the declared type for this {@code Field} object. */ + /** + * @return {@code Class} object that identifies the declared type for this {@code Field} object. + */ public final Class getType() { return jdkField.getType(); } - /** @return {@code true} if the field is defined with the {@code abstract} modifier, {@code false} otherwise. */ + /** + * @return {@code true} if the field is defined with the {@code abstract} modifier, {@code false} otherwise. + */ public final boolean isAbstract() { return Modifier.isAbstract(jdkField.getModifiers()); } - /** @return {@code true} if the field is defined with the {@code final} modifier, {@code false} otherwise. */ + /** + * @return {@code true} if the field is defined with the {@code final} modifier, {@code false} otherwise. + */ public final boolean isFinal() { return Modifier.isFinal(jdkField.getModifiers()); } - /** @return @return {@code true} if the field is defined with the {@code native} modifier, {@code false} otherwise. */ + /** + * @return @return {@code true} if the field is defined with the {@code native} modifier, {@code false} otherwise. + */ public final boolean isNative() { return Modifier.isNative(jdkField.getModifiers()); } - /** @return {@code true} if the field is defined with the {@code private} modifier, {@code false} otherwise. */ + /** + * @return {@code true} if the field is defined with the {@code private} modifier, {@code false} otherwise. + */ public final boolean isPackagePrivate() { return !isPrivate() && !isProtected() && !isPublic(); } - /** @return {@code true} if the field is a primitive (e.g. boolean, int, .., float, double value, {@code false} otherwise. */ + /** + * @return {@code true} if the field is a primitive (e.g. boolean, int, .., float, double value, {@code false} otherwise. + */ public final boolean isPrimitive() { return primitive; } - /** @return {@code true} if the field is defined with the {@code private} modifier, {@code false} otherwise. */ + /** + * @return {@code true} if the field is defined with the {@code private} modifier, {@code false} otherwise. + */ public final boolean isPrivate() { return Modifier.isPrivate(jdkField.getModifiers()); } - /** @return {@code true} if the field is defined with the {@code protected} modifier, {@code false} otherwise. */ + /** + * @return {@code true} if the field is defined with the {@code protected} modifier, {@code false} otherwise. + */ public final boolean isProtected() { return Modifier.isProtected(jdkField.getModifiers()); } - /** @return {@code true} if the field is defined with the {@code public} modifier, {@code false} otherwise. */ + /** + * @return {@code true} if the field is defined with the {@code public} modifier, {@code false} otherwise. + */ public final boolean isPublic() { return Modifier.isPublic(jdkField.getModifiers()); } - /** @return {@code true} if the field is defined with the {@code static} modifier, {@code false} otherwise. */ + /** + * @return {@code true} if the field is defined with the {@code static} modifier, {@code false} otherwise. + */ public final boolean isStatic() { return Modifier.isStatic(jdkField.getModifiers()); } - /** @return {@code true} if the field is defined with the {@code strictfp} modifier, {@code false} otherwise. */ + /** + * @return {@code true} if the field is defined with the {@code strictfp} modifier, {@code false} otherwise. + */ public final boolean isStrict() { return Modifier.isStrict(jdkField.getModifiers()); } - /** @return {@code true} if the field is defined with the {@code synchronised} modifier, {@code false} otherwise. */ + /** + * @return {@code true} if the field is defined with the {@code synchronised} modifier, {@code false} otherwise. + */ public final boolean isSynchronized() { return Modifier.isSynchronized(jdkField.getModifiers()); } - /** @return {@code true} if the field is defined with the {@code transient} modifier, {@code false} otherwise. */ + /** + * @return {@code true} if the field is defined with the {@code transient} modifier, {@code false} otherwise. + */ public final boolean isTransient() { return Modifier.isTransient(jdkField.getModifiers()); } - /** @return {@code true} if the field is defined with the {@code volatile} modifier, {@code false} otherwise. */ + /** + * @return {@code true} if the field is defined with the {@code volatile} modifier, {@code false} otherwise. + */ public final boolean isVolatile() { return Modifier.isVolatile(jdkField.getModifiers()); } @@ -478,12 +506,12 @@ public T getAnnotation(@NotNull final Class annotation } @Override - public final Annotation[] getAnnotations() { + public final Annotation @NotNull[] getAnnotations() { return getDeclaredAnnotations(); } @Override - public Annotation[] getDeclaredAnnotations() { + public Annotation @NotNull[] getDeclaredAnnotations() { if (declaredAnnotations == null) { declaredAnnotations = jdkField.getDeclaredAnnotations(); } diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/JsonSerialiser.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/JsonSerialiser.java index 8538f315..c6fef47d 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/JsonSerialiser.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/JsonSerialiser.java @@ -35,7 +35,7 @@ public class JsonSerialiser implements IoSerialiser { public static final char QUOTE = '\"'; private static final String NULL = "null"; private static final String ASSIGN = ": "; - private static final String LINE_BREAK = System.getProperty("line.separator"); + private static final String LINE_BREAK = System.lineSeparator(); public static final String UNCHECKED = "unchecked"; private final StringBuilder builder = new StringBuilder(DEFAULT_INITIAL_CAPACITY); // NOPMD private IoBuffer buffer; @@ -795,14 +795,14 @@ public WireDataFieldDescription putFieldHeader(final FieldDescription fieldDescr @Override public WireDataFieldDescription putFieldHeader(final String fieldName, final DataType dataType) { - lastFieldHeader = new WireDataFieldDescription(this, parent, fieldName.hashCode(), fieldName, dataType, -1, 1, -1); + lastFieldHeader = new WireDataFieldDescription(this, parent, fieldName, dataType, -1, 1, -1); queryFieldName = fieldName; return lastFieldHeader; } @Override public void putHeaderInfo(final FieldDescription... field) { - if (builder.length() > 0) { + if (!builder.isEmpty()) { final byte[] outputStrBytes = builder.toString().getBytes(StandardCharsets.UTF_8); buffer.ensureAdditionalCapacity(outputStrBytes.length); System.arraycopy(outputStrBytes, 0, buffer.elements(), buffer.position(), outputStrBytes.length); @@ -829,7 +829,7 @@ public void putStartMarker(final FieldDescription fieldDescription) { } public void serialiseObject(final Object obj) { - if (builder.length() > 0) { + if (!builder.isEmpty()) { final byte[] outputStrBytes = builder.toString().getBytes(StandardCharsets.UTF_8); buffer.ensureAdditionalCapacity(outputStrBytes.length); System.arraycopy(outputStrBytes, 0, buffer.elements(), buffer.position(), outputStrBytes.length); diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/ProtocolInfo.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/ProtocolInfo.java index 73225454..295253fe 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/ProtocolInfo.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/ProtocolInfo.java @@ -20,10 +20,9 @@ public ProtocolInfo(final IoSerialiser source, final WireDataFieldDescription fi @Override public boolean equals(final Object obj) { - if (!(obj instanceof ProtocolInfo)) { + if (!(obj instanceof ProtocolInfo other)) { return false; } - final ProtocolInfo other = (ProtocolInfo) obj; return other.isCompatible(); } diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/WireDataFieldDescription.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/WireDataFieldDescription.java index ad76780d..db225f38 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/WireDataFieldDescription.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/WireDataFieldDescription.java @@ -66,10 +66,9 @@ public boolean equals(final Object obj) { if (this == obj) { return true; } - if (!(obj instanceof FieldDescription)) { + if (!(obj instanceof FieldDescription other)) { return false; } - FieldDescription other = (FieldDescription) obj; if (this.getDataType() != other.getDataType()) { return false; } @@ -170,63 +169,35 @@ public void setFieldUnit(final String fieldUnit) { */ public Object data(DataType... overwriteType) { ioSerialiser.setQueryFieldName(fieldName, fieldDataStart); - switch (overwriteType.length == 0 ? this.dataType : overwriteType[0]) { - case START_MARKER: - case END_MARKER: - return null; - case BOOL: - return ioSerialiser.getBoolean(); - case BYTE: - return ioSerialiser.getByte(); - case SHORT: - return ioSerialiser.getShort(); - case INT: - return ioSerialiser.getInt(); - case LONG: - return ioSerialiser.getLong(); - case FLOAT: - return ioSerialiser.getFloat(); - case DOUBLE: - return ioSerialiser.getDouble(); - case CHAR: - return ioSerialiser.getChar(); - case STRING: - return ioSerialiser.getString(); - case BOOL_ARRAY: - return ioSerialiser.getBooleanArray(); - case BYTE_ARRAY: - return ioSerialiser.getByteArray(); - case SHORT_ARRAY: - return ioSerialiser.getShortArray(); - case INT_ARRAY: - return ioSerialiser.getIntArray(); - case LONG_ARRAY: - return ioSerialiser.getLongArray(); - case FLOAT_ARRAY: - return ioSerialiser.getFloatArray(); - case DOUBLE_ARRAY: - return ioSerialiser.getDoubleArray(); - case CHAR_ARRAY: - return ioSerialiser.getCharArray(); - case STRING_ARRAY: - return ioSerialiser.getStringArray(); - case ENUM: - return ioSerialiser.getEnum(null); - case LIST: - return ioSerialiser.getList(null); - case MAP: - return ioSerialiser.getMap(null); - case QUEUE: - return ioSerialiser.getQueue(null); - case SET: - return ioSerialiser.getSet(null); - case COLLECTION: - return ioSerialiser.getCollection(null); - case OTHER: - return ioSerialiser.getCustomData(null); - default: - throw new IllegalStateException("unknown dataType = " + dataType); - } + return switch (overwriteType.length == 0 ? this.dataType : overwriteType[0]) { + case START_MARKER, END_MARKER -> null; + case BOOL -> ioSerialiser.getBoolean(); + case BYTE -> ioSerialiser.getByte(); + case SHORT -> ioSerialiser.getShort(); + case INT -> ioSerialiser.getInt(); + case LONG -> ioSerialiser.getLong(); + case FLOAT -> ioSerialiser.getFloat(); + case DOUBLE -> ioSerialiser.getDouble(); + case CHAR -> ioSerialiser.getChar(); + case STRING -> ioSerialiser.getString(); + case BOOL_ARRAY -> ioSerialiser.getBooleanArray(); + case BYTE_ARRAY -> ioSerialiser.getByteArray(); + case SHORT_ARRAY -> ioSerialiser.getShortArray(); + case INT_ARRAY -> ioSerialiser.getIntArray(); + case LONG_ARRAY -> ioSerialiser.getLongArray(); + case FLOAT_ARRAY -> ioSerialiser.getFloatArray(); + case DOUBLE_ARRAY -> ioSerialiser.getDoubleArray(); + case CHAR_ARRAY -> ioSerialiser.getCharArray(); + case STRING_ARRAY -> ioSerialiser.getStringArray(); + case ENUM -> ioSerialiser.getEnum(null); + case LIST -> ioSerialiser.getList(null); + case MAP -> ioSerialiser.getMap(null); + case QUEUE -> ioSerialiser.getQueue(null); + case SET -> ioSerialiser.getSet(null); + case COLLECTION -> ioSerialiser.getCollection(null); + case OTHER -> ioSerialiser.getCustomData(null); + default -> throw new IllegalStateException("unknown dataType = " + dataType); + }; } /** diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/iobuffer/DataSetSerialiser.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/iobuffer/DataSetSerialiser.java index f512ab5d..e1229edd 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/iobuffer/DataSetSerialiser.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/iobuffer/DataSetSerialiser.java @@ -30,9 +30,9 @@ * Class to efficiently serialise and de-serialise DataSet objects into binary byte arrays. The performance can be tuned * through: *

      - *
    • using floats (ie. memory-IO vs network-IO bound serialisation), or
    • + *
    • using floats (i.e. memory-IO vs network-IO bound serialisation), or
    • *
    • via {@link #setDataLablesSerialised(boolean)} (default: true) to control whether data labels and styles shall be processed
    • - *
    • via {@link #setMetaDataSerialised(boolean)} (default: true) to control whether meta data shall be processed
    • + *
    • via {@link #setMetaDataSerialised(boolean)} (default: true) to control whether metadata shall be processed
    • *
    * * @author rstein @@ -203,28 +203,18 @@ protected static int getDimIndex(String fieldName, String prefix) { } protected static double[] getDoubleArray(final IoSerialiser ioSerialiser, final double[] origArray, final DataType dataType) { - switch (dataType) { - case BOOL_ARRAY: - return GenericsHelper.toDoublePrimitive(ioSerialiser.getBooleanArray()); - case BYTE_ARRAY: - return GenericsHelper.toDoublePrimitive(ioSerialiser.getByteArray()); - case SHORT_ARRAY: - return GenericsHelper.toDoublePrimitive(ioSerialiser.getShortArray()); - case INT_ARRAY: - return GenericsHelper.toDoublePrimitive(ioSerialiser.getIntArray()); - case LONG_ARRAY: - return GenericsHelper.toDoublePrimitive(ioSerialiser.getLongArray()); - case FLOAT_ARRAY: - return GenericsHelper.toDoublePrimitive(ioSerialiser.getFloatArray()); - case DOUBLE_ARRAY: - return ioSerialiser.getDoubleArray(origArray); - case CHAR_ARRAY: - return GenericsHelper.toDoublePrimitive(ioSerialiser.getCharArray()); - case STRING_ARRAY: - return GenericsHelper.toDoublePrimitive(ioSerialiser.getStringArray()); - default: - throw new IllegalArgumentException("dataType '" + dataType + "' is not an array"); - } + return switch (dataType) { + case BOOL_ARRAY -> GenericsHelper.toDoublePrimitive(ioSerialiser.getBooleanArray()); + case BYTE_ARRAY -> GenericsHelper.toDoublePrimitive(ioSerialiser.getByteArray()); + case SHORT_ARRAY -> GenericsHelper.toDoublePrimitive(ioSerialiser.getShortArray()); + case INT_ARRAY -> GenericsHelper.toDoublePrimitive(ioSerialiser.getIntArray()); + case LONG_ARRAY -> GenericsHelper.toDoublePrimitive(ioSerialiser.getLongArray()); + case FLOAT_ARRAY -> GenericsHelper.toDoublePrimitive(ioSerialiser.getFloatArray()); + case DOUBLE_ARRAY -> ioSerialiser.getDoubleArray(origArray); + case CHAR_ARRAY -> GenericsHelper.toDoublePrimitive(ioSerialiser.getCharArray()); + case STRING_ARRAY -> GenericsHelper.toDoublePrimitive(ioSerialiser.getStringArray()); + default -> throw new IllegalArgumentException("dataType '" + dataType + "' is not an array"); + }; } protected void parseDataLabels(final DataSetBuilder builder, final FieldDescription fieldRoot) { @@ -326,42 +316,6 @@ protected void writeDataLabelsToStream(final DataSet dataSet) { if ((style != null) && !style.isEmpty()) { styleMap.put(index, style); } - } - if (!styleMap.isEmpty()) { - ioSerialiser.put(DATA_STYLES, styleMap, Integer.class, String.class); - } - } - - protected void writeHeaderDataToStream(final DataSet dataSet) { - // common header data - ioSerialiser.put(DATA_SET_NAME, dataSet.getName()); - ioSerialiser.put(DIMENSIONS, dataSet.getDimension()); - final List axisDescriptions = dataSet.getAxisDescriptions(); - StringBuilder builder = new StringBuilder(60); - for (int i = 0; i < axisDescriptions.size(); i++) { - builder.setLength(0); - final String prefix = builder.append(AXIS).append(i).append('.').toString(); - builder.setLength(0); - final String name = builder.append(prefix).append(NAME).toString(); - builder.setLength(0); - final String unit = builder.append(prefix).append(UNIT).toString(); - builder.setLength(0); - final String minName = builder.append(prefix).append(MIN).toString(); - builder.setLength(0); - final String maxName = builder.append(prefix).append(MAX).toString(); - - ioSerialiser.put(name, dataSet.getAxisDescription(i).getName()); - ioSerialiser.put(unit, dataSet.getAxisDescription(i).getUnit()); - ioSerialiser.put(minName, dataSet.getAxisDescription(i).getMin()); - ioSerialiser.put(maxName, dataSet.getAxisDescription(i).getMax()); - } - } - - protected void writeMetaDataToStream(final DataSet dataSet) { - if (!(dataSet instanceof DataSetMetaData)) { - return; - } - final DataSetMetaData metaDataSet = (DataSetMetaData) dataSet; ioSerialiser.put(INFO_LIST, metaDataSet.getInfoList().toArray(new String[0])); ioSerialiser.put(WARNING_LIST, metaDataSet.getWarningList().toArray(new String[0])); @@ -369,58 +323,48 @@ protected void writeMetaDataToStream(final DataSet dataSet) { ioSerialiser.put(META_INFO, metaDataSet.getMetaInfo(), String.class, String.class); } - /** - * @param dataSet to be exported - */ - protected void writeNumericBinaryDataToBufferDouble(final DataSet dataSet) { - final int nDim = dataSet.getDimension(); - if (dataSet instanceof GridDataSet) { - GridDataSet gridDataSet = (GridDataSet) dataSet; - for (int dimIndex = 0; dimIndex < nDim; dimIndex++) { - final boolean gridDimension = dimIndex < gridDataSet.getNGrid(); - final int nsamples = gridDimension ? gridDataSet.getShape(dimIndex) : dataSet.getDataCount(); - final double[] values = gridDimension ? gridDataSet.getGridValues(dimIndex) : dataSet.getValues(dimIndex); - ioSerialiser.put(ARRAY_PREFIX + dimIndex, values, nsamples); - } - return; // GridDataSet does not provide errors - } - for (int dimIndex = 0; dimIndex < nDim; dimIndex++) { - final int nsamples = dataSet.getDataCount(); - ioSerialiser.put(ARRAY_PREFIX + dimIndex, dataSet.getValues(dimIndex), nsamples); - } - if (!(dataSet instanceof DataSetError)) { - return; // data set does not have any error definition - } - final DataSetError ds = (DataSetError) dataSet; - for (int dimIndex = 0; dimIndex < nDim; dimIndex++) { - final int nsamples = dataSet.getDataCount(); - switch (ds.getErrorType(dimIndex)) { - case SYMMETRIC: - ioSerialiser.put(EP_PREFIX + dimIndex, ds.getErrorsPositive(dimIndex), nsamples); - break; - case ASYMMETRIC: - ioSerialiser.put(EN_PREFIX + dimIndex, ds.getErrorsNegative(dimIndex), nsamples); - ioSerialiser.put(EP_PREFIX + dimIndex, ds.getErrorsPositive(dimIndex), nsamples); - break; - case NO_ERROR: - default: - break; + ioSerialiser.put(INFO_LIST, metaDataSet.getInfoList().toArray(new String[0])); + ioSerialiser.put(WARNING_LIST, metaDataSet.getWarningList().toArray(new String[0])); + ioSerialiser.put(ERROR_LIST, metaDataSet.getErrorList().toArray(new String[0])); + ioSerialiser.put(META_INFO, metaDataSet.getMetaInfo(), String.class, String.class); } - } - } - /** - * @param dataSet to be exported - */ - protected void writeNumericBinaryDataToBufferFloat(final DataSet dataSet) { - final int nDim = dataSet.getDimension(); - if (dataSet instanceof GridDataSet) { - GridDataSet gridDataSet = (GridDataSet) dataSet; - for (int dimIndex = 0; dimIndex < nDim; dimIndex++) { - final boolean gridDimension = dimIndex < gridDataSet.getNGrid(); - final int nsamples = gridDimension ? gridDataSet.getShape(dimIndex) : dataSet.getDataCount(); - final float[] values = MathUtils.toFloats(gridDimension ? gridDataSet.getGridValues(dimIndex) : dataSet.getValues(dimIndex)); - ioSerialiser.put(ARRAY_PREFIX + dimIndex, values, nsamples); + /** + * @param dataSet to be exported + */ + protected void writeNumericBinaryDataToBufferDouble(final DataSet dataSet) { + final int nDim = dataSet.getDimension(); + if (dataSet instanceof GridDataSet gridDataSet) { + for (int dimIndex = 0; dimIndex < nDim; dimIndex++) { + final boolean gridDimension = dimIndex < gridDataSet.getNGrid(); + final int nsamples = gridDimension ? gridDataSet.getShape(dimIndex) : dataSet.getDataCount(); + final double[] values = gridDimension ? gridDataSet.getGridValues(dimIndex) : dataSet.getValues(dimIndex); + ioSerialiser.put(ARRAY_PREFIX + dimIndex, values, nsamples); + } + return; // GridDataSet does not provide errors + } + for (int dimIndex = 0; dimIndex < nDim; dimIndex++) { + final int nsamples = dataSet.getDataCount(); + ioSerialiser.put(ARRAY_PREFIX + dimIndex, dataSet.getValues(dimIndex), nsamples); + } + if (!(dataSet instanceof DataSetError ds)) { + return; // data set does not have any error definition + } + for (int dimIndex = 0; dimIndex < nDim; dimIndex++) { + final int nsamples = dataSet.getDataCount(); + switch (ds.getErrorType(dimIndex)) { + case SYMMETRIC: + ioSerialiser.put(EP_PREFIX + dimIndex, ds.getErrorsPositive(dimIndex), nsamples); + break; + case ASYMMETRIC: + ioSerialiser.put(EN_PREFIX + dimIndex, ds.getErrorsNegative(dimIndex), nsamples); + ioSerialiser.put(EP_PREFIX + dimIndex, ds.getErrorsPositive(dimIndex), nsamples); + break; + case NO_ERROR: + default: + break; + } + } } return; // GridDataSet does not provide errors } @@ -429,27 +373,44 @@ protected void writeNumericBinaryDataToBufferFloat(final DataSet dataSet) { ioSerialiser.put(ARRAY_PREFIX + dimIndex, MathUtils.toFloats(dataSet.getValues(dimIndex)), nsamples); } - if (!(dataSet instanceof DataSetError)) { - return; // data set does not have any error definition - } - - final DataSetError ds = (DataSetError) dataSet; - for (int dimIndex = 0; dimIndex < nDim; dimIndex++) { - final int nsamples = dataSet.getDataCount(); - switch (ds.getErrorType(dimIndex)) { - case SYMMETRIC: - ioSerialiser.put(EP_PREFIX + dimIndex, MathUtils.toFloats(ds.getErrorsPositive(dimIndex)), nsamples); - break; - case ASYMMETRIC: - ioSerialiser.put(EN_PREFIX + dimIndex, MathUtils.toFloats(ds.getErrorsNegative(dimIndex)), nsamples); - ioSerialiser.put(EP_PREFIX + dimIndex, MathUtils.toFloats(ds.getErrorsPositive(dimIndex)), nsamples); - break; - case NO_ERROR: - default: - break; + /** + * @param dataSet to be exported + */ + protected void writeNumericBinaryDataToBufferFloat(final DataSet dataSet) { + final int nDim = dataSet.getDimension(); + if (dataSet instanceof GridDataSet gridDataSet) { + for (int dimIndex = 0; dimIndex < nDim; dimIndex++) { + final boolean gridDimension = dimIndex < gridDataSet.getNGrid(); + final int nsamples = gridDimension ? gridDataSet.getShape(dimIndex) : dataSet.getDataCount(); + final float[] values = MathUtils.toFloats(gridDimension ? gridDataSet.getGridValues(dimIndex) : dataSet.getValues(dimIndex)); + ioSerialiser.put(ARRAY_PREFIX + dimIndex, values, nsamples); + } + return; // GridDataSet does not provide errors + } + for (int dimIndex = 0; dimIndex < nDim; dimIndex++) { + final int nsamples = dataSet.getDataCount(); + ioSerialiser.put(ARRAY_PREFIX + dimIndex, MathUtils.toFloats(dataSet.getValues(dimIndex)), nsamples); + } + + if (!(dataSet instanceof DataSetError ds)) { + return; // data set does not have any error definition + } + for (int dimIndex = 0; dimIndex < nDim; dimIndex++) { + final int nsamples = dataSet.getDataCount(); + switch (ds.getErrorType(dimIndex)) { + case SYMMETRIC: + ioSerialiser.put(EP_PREFIX + dimIndex, MathUtils.toFloats(ds.getErrorsPositive(dimIndex)), nsamples); + break; + case ASYMMETRIC: + ioSerialiser.put(EN_PREFIX + dimIndex, MathUtils.toFloats(ds.getErrorsNegative(dimIndex)), nsamples); + ioSerialiser.put(EP_PREFIX + dimIndex, MathUtils.toFloats(ds.getErrorsPositive(dimIndex)), nsamples); + break; + case NO_ERROR: + default: + break; + } + } } - } - } private void parseHeader(final IoSerialiser ioSerialiser, final DataSetBuilder builder, FieldDescription fieldDescription) { final String fieldName = fieldDescription.getFieldName(); diff --git a/serialiser/src/test/java/io/opencmw/serialiser/IoClassSerialiserTests.java b/serialiser/src/test/java/io/opencmw/serialiser/IoClassSerialiserTests.java index 78cca905..d4793ed1 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/IoClassSerialiserTests.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/IoClassSerialiserTests.java @@ -70,10 +70,9 @@ protected void addCustomClassSerialiser(final IoClassSerialiser serialiser) { // provide a writer function final FieldSerialiser.TriConsumer writeFunction = (io, obj, field) -> { final Object localObj = field == null || field.getField() == null ? obj : field.getField().get(obj); - if (!(localObj instanceof CustomClass)) { + if (!(localObj instanceof CustomClass customClass)) { throw new IllegalArgumentException("object " + obj + " is not of type CustomClass"); } - CustomClass customClass = (CustomClass) localObj; // place custom elements/composites etc. here - N.B. ordering is of paramount importance since // these raw fields are not preceded by field headers io.getBuffer().putDouble(customClass.testDouble); @@ -94,10 +93,9 @@ protected void addCustomClassSerialiser(final IoClassSerialiser serialiser) { if (sourceField == null) { return new CustomClass(doubleVal, intVal, str); } else { - if (!(sourceField instanceof CustomClass)) { + if (!(sourceField instanceof CustomClass customClass)) { throw new IllegalArgumentException("object " + obj + " is not of type CustomClass"); } - CustomClass customClass = (CustomClass) sourceField; customClass.testDouble = doubleVal; customClass.testInt = intVal; customClass.testString = str; @@ -162,7 +160,6 @@ void testNestedClass() { @ParameterizedTest(name = "IoBuffer class - {0}") @ValueSource(classes = { ByteBuffer.class, FastByteBuffer.class }) - @SuppressWarnings("unchecked") void testGenericSerialiserIdentity(final Class bufferClass) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { assertNotNull(bufferClass, "bufferClass being not null"); assertNotNull(bufferClass.getConstructor(int.class), "Constructor(Integer) present"); @@ -243,7 +240,7 @@ void testGenericSerialiserIdentity(final Class bufferClass) assertTrue(destinationClass.dataSetSet.stream().anyMatch(ds -> ds.getName().equals("SetDataSet#1"))); assertTrue(destinationClass.dataSetSet.stream().anyMatch(ds -> ds.getName().equals("SetDataSet#2"))); - //assertEquals(sourceClass.dataSetQueue, destinationClass.dataSetQueue); + // assertEquals(sourceClass.dataSetQueue, destinationClass.dataSetQueue); assertTrue(destinationClass.dataSetQueue.stream().anyMatch(ds -> ds.getName().equals("QueueDataSet#1"))); assertTrue(destinationClass.dataSetQueue.stream().anyMatch(ds -> ds.getName().equals("QueueDataSet#2"))); @@ -336,7 +333,6 @@ void testGenericSerialiserIdentityMultiArray(final Class buf @ParameterizedTest(name = "IoBuffer class - {0}") @ValueSource(classes = { ByteBuffer.class, FastByteBuffer.class }) - @SuppressWarnings("unchecked") void testGenericSerialiserIdentityCollectionOfCustomTypes(final Class bufferClass) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { assertNotNull(bufferClass, "bufferClass being not null"); assertNotNull(bufferClass.getConstructor(int.class), "Constructor(Integer) present"); @@ -511,9 +507,8 @@ public NestedClass() { public boolean equals(final Object o) { if (this == o) return true; - if (!(o instanceof NestedClass)) + if (!(o instanceof NestedClass that)) return false; - final NestedClass that = (NestedClass) o; return i == that.i && Objects.equals(class1, that.class1) && Objects.equals(class2, that.class2) && Objects.equals(class3, that.class3); } @@ -548,9 +543,8 @@ public String toString() { public boolean equals(final Object o) { if (this == o) return true; - if (!(o instanceof NonStaticInnerClass)) + if (!(o instanceof NonStaticInnerClass that)) return false; - final NonStaticInnerClass that = (NonStaticInnerClass) o; return j == that.j; } diff --git a/serialiser/src/test/java/io/opencmw/serialiser/benchmark/DataSetSerialiserBenchmark.java b/serialiser/src/test/java/io/opencmw/serialiser/benchmark/DataSetSerialiserBenchmark.java index ea49b772..fc79f032 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/benchmark/DataSetSerialiserBenchmark.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/benchmark/DataSetSerialiserBenchmark.java @@ -18,7 +18,7 @@ /** * Simple benchmark to verify that the in-place DataSet (de-)serialiser is not significantly slower than creating a new DataSet - * + *

    * Benchmark Mode Cnt Score Error Units * DataSetSerialiserBenchmark.serialiserRoundTripByteBufferInplace thrpt 10 5971.023 ± 100.145 ops/s * DataSetSerialiserBenchmark.serialiserRoundTripByteBufferNewDataSet thrpt 10 5652.462 ± 114.474 ops/s diff --git a/serialiser/src/test/java/io/opencmw/serialiser/benchmark/JsonSelectionBenchmark.java b/serialiser/src/test/java/io/opencmw/serialiser/benchmark/JsonSelectionBenchmark.java index 38351a79..974fe383 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/benchmark/JsonSelectionBenchmark.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/benchmark/JsonSelectionBenchmark.java @@ -26,10 +26,10 @@ /** * simple benchmark to evaluate various JSON libraries. * N.B. This is not intended as a complete JSON serialiser evaluation but to indicate some rough trends. - * + *

    * testClassId 1: being a string-heavy test data class * testClassId 2: being a numeric-data-heavy test data class - * + *

    * Benchmark (testClassId) Mode Cnt Score Error Units * JsonSelectionBenchmark.pojoFastJson string-heavy thrpt 10 12857.850 ± 109.050 ops/s * JsonSelectionBenchmark.pojoFastJson numeric-heavy thrpt 10 91.458 ± 0.437 ops/s @@ -41,7 +41,7 @@ * JsonSelectionBenchmark.pojoJsonIter numeric-heavy thrpt 10 86.629 ± 1.122 ops/s * JsonSelectionBenchmark.pojoJsonIterCodeGen string-heavy thrpt 10 41048.034 ± 396.628 ops/s * JsonSelectionBenchmark.pojoJsonIterCodeGen numeric-heavy thrpt 10 377.412 ± 9.755 ops/s - * + *

    * Process finished with exit code 0 */ @State(Scope.Benchmark) diff --git a/serialiser/src/test/java/io/opencmw/serialiser/benchmark/ReflectionBenchmark.java b/serialiser/src/test/java/io/opencmw/serialiser/benchmark/ReflectionBenchmark.java index b37286a1..0be2ea1a 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/benchmark/ReflectionBenchmark.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/benchmark/ReflectionBenchmark.java @@ -14,7 +14,7 @@ /** * Benchmark to compare, test and rationalise some assumptions that went into the serialiser refactoring - * + *

    * last test output (openjdk 11.0.7 2020-04-14, took 24 min): * Benchmark Mode Cnt Score Error Units * ReflectionBenchmark.fieldAccess1ViaMethod thrpt 10 368156046.779 ± 29954108.137 ops/s diff --git a/serialiser/src/test/java/io/opencmw/serialiser/benchmark/SerialiserAssumptionsBenchmark.java b/serialiser/src/test/java/io/opencmw/serialiser/benchmark/SerialiserAssumptionsBenchmark.java index bf97e2aa..4d70e293 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/benchmark/SerialiserAssumptionsBenchmark.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/benchmark/SerialiserAssumptionsBenchmark.java @@ -18,7 +18,7 @@ /** * Benchmark to compare, test and rationalise some assumptions that went into the serialiser refactoring - * + *

    * last test output (openjdk 11.0.7 2020-04-14, took ~1:15h): Benchmark Mode Cnt Score Error Units SerialiserAssumptionsBenchmark.fluentDesignVoid thrpt 10 471049302.874 ± 38950975.384 ops/s diff --git a/serialiser/src/test/java/io/opencmw/serialiser/benchmark/SerialiserBenchmark.java b/serialiser/src/test/java/io/opencmw/serialiser/benchmark/SerialiserBenchmark.java index b6975753..734b8582 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/benchmark/SerialiserBenchmark.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/benchmark/SerialiserBenchmark.java @@ -23,7 +23,7 @@ * More thorough (JMH-based)) benchmark of various internal and external serialiser protocols. * Test consists of a simple repeated POJO->serialised->byte[] buffer -> de-serialisation -> POJO + comparison checks. * N.B. this isn't as precise as the JMH tests but gives a rough idea whether the protocol degraded or needs to be improved. - * + *

    * Benchmark (testClassId) Mode Cnt Score Error Units * SerialiserBenchmark.customCmwLight string-heavy thrpt 10 49954.479 ± 560.726 ops/s * SerialiserBenchmark.customCmwLight numeric-heavy thrpt 10 22433.828 ± 195.939 ops/s diff --git a/serialiser/src/test/java/io/opencmw/serialiser/benchmark/SerialiserQuickBenchmark.java b/serialiser/src/test/java/io/opencmw/serialiser/benchmark/SerialiserQuickBenchmark.java index fd1f20a8..d1ab3a0e 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/benchmark/SerialiserQuickBenchmark.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/benchmark/SerialiserQuickBenchmark.java @@ -13,7 +13,7 @@ * Simple (rough) benchmark of various internal and external serialiser protocols. * Test consists of a simple repeated POJO->serialised->byte[] buffer -> de-serialisation -> POJO + comparison checks. * N.B. this isn't as precise as the JMH tests but gives a rough idea whether the protocol degraded or needs to be improved. - * + *

    * Example output - numbers should be compared relatively (nIterations = 100000): * (openjdk 11.0.7 2020-04-14, ASCII-only, nSizePrimitiveArrays = 10, nSizeString = 100, nestedClassRecursion = 1) * [..] more string-heavy TestDataClass @@ -22,28 +22,28 @@ * - CMW Serializer (Map only) throughput = 220.2 MB/s for 6.3 kB per test run (took 2871.0 ms) * - CmwLight Serializer (Map only) throughput = 683.1 MB/s for 6.4 kB per test run (took 935.0 ms) * - IO Serializer (Map only) throughput = 810.0 MB/s for 7.4 kB per test run (took 908.0 ms) - * + *

    * - FlatBuffers (custom FlexBuffers) throughput = 173.7 MB/s for 6.1 kB per test run (took 3536.0 ms) * - CmwLight Serializer (custom) throughput = 460.5 MB/s for 6.4 kB per test run (took 1387.0 ms) * - IO Serializer (custom) throughput = 545.0 MB/s for 7.3 kB per test run (took 1344.0 ms) - * + *

    * - JSON Serializer (POJO) throughput = 53.8 MB/s for 5.2 kB per test run (took 9747.0 ms) * - CMW Serializer (POJO) throughput = 182.8 MB/s for 6.3 kB per test run (took 3458.0 ms) * - CmwLight Serializer (POJO) throughput = 329.2 MB/s for 6.3 kB per test run (took 1906.0 ms) * - IO Serializer (POJO) throughput = 374.9 MB/s for 7.2 kB per test run (took 1925.0 ms) - * - * [..] more primitive-array-heavy TestDataClass + *

    + * […] more primitive-array-heavy TestDataClass * (openjdk 11.0.7 2020-04-14, UTF8, nSizePrimitiveArrays = 1000, nSizeString = 0, nestedClassRecursion = 0) * - run 1 * - JSON Serializer (Map only) throughput = 350.7 MB/s for 34.3 kB per test run (took 9793.0 ms) * - CMW Serializer (Map only) throughput = 1.7 GB/s for 29.2 kB per test run (took 1755.0 ms) * - CmwLight Serializer (Map only) throughput = 6.7 GB/s for 29.2 kB per test run (took 437.0 ms) * - IO Serializer (Map only) throughput = 6.1 GB/s for 29.7 kB per test run (took 485.0 ms) - * + *

    * - FlatBuffers (custom FlexBuffers) throughput = 123.1 MB/s for 30.1 kB per test run (took 24467.0 ms) * - CmwLight Serializer (custom) throughput = 3.9 GB/s for 29.2 kB per test run (took 751.0 ms) * - IO Serializer (custom) throughput = 3.8 GB/s for 29.7 kB per test run (took 782.0 ms) - * + *

    * - JSON Serializer (POJO) throughput = 31.7 MB/s for 34.3 kB per test run (took 108415.0 ms) * - CMW Serializer (POJO) throughput = 1.5 GB/s for 29.2 kB per test run (took 1924.0 ms) * - CmwLight Serializer (POJO) throughput = 3.5 GB/s for 29.1 kB per test run (took 824.0 ms) diff --git a/serialiser/src/test/java/io/opencmw/serialiser/spi/BinarySerialiserTests.java b/serialiser/src/test/java/io/opencmw/serialiser/spi/BinarySerialiserTests.java index a336608b..c454e16b 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/spi/BinarySerialiserTests.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/spi/BinarySerialiserTests.java @@ -459,7 +459,7 @@ void testHeaderAndSpecialItems(final Class bufferClass) thro // header info assertEquals(positionBefore.removeFirst(), buffer.position()); ProtocolInfo headerInfo = ioSerialiser.checkHeaderInfo(); - assertNotEquals(headerInfo, new Object()); // silly comparison for coverage reasons + assertNotEquals(new Object(), headerInfo); // silly comparison for coverage reasons assertNotNull(headerInfo); assertEquals(BinarySerialiser.PROTOCOL_NAME, headerInfo.getProducerName()); assertEquals(BinarySerialiser.VERSION_MAJOR, headerInfo.getVersionMajor()); diff --git a/serialiser/src/test/java/io/opencmw/serialiser/spi/IoBufferTests.java b/serialiser/src/test/java/io/opencmw/serialiser/spi/IoBufferTests.java index 978d382c..cd9f71a0 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/spi/IoBufferTests.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/spi/IoBufferTests.java @@ -27,7 +27,7 @@ class IoBufferTests { protected static final double[] doubleTestArray = { Float.MAX_VALUE + 1.1e9, Float.MAX_VALUE + 1.2e9, Float.MAX_VALUE + 1.3e9f, -Float.MAX_VALUE - 1.1e9f, -Float.MAX_VALUE - 1.2e9f, Float.MAX_VALUE - 1.3e9f }; protected static final char[] charTestArray = { 'a', 'b', 'c', 'd' }; protected static final String[] stringTestArray = { "Is", "this", "the", "real", "life?", "Is", "this", "just", "fantasy?", "", null }; - protected static final String[] stringTestArrayNullAsEmpty = Arrays.stream(stringTestArray).map(s -> s == null ? "" : s).toArray(String[]::new); + protected static final String[] stringTestArrayNullAsEmpty = Arrays.stream(stringTestArray).map(s -> s == null ? "" : s).toArray(String[] ::new); private static final int BUFFER_SIZE = 1000; @ParameterizedTest(name = "IoBuffer class - {0}") @@ -166,7 +166,7 @@ void primitivesArraysASCII() { { final char[] chars = Character.toChars(0x1F701); final String fourByteCharacter = new String(chars); - String utf8TestString = "Γειά σου Κόσμε! - " + fourByteCharacter + " 語 \u00ea \u00f1 \u00fc + some normal ASCII character"; + String utf8TestString = "Γειά σου Κόσμε! - " + fourByteCharacter + " 語 ê ñ ü + some normal ASCII character"; buffer.reset(); assertDoesNotThrow(() -> buffer.putStringArray(stringTestArray, stringTestArray.length)); assertDoesNotThrow(() -> buffer.putStringArray(stringTestArray, -1)); @@ -221,17 +221,17 @@ void primitivesMixed(final Class bufferClass) throws NoSuchM buffer.flip(); assertTrue(buffer.getBoolean()); assertFalse(buffer.getBoolean()); - assertEquals(buffer.getByte(), (byte) 0xFE); - assertEquals(buffer.getShort(), (short) 43); + assertEquals((byte) 0xFE, buffer.getByte()); + assertEquals((short) 43, buffer.getShort()); assertEquals(1025, buffer.getInt()); - assertEquals(buffer.getLong(), largeLong); + assertEquals(largeLong, buffer.getLong()); assertEquals(1.3e10f, buffer.getFloat()); assertEquals(1.3e10f, buffer.getDouble()); assertEquals('@', buffer.getChar()); assertEquals((char) 513, buffer.getChar()); assertEquals("Hello World!", buffer.getStringISO8859()); assertEquals("Γειά σου Κόσμε!", buffer.getString()); - assertEquals(buffer.position(), position); + assertEquals(position, buffer.position()); } @ParameterizedTest(name = "IoBuffer class - {0}") @@ -253,12 +253,12 @@ void primitivesSimple(final Class bufferClass) throws NoSuch buffer.reset(); buffer.putByte((byte) 0xFE); buffer.flip(); - assertEquals(buffer.getByte(), (byte) 0xFE); + assertEquals((byte) 0xFE, buffer.getByte()); buffer.reset(); buffer.putShort((short) 43); buffer.flip(); - assertEquals(buffer.getShort(), (short) 43); + assertEquals((short) 43, buffer.getShort()); buffer.reset(); buffer.putInt(1025); @@ -269,7 +269,7 @@ void primitivesSimple(final Class bufferClass) throws NoSuch final long largeLong = (long) Integer.MAX_VALUE + (long) 10; buffer.putLong(largeLong); buffer.flip(); - assertEquals(buffer.getLong(), largeLong); + assertEquals(largeLong, buffer.getLong()); buffer.reset(); buffer.putFloat(1.3e10f); @@ -313,17 +313,17 @@ void primitivesSimpleInPlace(final Class bufferClass) throws assertFalse(buffer.getBoolean(0)); buffer.putByte(1, (byte) 0xFE); - assertEquals(buffer.getByte(1), (byte) 0xFE); + assertEquals((byte) 0xFE, buffer.getByte(1)); buffer.putShort(2, (short) 43); - assertEquals(buffer.getShort(2), (short) 43); + assertEquals((short) 43, buffer.getShort(2)); buffer.putInt(3, 1025); assertEquals(1025, buffer.getInt(3)); final long largeLong = (long) Integer.MAX_VALUE + (long) 10; buffer.putLong(4, largeLong); - assertEquals(buffer.getLong(4), largeLong); + assertEquals(largeLong, buffer.getLong(4)); buffer.putFloat(5, 1.3e10f); assertEquals(1.3e10f, buffer.getFloat(5)); diff --git a/serialiser/src/test/java/io/opencmw/serialiser/spi/JsonSerialiserTests.java b/serialiser/src/test/java/io/opencmw/serialiser/spi/JsonSerialiserTests.java index 369e02dc..a42fa992 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/spi/JsonSerialiserTests.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/spi/JsonSerialiserTests.java @@ -84,7 +84,7 @@ void testHeaderAndSpecialItems(final Class bufferClass) thro // header info ProtocolInfo headerInfo = ioSerialiser.checkHeaderInfo(); - assertNotEquals(headerInfo, new Object()); // silly comparison for coverage reasons + assertNotEquals(new Object(), headerInfo); // silly comparison for coverage reasons assertNotNull(headerInfo); assertEquals(JsonSerialiser.class.getCanonicalName(), headerInfo.getProducerName()); assertEquals(1, headerInfo.getVersionMajor()); @@ -291,9 +291,8 @@ public void setValues() { public boolean equals(final Object o) { if (this == o) return true; - if (!(o instanceof SimpleClass)) + if (!(o instanceof SimpleClass that)) return false; - final SimpleClass that = (SimpleClass) o; return integer == that.integer && Objects.equals(foo, that.foo) && Objects.equals(switches, that.switches); } diff --git a/serialiser/src/test/java/io/opencmw/serialiser/utils/FlatBuffersHelper.java b/serialiser/src/test/java/io/opencmw/serialiser/utils/FlatBuffersHelper.java index a3490e7a..f8ebb968 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/utils/FlatBuffersHelper.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/utils/FlatBuffersHelper.java @@ -304,7 +304,7 @@ public static void deserialiseCustom(FlexBuffers.Map map, final TestDataClass po final FlexBuffers.Map nestedMap = map.get("nestedData").asMap(); - if (nestedMap != null && nestedMap.size() != 0) { + if (nestedMap != null && !nestedMap.isEmpty()) { deserialiseCustom(map.get("nestedData").asMap(), pojo.nestedData, false); } } @@ -339,7 +339,7 @@ public static void testCustomSerialiserPerformance(final int iterations, final T } public static int checkCustomSerialiserIdentity(final TestDataClass inputObject, final TestDataClass outputObject) { - //final FlexBuffersBuilder floatBuffersBuilder = new FlexBuffersBuilder(new ArrayReadWriteBuf(rawByteBuffer), FlexBuffersBuilder.BUILDER_FLAG_SHARE_KEYS_AND_STRINGS); + // final FlexBuffersBuilder floatBuffersBuilder = new FlexBuffersBuilder(new ArrayReadWriteBuf(rawByteBuffer), FlexBuffersBuilder.BUILDER_FLAG_SHARE_KEYS_AND_STRINGS); final FlexBuffersBuilder floatBuffersBuilder = new FlexBuffersBuilder(new ArrayReadWriteBuf(rawByteBuffer), FlexBuffersBuilder.BUILDER_FLAG_NONE); final ByteBuffer retVal = FlatBuffersHelper.serialiseCustom(floatBuffersBuilder, inputObject); final int nBytesFlatBuffers = retVal.limit(); diff --git a/serialiser/src/test/java/io/opencmw/serialiser/utils/TestDataClass.java b/serialiser/src/test/java/io/opencmw/serialiser/utils/TestDataClass.java index dfa2f013..f0f839f2 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/utils/TestDataClass.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/utils/TestDataClass.java @@ -69,7 +69,7 @@ public TestDataClass() { public TestDataClass(final int nSizePrimitives, final int nSizeString, final int nestedClassRecursion) { if (nestedClassRecursion > 0) { nestedData = new TestDataClass(nSizePrimitives, nSizeString, nestedClassRecursion - 1); - nestedData.init(nSizePrimitives + 1, nSizeString + 1); //N.B. '+1' to have different sizes for nested classes + nestedData.init(nSizePrimitives + 1, nSizeString + 1); // N.B. '+1' to have different sizes for nested classes } init(nSizePrimitives, nSizeString); @@ -126,11 +126,10 @@ public boolean equals(final Object obj) { if (this == obj) { return true; } - if (!(obj instanceof TestDataClass)) { + if (!(obj instanceof TestDataClass other)) { LOGGER.atError().addArgument(obj).log("incompatible object type of obj = '{}'"); return false; } - final TestDataClass other = (TestDataClass) obj; boolean returnState = true; if (this.bool1 != other.bool1) { LOGGER.atError().addArgument("bool1").addArgument(this.bool1).addArgument(other.bool1) // @@ -228,12 +227,12 @@ public boolean equals(final Object obj) { LOGGER.atError().addArgument("byteArray").addArgument(e.getMessage()).log("field '{}' does not match '{}'"); returnState = false; } - //try { - // assertArrayEquals(this.charArray, other.charArray); - //} catch(AssertionFailedError e) { - // LOGGER.atError().addArgument("charArray").addArgument(e.getMessage()).log("field '{}' does not match '{}'"); - // returnState = false; - //} + // try { + // assertArrayEquals(this.charArray, other.charArray); + // } catch(AssertionFailedError e) { + // LOGGER.atError().addArgument("charArray").addArgument(e.getMessage()).log("field '{}' does not match '{}'"); + // returnState = false; + // } try { assertArrayEquals(this.shortArray, other.shortArray); } catch (AssertionFailedError e) { @@ -290,12 +289,12 @@ public boolean equals(final Object obj) { LOGGER.atError().addArgument("byteNdimArray").addArgument(e.getMessage()).log("field '{}' does not match '{}'"); returnState = false; } - //try { - // assertArrayEquals(this.charNdimArray, other.charNdimArray); - //} catch(AssertionFailedError e) { - // LOGGER.atError().addArgument("charNdimArray").addArgument(e.getMessage()).log("field '{}' does not match '{}'"); - // returnState = false; - //} + // try { + // assertArrayEquals(this.charNdimArray, other.charNdimArray); + // } catch(AssertionFailedError e) { + // LOGGER.atError().addArgument("charNdimArray").addArgument(e.getMessage()).log("field '{}' does not match '{}'"); + // returnState = false; + // } try { assertArrayEquals(this.shortNdimArray, other.shortNdimArray); } catch (AssertionFailedError e) { From facef37e9e8544c2cedbf9e2f992fee102a7e314 Mon Sep 17 00:00:00 2001 From: Alexander Krimm Date: Tue, 2 Dec 2025 11:52:18 +0100 Subject: [PATCH 5/7] JsonSerialiser: use reflection mode as code-generation does not work on newer java versions Signed-off-by: Alexander Krimm --- pom.xml | 1 + .../java/io/opencmw/serialiser/spi/JsonSerialiser.java | 8 ++++---- .../java/io/opencmw/serialiser/IoSerialiserTests.java | 6 +++--- .../test/java/io/opencmw/serialiser/utils/JsonHelper.java | 6 +++--- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index 82de3bfb..fe7ce0dc 100644 --- a/pom.xml +++ b/pom.xml @@ -186,6 +186,7 @@ --add-opens io.opencmw.client/io.opencmw.client.cmwlight=ALL-UNNAMED --add-opens io.opencmw.concepts/io.opencmw.concepts.cmwlight=ALL-UNNAMED --add-opens io.opencmw.concepts/io.opencmw.concepts.aggregate=ALL-UNNAMED + --add-opens java.base/java.lang=ALL-UNNAMED -Duser.language=en -Duser.country=US -Xms256m -Xmx2048m -XX:G1HeapRegionSize=32m -Djava.awt.headless=true -Dtestfx.robot=glass -Dtestfx.headless=true -Dprism.order=sw diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/JsonSerialiser.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/JsonSerialiser.java index c6fef47d..6b82acd5 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/JsonSerialiser.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/JsonSerialiser.java @@ -56,10 +56,10 @@ public JsonSerialiser(final IoBuffer buffer) { this.buffer = buffer; // JsonStream.setIndentionStep(DEFAULT_INDENTATION) - // JsonStream.setMode(EncodingMode.REFLECTION_MODE) -- enable as a fall back - // JsonIterator.setMode(DecodingMode.REFLECTION_MODE) -- enable as a fall back - JsonStream.setMode(EncodingMode.DYNAMIC_MODE); - JsonIterator.setMode(DecodingMode.DYNAMIC_MODE_AND_MATCH_FIELD_WITH_HASH); + JsonStream.setMode(EncodingMode.REFLECTION_MODE); // enable as a fall-back + JsonIterator.setMode(DecodingMode.REFLECTION_MODE); // enable as a fall-back + // JsonStream.setMode(EncodingMode.DYNAMIC_MODE); + // JsonIterator.setMode(DecodingMode.DYNAMIC_MODE_AND_MATCH_FIELD_WITH_HASH); try { PreciseFloatSupport.enable(); diff --git a/serialiser/src/test/java/io/opencmw/serialiser/IoSerialiserTests.java b/serialiser/src/test/java/io/opencmw/serialiser/IoSerialiserTests.java index 6b706fcf..e2adc6d4 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/IoSerialiserTests.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/IoSerialiserTests.java @@ -50,7 +50,7 @@ void simpleStreamerTest(final Class bufferClass) throws NoSu // first test - check for equal initialisation -- this should be trivial assertEquals(inputObject, outputObject1); - //final IoBuffer buffer = new FastByteBuffer(1000000); + // final IoBuffer buffer = new FastByteBuffer(1000000); final IoClassSerialiser serialiser = new IoClassSerialiser(buffer, BinarySerialiser.class); serialiser.serialiseObject(inputObject); @@ -209,7 +209,7 @@ void testParsingInterface(final Class ioSerialiserClass, buffer.reset(); final WireDataFieldDescription rootField = ioClassSerialiser.parseWireFormat(); - //rootField.printFieldStructure(); + // rootField.printFieldStructure(); assertEquals("ROOT", rootField.getFieldName()); final WireDataFieldDescription classFields = (WireDataFieldDescription) (rootField.getChildren().get(0)); @@ -296,7 +296,7 @@ void benchmarkPerformanceTests() { // POJO performance assertDoesNotThrow(() -> JsonHelper.testPerformancePojo(nIterations, inputObject, outputObject)); - assertDoesNotThrow(() -> JsonHelper.testPerformancePojoCodeGen(nIterations, inputObject, outputObject)); + // assertDoesNotThrow(() -> JsonHelper.testPerformancePojoCodeGen(nIterations, inputObject, outputObject)); // code generation has to be adapted to newer java versions due to stricter encapsulation // assertDoesNotThrow(() -> CmwHelper.testPerformancePojo(nIterations, inputObject, outputObject)); assertDoesNotThrow(() -> CmwLightHelper.testPerformancePojo(nIterations, inputObject, outputObject)); assertDoesNotThrow(() -> SerialiserHelper.testPerformancePojo(nIterations, inputObject, outputObject)); diff --git a/serialiser/src/test/java/io/opencmw/serialiser/utils/JsonHelper.java b/serialiser/src/test/java/io/opencmw/serialiser/utils/JsonHelper.java index a92991b6..4f1c344f 100644 --- a/serialiser/src/test/java/io/opencmw/serialiser/utils/JsonHelper.java +++ b/serialiser/src/test/java/io/opencmw/serialiser/utils/JsonHelper.java @@ -24,7 +24,7 @@ import com.jsoniter.spi.JsonException; public final class JsonHelper { - private static final Logger LOGGER = LoggerFactory.getLogger(SerialiserQuickBenchmark.class); // N.B. SerialiserQuickBenchmark reference on purpose + private static final Logger LOGGER = LoggerFactory.getLogger(JsonHelper.class); // N.B. SerialiserQuickBenchmark reference on purpose private static final IoBuffer byteBuffer = new FastByteBuffer(1000000); // private static final IoBuffer byteBuffer = new ByteBuffer(20000); private static final JsonSerialiser jsonSerialiser = new JsonSerialiser(byteBuffer); @@ -53,11 +53,11 @@ public static int checkSerialiserIdentity(final TestDataClass inputObject, TestD outputObject.clear(); // JsonIterator.setMode(DecodingMode.DYNAMIC_MODE_AND_MATCH_FIELD_WITH_HASH); // JsonStream.setMode(EncodingMode.DYNAMIC_MODE); - // JsonIterator.setMode(DecodingMode.REFLECTION_MODE); + JsonIterator.setMode(DecodingMode.REFLECTION_MODE); // JsonStream.setIndentionStep(2); // sets line-breaks and indentation (more human readable) // Base64Support.enable(); // Base64FloatSupport.enableEncodersAndDecoders(); - JsonStream.setMode(EncodingMode.DYNAMIC_MODE); + JsonStream.setMode(EncodingMode.REFLECTION_MODE); try { PreciseFloatSupport.enable(); From 4456f4c44e05765070925c31ca17c2b25c60dfd2 Mon Sep 17 00:00:00 2001 From: Alexander Krimm Date: Tue, 2 Dec 2025 15:40:31 +0100 Subject: [PATCH 6/7] Restyled: apply current restyler to modified files Signed-off-by: Alexander Krimm --- .../serialiser/spi/BinarySerialiser.java | 2018 +++++++++-------- .../spi/iobuffer/DataSetSerialiser.java | 289 +-- 2 files changed, 1170 insertions(+), 1137 deletions(-) diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/BinarySerialiser.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/BinarySerialiser.java index 48aa09f4..6f813dd3 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/BinarySerialiser.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/BinarySerialiser.java @@ -292,106 +292,92 @@ public Collection getCollection(final Collection collection) { final String classTypeName = buffer.getStringISO8859(); final String secondaryTypeName = buffer.getStringISO8859(); final Type classType = ClassUtils.getClassByName(classTypeName); - final Type[] secondaryType = secondaryTypeName.isEmpty() ? new Type[0] : new Type[] { ClassUtils.getClassByName(secondaryTypeName) }; - final BiFunction> serialiserLookup = getSerialiserLookupFunction(); - if (serialiserLookup == null) { - throw new IllegalArgumentException(PROTOCOL_ERROR_SERIALISER_LOOKUP_MUST_NOT_BE_NULL); - } - @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) - final FieldSerialiser serialiser = (FieldSerialiser) serialiserLookup.apply(classType, secondaryType); + final Type[] secondaryType = secondaryTypeName.isEmpty() ? new Type[0] : + new Type[] { ClassUtils.getClassByName(secondaryTypeName) }; + final BiFunction> serialiserLookup = getSerialiserLookupFunction(); + if (serialiserLookup == null) { + throw new IllegalArgumentException(PROTOCOL_ERROR_SERIALISER_LOOKUP_MUST_NOT_BE_NULL); + } + @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) + final FieldSerialiser serialiser = (FieldSerialiser) serialiserLookup.apply(classType, secondaryType); + + if (serialiser == null) { + throw new IllegalArgumentException(NO_SERIALISER_IMP_FOUND + classTypeName); + } + for (int i = 0; i < nElements; i++) { + retCollection.add(serialiser.getReturnObjectFunction().apply(this, null, null)); + } + + return retCollection; + } + + // read primitive or String value vector + final E[] values = getGenericArrayAsBoxedPrimitive(valueDataType); + if (nElements != values.length) { + throw new IllegalStateException(PROTOCOL_MISMATCH_N_ELEMENTS_HEADER + nElements + VS_ARRAY + values.length); + } + retCollection.addAll(Arrays.asList(values)); + + return retCollection; + } - if (serialiser == null) { - throw new IllegalArgumentException(NO_SERIALISER_IMP_FOUND + classTypeName); - } - for (int i = 0; i < nElements; i++) { - retCollection.add(serialiser.getReturnObjectFunction().apply(this, null, null)); + @Override + @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) + public E getCustomData(final FieldSerialiser serialiser) { + String classType = null; + String classSecondaryType = null; + try { + classType = buffer.getStringISO8859(); + classSecondaryType = buffer.getStringISO8859(); + if (serialiser == null) { + final Type classTypeT = ClassUtils.getClassByName(classType); + final Type[] secondaryTypeT = classSecondaryType.isEmpty() ? new Type[0] : new Type[] { ClassUtils.getClassByName(classSecondaryType) }; + return (E) getSerialiserLookupFunction().apply(classTypeT, secondaryTypeT).getReturnObjectFunction().apply(this, null, null); + } else { + return serialiser.getReturnObjectFunction().apply(this, null, null); + } + } catch (Exception e) { // NOPMD + LOGGER.atError().setCause(e).addArgument(classType).addArgument(classSecondaryType).log("problems with generic classType: {} classSecondaryType: {}"); + throw e; } - - return retCollection; } - // read primitive or String value vector - final E[] values = getGenericArrayAsBoxedPrimitive(valueDataType); - if (nElements != values.length) { - throw new IllegalStateException(PROTOCOL_MISMATCH_N_ELEMENTS_HEADER + nElements + VS_ARRAY + values.length); + @Override + public double getDouble() { + return buffer.getDouble(); } - retCollection.addAll(Arrays.asList(values)); - return retCollection; - } - - @Override - @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) - public E getCustomData(final FieldSerialiser serialiser) { - String classType = null; - String classSecondaryType = null; - try { - classType = buffer.getStringISO8859(); - classSecondaryType = buffer.getStringISO8859(); - if (serialiser == null) { - final Type classTypeT = ClassUtils.getClassByName(classType); - final Type[] secondaryTypeT = classSecondaryType.isEmpty() ? new Type[0] : new Type[] { ClassUtils.getClassByName(classSecondaryType) }; - return (E) getSerialiserLookupFunction().apply(classTypeT, secondaryTypeT).getReturnObjectFunction().apply(this, null, null); - } else { - return serialiser.getReturnObjectFunction().apply(this, null, null); - } - } catch (Exception e) { // NOPMD - LOGGER.atError().setCause(e).addArgument(classType).addArgument(classSecondaryType).log("problems with generic classType: {} classSecondaryType: {}"); - throw e; + @Override + public double[] getDoubleArray(final double[] dst, final int length) { + getArraySizeDescriptor(); + return buffer.getDoubleArray(dst, length); } - } - - @Override - public double getDouble() { - return buffer.getDouble(); - } - @Override - public double[] getDoubleArray(final double[] dst, final int length) { - getArraySizeDescriptor(); - return buffer.getDoubleArray(dst, length); - } - - @Override - @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) - public > Enum getEnum(final Enum enumeration) { - // read value vector - final String enumSimpleName = buffer.getStringISO8859(); - final String enumName = buffer.getStringISO8859(); - buffer.getStringISO8859(); // enumTypeList - final String enumState = buffer.getStringISO8859(); - buffer.getInt(); // enumOrdinal - // N.B. for the time being package name + class name is required - Class enumClass = ClassUtils.getClassByName(enumName); - if (enumClass == null) { - enumClass = ClassUtils.getClassByName(enumSimpleName); + @Override + @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) + public > Enum getEnum(final Enum enumeration) { + // read value vector + final String enumSimpleName = buffer.getStringISO8859(); + final String enumName = buffer.getStringISO8859(); + buffer.getStringISO8859(); // enumTypeList + final String enumState = buffer.getStringISO8859(); + buffer.getInt(); // enumOrdinal + // N.B. for the time being package name + class name is required + Class enumClass = ClassUtils.getClassByName(enumName); if (enumClass == null) { - throw new IllegalStateException( - "could not find enum class description '" + enumName + "' or '" + enumSimpleName + "'"); + enumClass = ClassUtils.getClassByName(enumSimpleName); + if (enumClass == null) { + throw new IllegalStateException( + "could not find enum class description '" + enumName + "' or '" + enumSimpleName + "'"); + } } - } - try { - final Method valueOf = enumClass.getMethod("valueOf", String.class); - return (Enum) valueOf.invoke(null, enumState); - } catch (final ReflectiveOperationException e) { - LOGGER.atError().setCause(e).addArgument(enumClass).log("could not match 'valueOf(String)' function for class/(supposedly) enum of {}"); - } - - return null; - } - - @Override - public String getEnumTypeList() { - // read value vector - buffer.getStringISO8859(); // enumSimpleName - buffer.getStringISO8859(); // enumName - final String enumTypeList = buffer.getStringISO8859(); - buffer.getStringISO8859(); // enumState - buffer.getInt(); // enumOrdinal - - return enumTypeList; - } + try { + final Method valueOf = enumClass.getMethod("valueOf", String.class); + return (Enum) valueOf.invoke(null, enumState); + } catch (final ReflectiveOperationException e) { + LOGGER.atError().setCause(e).addArgument(enumClass).log("could not match 'valueOf(String)' function for class/(supposedly) enum of {}"); + } return null; } @@ -408,363 +394,412 @@ public String getEnumTypeList() { return enumTypeList; } - if (this.isPutFieldMetaData()) { - // optional meta data + @Override + public WireDataFieldDescription getFieldHeader() { + final int headerStart = buffer.position(); + final byte dataTypeByte = buffer.getByte(); + final int dataStartOffset = buffer.getInt(); + final int dataStartPosition = headerStart + dataStartOffset; + int dataSize = buffer.getInt(); + final String fieldName; if (buffer.position() < dataStartPosition) { - lastFieldHeader.setFieldUnit(buffer.getString()); + fieldName = buffer.getStringISO8859(); + } else { + fieldName = null; } - if (buffer.position() < dataStartPosition) { - lastFieldHeader.setFieldDescription(buffer.getString()); + + final DataType dataType = getDataType(dataTypeByte); + if (dataType == DataType.END_MARKER) { + parent = (WireDataFieldDescription) parent.getParent(); } - if (buffer.position() < dataStartPosition) { - lastFieldHeader.setFieldDirection(buffer.getString()); + lastFieldHeader = new WireDataFieldDescription(this, parent, fieldName, dataType, headerStart, dataStartOffset, dataSize); + if (dataType == DataType.START_MARKER) { + parent = lastFieldHeader; } - if (buffer.position() < dataStartPosition) { - final String[] fieldGroups = buffer.getStringArray(); - lastFieldHeader.setFieldGroups(fieldGroups == null ? Collections.emptyList() : Arrays.asList(fieldGroups)); + + if (this.isPutFieldMetaData()) { + // optional meta data + if (buffer.position() < dataStartPosition) { + lastFieldHeader.setFieldUnit(buffer.getString()); + } + if (buffer.position() < dataStartPosition) { + lastFieldHeader.setFieldDescription(buffer.getString()); + } + if (buffer.position() < dataStartPosition) { + lastFieldHeader.setFieldDirection(buffer.getString()); + } + if (buffer.position() < dataStartPosition) { + final String[] fieldGroups = buffer.getStringArray(); + lastFieldHeader.setFieldGroups(fieldGroups == null ? Collections.emptyList() : Arrays.asList(fieldGroups)); + } + } else { + buffer.position(dataStartPosition); } - } else { - buffer.position(dataStartPosition); - } - // check for header-dataStart offset consistency - if (buffer.position() != dataStartPosition) { - final int diff = dataStartPosition - buffer.position(); - throw new IllegalStateException("could not parse FieldHeader: fieldName='" + dataType + ":" + fieldName + "' dataOffset = " + dataStartOffset + " bytes (read) -- " // - + " buffer position is " + buffer.position() + " vs. calculated " + dataStartPosition + " diff = " + diff); - } + // check for header-dataStart offset consistency + if (buffer.position() != dataStartPosition) { + final int diff = dataStartPosition - buffer.position(); + throw new IllegalStateException("could not parse FieldHeader: fieldName='" + dataType + ":" + fieldName + "' dataOffset = " + dataStartOffset + " bytes (read) -- " // + + " buffer position is " + buffer.position() + " vs. calculated " + dataStartPosition + " diff = " + diff); + } + + if (dataSize >= 0) { + return lastFieldHeader; + } + + // last-minute check in case dataSize hasn't been set correctly + if (dataType.isScalar()) { + dataSize = dataType.getPrimitiveSize(); + } else if (dataType == DataType.STRING) { + // sneak-peak look-ahead to get actual string size + // N.B. regarding jump size: <(>string size -1> + + dataSize = buffer.getInt(buffer.position() + FastByteBuffer.SIZE_OF_INT) + FastByteBuffer.SIZE_OF_INT; + } + lastFieldHeader.setDataSize(dataSize); - if (dataSize >= 0) { return lastFieldHeader; } - // last-minute check in case dataSize hasn't been set correctly - if (dataType.isScalar()) { - dataSize = dataType.getPrimitiveSize(); - } else if (dataType == DataType.STRING) { - // sneak-peak look-ahead to get actual string size - // N.B. regarding jump size: <(>string size -1> + - dataSize = buffer.getInt(buffer.position() + FastByteBuffer.SIZE_OF_INT) + FastByteBuffer.SIZE_OF_INT; + @Override + public float getFloat() { + return buffer.getFloat(); } - lastFieldHeader.setDataSize(dataSize); - - return lastFieldHeader; - } - - @Override - public float getFloat() { - return buffer.getFloat(); - } - @Override - public float[] getFloatArray(final float[] dst, final int length) { - getArraySizeDescriptor(); - return buffer.getFloatArray(dst, length); - } - - @Override - public int getInt() { - return buffer.getInt(); - } - - @Override - public int[] getIntArray(final int[] dst, final int length) { - getArraySizeDescriptor(); - return buffer.getIntArray(dst, length); - } + @Override + public float[] getFloatArray(final float[] dst, final int length) { + getArraySizeDescriptor(); + return buffer.getFloatArray(dst, length); + } - @Override - public List getList(final List collection) { - getArraySizeDescriptor(); - final int nElements = buffer.getInt(); - final DataType listDataType = getDataType(buffer.getByte()); - final DataType valueDataType = getDataType(buffer.getByte()); - if (!listDataType.equals(DataType.LIST) && !listDataType.equals(DataType.COLLECTION)) { - throw new IllegalArgumentException("dataType incompatible with List = " + listDataType); + @Override + public int getInt() { + return buffer.getInt(); } - final List retCollection; - if (collection == null) { - retCollection = new ArrayList<>(); - } else { - retCollection = collection; - retCollection.clear(); + + @Override + public int[] getIntArray(final int[] dst, final int length) { + getArraySizeDescriptor(); + return buffer.getIntArray(dst, length); } - if (DataType.OTHER.equals(valueDataType)) { - final String classTypeName = buffer.getStringISO8859(); - final String secondaryTypeName = buffer.getStringISO8859(); - final Type classType = ClassUtils.getClassByName(classTypeName); - final Type[] secondaryType = secondaryTypeName.isEmpty() ? new Type[0] : new Type[] { ClassUtils.getClassByName(secondaryTypeName) }; - final BiFunction> serialiserLookup = getSerialiserLookupFunction(); - if (serialiserLookup == null) { - throw new IllegalArgumentException(PROTOCOL_ERROR_SERIALISER_LOOKUP_MUST_NOT_BE_NULL); + @Override + public List getList(final List collection) { + getArraySizeDescriptor(); + final int nElements = buffer.getInt(); + final DataType listDataType = getDataType(buffer.getByte()); + final DataType valueDataType = getDataType(buffer.getByte()); + if (!listDataType.equals(DataType.LIST) && !listDataType.equals(DataType.COLLECTION)) { + throw new IllegalArgumentException("dataType incompatible with List = " + listDataType); + } + final List retCollection; + if (collection == null) { + retCollection = new ArrayList<>(); + } else { + retCollection = collection; + retCollection.clear(); } - @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) - final FieldSerialiser serialiser = (FieldSerialiser) serialiserLookup.apply(classType, secondaryType); - if (serialiser == null) { - throw new IllegalArgumentException(NO_SERIALISER_IMP_FOUND + classTypeName); + if (DataType.OTHER.equals(valueDataType)) { + final String classTypeName = buffer.getStringISO8859(); + final String secondaryTypeName = buffer.getStringISO8859(); + final Type classType = ClassUtils.getClassByName(classTypeName); + final Type[] secondaryType = secondaryTypeName.isEmpty() ? new Type[0] : new Type[] { ClassUtils.getClassByName(secondaryTypeName) }; + final BiFunction> serialiserLookup = getSerialiserLookupFunction(); + if (serialiserLookup == null) { + throw new IllegalArgumentException(PROTOCOL_ERROR_SERIALISER_LOOKUP_MUST_NOT_BE_NULL); + } + @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) + final FieldSerialiser serialiser = (FieldSerialiser) serialiserLookup.apply(classType, secondaryType); + + if (serialiser == null) { + throw new IllegalArgumentException(NO_SERIALISER_IMP_FOUND + classTypeName); + } + for (int i = 0; i < nElements; i++) { + retCollection.add(serialiser.getReturnObjectFunction().apply(this, null, null)); + } + + return retCollection; } - for (int i = 0; i < nElements; i++) { - retCollection.add(serialiser.getReturnObjectFunction().apply(this, null, null)); + + // read primitive or String value vector + final E[] values = getGenericArrayAsBoxedPrimitive(valueDataType); + if (nElements != values.length) { + throw new IllegalStateException(PROTOCOL_MISMATCH_N_ELEMENTS_HEADER + nElements + VS_ARRAY + values.length); } + retCollection.addAll(Arrays.asList(values)); return retCollection; } - // read primitive or String value vector - final E[] values = getGenericArrayAsBoxedPrimitive(valueDataType); - if (nElements != values.length) { - throw new IllegalStateException(PROTOCOL_MISMATCH_N_ELEMENTS_HEADER + nElements + VS_ARRAY + values.length); + @Override + public long getLong() { + return buffer.getLong(); } - retCollection.addAll(Arrays.asList(values)); - - return retCollection; - } - @Override - public long getLong() { - return buffer.getLong(); - } + @Override + public long[] getLongArray(final long[] dst, final int length) { + getArraySizeDescriptor(); + return buffer.getLongArray(dst, length); + } - @Override - public long[] getLongArray(final long[] dst, final int length) { - getArraySizeDescriptor(); - return buffer.getLongArray(dst, length); - } + @Override + @SuppressWarnings({ UNCHECKED_CAST_SUPPRESSION }) + public Map getMap(final Map map) { // NOSONAR NOPMD + getArraySizeDescriptor(); + final int nElements = buffer.getInt(); + // convert into two linear arrays one of K and the other for V streamer encoding as + // <1 (int)> - @Override - @SuppressWarnings({ UNCHECKED_CAST_SUPPRESSION }) - public Map getMap(final Map map) { // NOSONAR NOPMD - getArraySizeDescriptor(); - final int nElements = buffer.getInt(); - // convert into two linear arrays one of K and the other for V streamer encoding as - // <1 (int)> - - // read key type and key value vector - final K[] keys; - final DataType keyDataType = getDataType(buffer.getByte()); - final BiFunction> serialiserLookup = getSerialiserLookupFunction(); - if (keyDataType == DataType.OTHER) { - final String classTypeName = buffer.getStringISO8859(); - final String secondaryTypeName = buffer.getStringISO8859(); - final Type classType = ClassUtils.getClassByName(classTypeName); - final Type[] secondaryType = secondaryTypeName.isEmpty() ? new Type[0] : new Type[] { ClassUtils.getClassByName(secondaryTypeName) }; - if (serialiserLookup == null) { - throw new IllegalArgumentException(PROTOCOL_ERROR_SERIALISER_LOOKUP_MUST_NOT_BE_NULL); - } - final FieldSerialiser serialiser = serialiserLookup.apply(classType, secondaryType); - if (serialiser == null) { - throw new IllegalArgumentException(NO_SERIALISER_IMP_FOUND + classTypeName); - } - keys = (K[]) new Object[nElements]; - for (int i = 0; i < keys.length; i++) { - keys[i] = (K) serialiser.getReturnObjectFunction().apply(this, null, null); + // read key type and key value vector + final K[] keys; + final DataType keyDataType = getDataType(buffer.getByte()); + final BiFunction> serialiserLookup = getSerialiserLookupFunction(); + if (keyDataType == DataType.OTHER) { + final String classTypeName = buffer.getStringISO8859(); + final String secondaryTypeName = buffer.getStringISO8859(); + final Type classType = ClassUtils.getClassByName(classTypeName); + final Type[] secondaryType = secondaryTypeName.isEmpty() ? new Type[0] : new Type[] { ClassUtils.getClassByName(secondaryTypeName) }; + if (serialiserLookup == null) { + throw new IllegalArgumentException(PROTOCOL_ERROR_SERIALISER_LOOKUP_MUST_NOT_BE_NULL); + } + final FieldSerialiser serialiser = serialiserLookup.apply(classType, secondaryType); + if (serialiser == null) { + throw new IllegalArgumentException(NO_SERIALISER_IMP_FOUND + classTypeName); + } + keys = (K[]) new Object[nElements]; + for (int i = 0; i < keys.length; i++) { + keys[i] = (K) serialiser.getReturnObjectFunction().apply(this, null, null); + } + } else { + keys = getGenericArrayAsBoxedPrimitive(keyDataType); } - } else { - keys = getGenericArrayAsBoxedPrimitive(keyDataType); - } - // read value type and value vector - final V[] values; - final DataType valueDataType = getDataType(buffer.getByte()); - if (valueDataType == DataType.OTHER) { - final String classTypeName = buffer.getStringISO8859(); - final String secondaryTypeName = buffer.getStringISO8859(); - final Type classType = ClassUtils.getClassByName(classTypeName); - final Type[] secondaryType = secondaryTypeName.isEmpty() ? new Type[0] : new Type[] { ClassUtils.getClassByName(secondaryTypeName) }; - if (serialiserLookup == null) { - throw new IllegalArgumentException(PROTOCOL_ERROR_SERIALISER_LOOKUP_MUST_NOT_BE_NULL); + // read value type and value vector + final V[] values; + final DataType valueDataType = getDataType(buffer.getByte()); + if (valueDataType == DataType.OTHER) { + final String classTypeName = buffer.getStringISO8859(); + final String secondaryTypeName = buffer.getStringISO8859(); + final Type classType = ClassUtils.getClassByName(classTypeName); + final Type[] secondaryType = secondaryTypeName.isEmpty() ? new Type[0] : new Type[] { ClassUtils.getClassByName(secondaryTypeName) }; + if (serialiserLookup == null) { + throw new IllegalArgumentException(PROTOCOL_ERROR_SERIALISER_LOOKUP_MUST_NOT_BE_NULL); + } + final FieldSerialiser serialiser = serialiserLookup.apply(classType, secondaryType); + + if (serialiser == null) { + throw new IllegalArgumentException(NO_SERIALISER_IMP_FOUND + classTypeName); + } + values = (V[]) new Object[nElements]; + for (int i = 0; i < values.length; i++) { + values[i] = (V) serialiser.getReturnObjectFunction().apply(this, null, null); + } + } else { + values = getGenericArrayAsBoxedPrimitive(valueDataType); } - final FieldSerialiser serialiser = serialiserLookup.apply(classType, secondaryType); - if (serialiser == null) { - throw new IllegalArgumentException(NO_SERIALISER_IMP_FOUND + classTypeName); + // generate new/write into an existing Map + final Map retMap = map == null ? new ConcurrentHashMap<>() : map; + if (map != null) { + map.clear(); } - values = (V[]) new Object[nElements]; - for (int i = 0; i < values.length; i++) { - values[i] = (V) serialiser.getReturnObjectFunction().apply(this, null, null); + for (int i = 0; i < keys.length; i++) { + retMap.put(keys[i], values[i]); } - } else { - values = getGenericArrayAsBoxedPrimitive(valueDataType); - } return retMap; } - for (int i = 0; i < keys.length; i++) { - retMap.put(keys[i], values[i]); - } - - return retMap; - } - - public WireDataFieldDescription getParent() { - return parent; - } - @Override - public Queue getQueue(final Queue collection) { - getArraySizeDescriptor(); - final int nElements = buffer.getInt(); - final DataType listDataType = getDataType(buffer.getByte()); - final DataType valueDataType = getDataType(buffer.getByte()); - if (!listDataType.equals(DataType.QUEUE) && !listDataType.equals(DataType.COLLECTION)) { - throw new IllegalArgumentException("dataType incompatible with Queue = " + listDataType); - } - final Queue retCollection; - if (collection == null) { - retCollection = new ArrayDeque<>(); - } else { - retCollection = collection; - retCollection.clear(); + public WireDataFieldDescription getParent() { + return parent; } - if (DataType.OTHER.equals(valueDataType)) { - final String classTypeName = buffer.getStringISO8859(); - final String secondaryTypeName = buffer.getStringISO8859(); - final Type classType = ClassUtils.getClassByName(classTypeName); - final Type[] secondaryType = secondaryTypeName.isEmpty() ? new Type[0] : new Type[] { ClassUtils.getClassByName(secondaryTypeName) }; - final BiFunction> serialiserLookup = getSerialiserLookupFunction(); - if (serialiserLookup == null) { - throw new IllegalArgumentException(PROTOCOL_ERROR_SERIALISER_LOOKUP_MUST_NOT_BE_NULL); + @Override + public Queue getQueue(final Queue collection) { + getArraySizeDescriptor(); + final int nElements = buffer.getInt(); + final DataType listDataType = getDataType(buffer.getByte()); + final DataType valueDataType = getDataType(buffer.getByte()); + if (!listDataType.equals(DataType.QUEUE) && !listDataType.equals(DataType.COLLECTION)) { + throw new IllegalArgumentException("dataType incompatible with Queue = " + listDataType); + } + final Queue retCollection; + if (collection == null) { + retCollection = new ArrayDeque<>(); + } else { + retCollection = collection; + retCollection.clear(); } - @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) - final FieldSerialiser serialiser = (FieldSerialiser) serialiserLookup.apply(classType, secondaryType); - if (serialiser == null) { - throw new IllegalArgumentException(NO_SERIALISER_IMP_FOUND + classTypeName); + if (DataType.OTHER.equals(valueDataType)) { + final String classTypeName = buffer.getStringISO8859(); + final String secondaryTypeName = buffer.getStringISO8859(); + final Type classType = ClassUtils.getClassByName(classTypeName); + final Type[] secondaryType = secondaryTypeName.isEmpty() ? new Type[0] : new Type[] { ClassUtils.getClassByName(secondaryTypeName) }; + final BiFunction> serialiserLookup = getSerialiserLookupFunction(); + if (serialiserLookup == null) { + throw new IllegalArgumentException(PROTOCOL_ERROR_SERIALISER_LOOKUP_MUST_NOT_BE_NULL); + } + @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) + final FieldSerialiser serialiser = (FieldSerialiser) serialiserLookup.apply(classType, secondaryType); + + if (serialiser == null) { + throw new IllegalArgumentException(NO_SERIALISER_IMP_FOUND + classTypeName); + } + for (int i = 0; i < nElements; i++) { + retCollection.add(serialiser.getReturnObjectFunction().apply(this, null, null)); + } + + return retCollection; } - for (int i = 0; i < nElements; i++) { - retCollection.add(serialiser.getReturnObjectFunction().apply(this, null, null)); + + // read primitive or String value vector + final E[] values = getGenericArrayAsBoxedPrimitive(valueDataType); + if (nElements != values.length) { + throw new IllegalStateException(PROTOCOL_MISMATCH_N_ELEMENTS_HEADER + nElements + VS_ARRAY + values.length); } + retCollection.addAll(Arrays.asList(values)); return retCollection; } - // read primitive or String value vector - final E[] values = getGenericArrayAsBoxedPrimitive(valueDataType); - if (nElements != values.length) { - throw new IllegalStateException(PROTOCOL_MISMATCH_N_ELEMENTS_HEADER + nElements + VS_ARRAY + values.length); - } - retCollection.addAll(Arrays.asList(values)); - - return retCollection; - } - - @Override - public Set getSet(final Set collection) { - getArraySizeDescriptor(); - final int nElements = buffer.getInt(); - final DataType listDataType = getDataType(buffer.getByte()); - final DataType valueDataType = getDataType(buffer.getByte()); - if (!listDataType.equals(DataType.SET) && !listDataType.equals(DataType.COLLECTION)) { - throw new IllegalArgumentException("dataType incompatible with Set = " + listDataType); - } - final Set retCollection; - if (collection == null) { - retCollection = new HashSet<>(); - } else { - retCollection = collection; - retCollection.clear(); - } - - if (DataType.OTHER.equals(valueDataType)) { - final BiFunction> serialiserLookup = getSerialiserLookupFunction(); - if (serialiserLookup == null) { - throw new IllegalArgumentException(PROTOCOL_ERROR_SERIALISER_LOOKUP_MUST_NOT_BE_NULL); + @Override + public Set getSet(final Set collection) { + getArraySizeDescriptor(); + final int nElements = buffer.getInt(); + final DataType listDataType = getDataType(buffer.getByte()); + final DataType valueDataType = getDataType(buffer.getByte()); + if (!listDataType.equals(DataType.SET) && !listDataType.equals(DataType.COLLECTION)) { + throw new IllegalArgumentException("dataType incompatible with Set = " + listDataType); + } + final Set retCollection; + if (collection == null) { + retCollection = new HashSet<>(); + } else { + retCollection = collection; + retCollection.clear(); } - final String classTypeName = buffer.getStringISO8859(); - final String secondaryTypeName = buffer.getStringISO8859(); - final Type classType = ClassUtils.getClassByName(classTypeName); - final Type[] secondaryType = secondaryTypeName.isEmpty() ? new Type[0] : new Type[] { ClassUtils.getClassByName(secondaryTypeName) }; - @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) - final FieldSerialiser serialiser = (FieldSerialiser) serialiserLookup.apply(classType, secondaryType); - if (serialiser == null) { - throw new IllegalArgumentException(NO_SERIALISER_IMP_FOUND + classTypeName); + if (DataType.OTHER.equals(valueDataType)) { + final BiFunction> serialiserLookup = getSerialiserLookupFunction(); + if (serialiserLookup == null) { + throw new IllegalArgumentException(PROTOCOL_ERROR_SERIALISER_LOOKUP_MUST_NOT_BE_NULL); + } + final String classTypeName = buffer.getStringISO8859(); + final String secondaryTypeName = buffer.getStringISO8859(); + final Type classType = ClassUtils.getClassByName(classTypeName); + final Type[] secondaryType = secondaryTypeName.isEmpty() ? new Type[0] : new Type[] { ClassUtils.getClassByName(secondaryTypeName) }; + @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) + final FieldSerialiser serialiser = (FieldSerialiser) serialiserLookup.apply(classType, secondaryType); + + if (serialiser == null) { + throw new IllegalArgumentException(NO_SERIALISER_IMP_FOUND + classTypeName); + } + for (int i = 0; i < nElements; i++) { + retCollection.add(serialiser.getReturnObjectFunction().apply(this, null, null)); + } + + return retCollection; } - for (int i = 0; i < nElements; i++) { - retCollection.add(serialiser.getReturnObjectFunction().apply(this, null, null)); + + // read primitive or String value vector + final E[] values = getGenericArrayAsBoxedPrimitive(valueDataType); + if (nElements != values.length) { + throw new IllegalStateException(PROTOCOL_MISMATCH_N_ELEMENTS_HEADER + nElements + VS_ARRAY + values.length); } + retCollection.addAll(Arrays.asList(values)); return retCollection; } - // read primitive or String value vector - final E[] values = getGenericArrayAsBoxedPrimitive(valueDataType); - if (nElements != values.length) { - throw new IllegalStateException(PROTOCOL_MISMATCH_N_ELEMENTS_HEADER + nElements + VS_ARRAY + values.length); + @Override + public short getShort() { + return buffer.getShort(); } - retCollection.addAll(Arrays.asList(values)); - - return retCollection; - } - - @Override - public short getShort() { - return buffer.getShort(); - } - - @Override - public short[] getShortArray(final short[] dst, final int length) { - getArraySizeDescriptor(); - return buffer.getShortArray(dst, length); - } - @Override - public String getString() { - return buffer.getString(); - } + @Override + public short[] getShortArray(final short[] dst, final int length) { + getArraySizeDescriptor(); + return buffer.getShortArray(dst, length); + } - @Override - public String[] getStringArray(final String[] dst, final int length) { - getArraySizeDescriptor(); - return buffer.getStringArray(dst, length); - } + @Override + public String getString() { + return buffer.getString(); + } - @Override - public String getStringISO8859() { - return buffer.getStringISO8859(); - } + @Override + public String[] getStringArray(final String[] dst, final int length) { + getArraySizeDescriptor(); + return buffer.getStringArray(dst, length); + } - /** - * @return {@code true} the ISO-8859-1 character encoding is being enforced for data fields (better performance), otherwise UTF-8 is being used (more generic encoding) - */ - public boolean isEnforceSimpleStringEncoding() { - return buffer.isEnforceSimpleStringEncoding(); - } + @Override + public String getStringISO8859() { + return buffer.getStringISO8859(); + } - /** - * - * @param state {@code true} the ISO-8859-1 character encoding is being enforced for data fields (better performance), otherwise UTF-8 is being used (more generic encoding) - */ - public void setEnforceSimpleStringEncoding(final boolean state) { - buffer.setEnforceSimpleStringEncoding(state); - } + /** + * @return {@code true} the ISO-8859-1 character encoding is being enforced for data fields (better performance), otherwise UTF-8 is being used (more generic encoding) + */ + public boolean isEnforceSimpleStringEncoding() { + return buffer.isEnforceSimpleStringEncoding(); + } - @Override - public boolean isPutFieldMetaData() { - return putFieldMetaData; - } + /** + * + * @param state {@code true} the ISO-8859-1 character encoding is being enforced for data fields (better performance), otherwise UTF-8 is being used (more generic encoding) + */ + public void setEnforceSimpleStringEncoding(final boolean state) { + buffer.setEnforceSimpleStringEncoding(state); + } - @Override - public void setPutFieldMetaData(final boolean putFieldMetaData) { - this.putFieldMetaData = putFieldMetaData; - } + @Override + public boolean isPutFieldMetaData() { + return putFieldMetaData; + } @Override public void setPutFieldMetaData(final boolean putFieldMetaData) { this.putFieldMetaData = putFieldMetaData; } - public void parseIoStream(final WireDataFieldDescription fieldRoot, final int recursionDepth) { - if (fieldRoot.getParent() == null) { - parent = lastFieldHeader = fieldRoot; + @Override + public WireDataFieldDescription parseIoStream(final boolean readHeader) { + final WireDataFieldDescription fieldRoot = getRootElement(); + parent = fieldRoot; + final WireDataFieldDescription headerRoot = readHeader ? checkHeaderInfo().getFieldHeader() : getFieldHeader(); + buffer.position(headerRoot.getDataStartPosition()); + parseIoStream(headerRoot, 0); + // updateDataEndMarker(fieldRoot) + return fieldRoot; } public void parseIoStream(final WireDataFieldDescription fieldRoot, final int recursionDepth) { if (fieldRoot.getParent() == null) { parent = lastFieldHeader = fieldRoot; } + WireDataFieldDescription field; + while ((field = getFieldHeader()) != null) { + final DataType dataType = field.getDataType(); + if (dataType == DataType.END_MARKER) { + // reached the end of (sub)class - close nested hierarchy + break; + } + + if (dataType == DataType.START_MARKER) { + // detected subclass start marker + parseIoStream(field, recursionDepth + 1); + continue; + } + + final int dataSize = field.getDataSize(); + if (dataSize < 0) { + throw new IllegalStateException("FieldDescription for '" + field.getFieldName() + "' type '" + dataType + "' has negative dataSize = " + dataSize); + } + final int skipPosition = field.getDataStartPosition() + dataSize; + buffer.position(skipPosition); + } + } @Override public void put(final FieldDescription fieldDescription, final Collection collection, final Type valueType) { @@ -787,658 +822,621 @@ public void put(final FieldDescription fieldDescription, final Collection buffer.putByte(getDataType(DataType.COLLECTION)); } - final int dataSize = field.getDataSize(); - if (dataSize < 0) { - throw new IllegalStateException("FieldDescription for '" + field.getFieldName() + "' type '" + dataType + "' has negative dataSize = " + dataSize); + final BiFunction> serialiserLookup = getSerialiserLookupFunction(); + if (ClassUtils.isPrimitiveWrapperOrString(cleanedType) || serialiserLookup == null) { + buffer.ensureAdditionalCapacity((nElements * entrySize) + 9); + buffer.putByte(getDataType(valueDataType)); // write value element type + putGenericArrayAsPrimitive(valueDataType, values, nElements); + } else { + buffer.putByte(getDataType(DataType.OTHER)); // write value element type + final Type[] secondaryType = ClassUtils.getSecondaryType(valueType); + @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) + final FieldSerialiser serialiser = (FieldSerialiser) serialiserLookup.apply(valueType, secondaryType); + if (serialiser == null) { + throw new IllegalArgumentException("could not find serialiser for class type " + valueType); + } + buffer.putStringISO8859(serialiser.getClassPrototype().getTypeName()); // primary type + buffer.putStringISO8859(serialiser.getGenericsPrototypes().isEmpty() ? "" : serialiser.getGenericsPrototypes().get(0).getTypeName()); // secondary type if any + + final FieldSerialiser.TriConsumer writerFunction = serialiser.getWriterFunction(); + for (final Object value : values) { + writerFunction.accept(this, value, null); + } } - final int skipPosition = field.getDataStartPosition() + dataSize; - buffer.position(skipPosition); - } - } - @Override - public void put(final FieldDescription fieldDescription, final Collection collection, final Type valueType) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final Object[] values = collection.toArray(); - final int nElements = collection.size(); - final Class cleanedType = ClassUtils.getRawType(valueType); - final DataType valueDataType = DataType.fromClassType(cleanedType); - final int entrySize = 17; // as an initial estimate - putArraySizeDescriptor(nElements); - buffer.putInt(nElements); - - if (collection instanceof Queue) { - buffer.putByte(getDataType(DataType.QUEUE)); - } else if (collection instanceof Set) { - buffer.putByte(getDataType(DataType.SET)); - } else if (collection instanceof List) { - buffer.putByte(getDataType(DataType.LIST)); - } else { - buffer.putByte(getDataType(DataType.COLLECTION)); + updateDataEndMarker(fieldHeader); } - final BiFunction> serialiserLookup = getSerialiserLookupFunction(); - if (ClassUtils.isPrimitiveWrapperOrString(cleanedType) || serialiserLookup == null) { - buffer.ensureAdditionalCapacity((nElements * entrySize) + 9); - buffer.putByte(getDataType(valueDataType)); // write value element type - putGenericArrayAsPrimitive(valueDataType, values, nElements); - } else { - buffer.putByte(getDataType(DataType.OTHER)); // write value element type - final Type[] secondaryType = ClassUtils.getSecondaryType(valueType); - @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) - final FieldSerialiser serialiser = (FieldSerialiser) serialiserLookup.apply(valueType, secondaryType); - if (serialiser == null) { - throw new IllegalArgumentException("could not find serialiser for class type " + valueType); + @Override + public void put(final FieldDescription fieldDescription, final Enum enumeration) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + if (enumeration == null) { + return; } - buffer.putStringISO8859(serialiser.getClassPrototype().getTypeName()); // primary type - buffer.putStringISO8859(serialiser.getGenericsPrototypes().isEmpty() ? "" : serialiser.getGenericsPrototypes().get(0).getTypeName()); // secondary type if any - - final FieldSerialiser.TriConsumer writerFunction = serialiser.getWriterFunction(); - for (final Object value : values) { - writerFunction.accept(this, value, null); + @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) + final Class> clazz = (Class>) enumeration.getClass(); + final Enum[] enumConsts = clazz.getEnumConstants(); + if (enumConsts == null) { + return; } - } - updateDataEndMarker(fieldHeader); - } + final int nElements = 1; + final int entrySize = 17; // as an initial estimate - @Override - public void put(final FieldDescription fieldDescription, final Enum enumeration) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - if (enumeration == null) { - return; - } - @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) - final Class> clazz = (Class>) enumeration.getClass(); - final Enum[] enumConsts = clazz.getEnumConstants(); - if (enumConsts == null) { - return; + buffer.ensureAdditionalCapacity((nElements * entrySize) + 9); + final String typeList = Arrays.stream(clazz.getEnumConstants()).map(Object::toString).collect(Collectors.joining(", ", "[", "]")); + buffer.putStringISO8859(clazz.getSimpleName()); + buffer.putStringISO8859(enumeration.getClass().getName()); + buffer.putStringISO8859(typeList); + buffer.putStringISO8859(enumeration.name()); + buffer.putInt(enumeration.ordinal()); + + updateDataEndMarker(fieldHeader); } - final int nElements = 1; - final int entrySize = 17; // as an initial estimate + @Override + public void put(final FieldDescription fieldDescription, final Map map, Type keyType, Type valueType) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final Object[] keySet = map.keySet().toArray(); + final int nElements = keySet.length; + putArraySizeDescriptor(nElements); + buffer.putInt(nElements); // convert into two linear arrays one of K and the other for V streamer encoding as // <1 (int)> - updateDataEndMarker(fieldHeader); - } - - @Override - public void put(final FieldDescription fieldDescription, final Map map, Type keyType, Type valueType) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final Object[] keySet = map.keySet().toArray(); - final int nElements = keySet.length; - putArraySizeDescriptor(nElements); - buffer.putInt(nElements); - - // convert into two linear arrays one of K and the other for V streamer encoding as - // <1 (int)> - - final Class cleanedKeyType = ClassUtils.getRawType(keyType); - final DataType keyDataType = DataType.fromClassType(cleanedKeyType); - final BiFunction> serialiserLookup = getSerialiserLookupFunction(); - if (serialiserLookup == null || ClassUtils.isPrimitiveWrapperOrString(cleanedKeyType)) { - final int entrySize = 17; // as an initial estimate - buffer.ensureAdditionalCapacity((nElements * entrySize) + 9); - buffer.putByte(getDataType(keyDataType)); // write key element type - putGenericArrayAsPrimitive(keyDataType, keySet, nElements); - } else { - // write key type - buffer.putByte(getDataType(DataType.OTHER)); // write key element type - final Type[] secondaryKeyType = ClassUtils.getSecondaryType(keyType); - final FieldSerialiser serialiserKey = serialiserLookup.apply(keyType, secondaryKeyType); - if (serialiserKey == null) { - throw new IllegalArgumentException("could not find serialiser for key class type " + keyType); + final Class cleanedKeyType = ClassUtils.getRawType(keyType); + final DataType keyDataType = DataType.fromClassType(cleanedKeyType); + final BiFunction> serialiserLookup = getSerialiserLookupFunction(); + if (serialiserLookup == null || ClassUtils.isPrimitiveWrapperOrString(cleanedKeyType)) { + final int entrySize = 17; // as an initial estimate + buffer.ensureAdditionalCapacity((nElements * entrySize) + 9); + buffer.putByte(getDataType(keyDataType)); // write key element type + putGenericArrayAsPrimitive(keyDataType, keySet, nElements); + } else { + // write key type + buffer.putByte(getDataType(DataType.OTHER)); // write key element type + final Type[] secondaryKeyType = ClassUtils.getSecondaryType(keyType); + final FieldSerialiser serialiserKey = serialiserLookup.apply(keyType, secondaryKeyType); + if (serialiserKey == null) { + throw new IllegalArgumentException("could not find serialiser for key class type " + keyType); + } + buffer.putStringISO8859(serialiserKey.getClassPrototype().getTypeName()); // primary type + buffer.putStringISO8859(serialiserKey.getGenericsPrototypes().isEmpty() ? "" : serialiserKey.getGenericsPrototypes().get(0).getTypeName()); // secondary key type if any + // write key data + final FieldSerialiser.TriConsumer writerFunctionKey = serialiserKey.getWriterFunction(); + for (final Object key : keySet) { + writerFunctionKey.accept(this, key, null); + } } - buffer.putStringISO8859(serialiserKey.getClassPrototype().getTypeName()); // primary type - buffer.putStringISO8859(serialiserKey.getGenericsPrototypes().isEmpty() ? "" : serialiserKey.getGenericsPrototypes().get(0).getTypeName()); // secondary key type if any - // write key data - final FieldSerialiser.TriConsumer writerFunctionKey = serialiserKey.getWriterFunction(); - for (final Object key : keySet) { - writerFunctionKey.accept(this, key, null); + + final Class cleanedValueType = ClassUtils.getRawType(valueType); + final Object[] valueSet = map.values().toArray(); + final DataType valueDataType = DataType.fromClassType(cleanedValueType); + if (serialiserLookup == null || ClassUtils.isPrimitiveWrapperOrString(cleanedValueType)) { + final int entrySize = 17; // as an initial estimate + buffer.ensureAdditionalCapacity((nElements * entrySize) + 9); + buffer.putByte(getDataType(valueDataType)); // write value element type + putGenericArrayAsPrimitive(valueDataType, valueSet, nElements); + } else { + // write value type + buffer.putByte(getDataType(DataType.OTHER)); // write key element type + final Type[] secondaryValueType = ClassUtils.getSecondaryType(valueType); + final FieldSerialiser serialiserValue = serialiserLookup.apply(valueType, secondaryValueType); + if (serialiserValue == null) { + throw new IllegalArgumentException("could not find serialiser for value class type " + valueType); + } + buffer.putStringISO8859(serialiserValue.getClassPrototype().getTypeName()); // primary type + buffer.putStringISO8859(serialiserValue.getGenericsPrototypes().isEmpty() ? "" : serialiserValue.getGenericsPrototypes().get(0).getTypeName()); // secondary key type if any + + // write key data + final FieldSerialiser.TriConsumer writerFunctionValue = serialiserValue.getWriterFunction(); + for (final Object value : valueSet) { + writerFunctionValue.accept(this, value, null); + } } + updateDataEndMarker(fieldHeader); } - final Class cleanedValueType = ClassUtils.getRawType(valueType); - final Object[] valueSet = map.values().toArray(); - final DataType valueDataType = DataType.fromClassType(cleanedValueType); - if (serialiserLookup == null || ClassUtils.isPrimitiveWrapperOrString(cleanedValueType)) { - final int entrySize = 17; // as an initial estimate - buffer.ensureAdditionalCapacity((nElements * entrySize) + 9); - buffer.putByte(getDataType(valueDataType)); // write value element type - putGenericArrayAsPrimitive(valueDataType, valueSet, nElements); - } else { - // write value type - buffer.putByte(getDataType(DataType.OTHER)); // write key element type - final Type[] secondaryValueType = ClassUtils.getSecondaryType(valueType); - final FieldSerialiser serialiserValue = serialiserLookup.apply(valueType, secondaryValueType); - if (serialiserValue == null) { - throw new IllegalArgumentException("could not find serialiser for value class type " + valueType); + @Override + public void put(final String fieldName, final Collection collection, final Type valueType) { + final DataType dataType; + if (collection instanceof Queue) { + dataType = DataType.QUEUE; + } else if (collection instanceof Set) { + dataType = DataType.SET; + } else if (collection instanceof List) { + dataType = DataType.LIST; + } else { + dataType = DataType.COLLECTION; } - buffer.putStringISO8859(serialiserValue.getClassPrototype().getTypeName()); // primary type - buffer.putStringISO8859(serialiserValue.getGenericsPrototypes().isEmpty() ? "" : serialiserValue.getGenericsPrototypes().get(0).getTypeName()); // secondary key type if any - // write key data - final FieldSerialiser.TriConsumer writerFunctionValue = serialiserValue.getWriterFunction(); - for (final Object value : valueSet) { - writerFunctionValue.accept(this, value, null); - } + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, dataType); + this.put((FieldDescription) null, collection, valueType); + this.updateDataEndMarker(fieldHeader); } - updateDataEndMarker(fieldHeader); - } - @Override - public void put(final String fieldName, final Collection collection, final Type valueType) { - final DataType dataType; - if (collection instanceof Queue) { - dataType = DataType.QUEUE; - } else if (collection instanceof Set) { - dataType = DataType.SET; - } else if (collection instanceof List) { - dataType = DataType.LIST; - } else { - dataType = DataType.COLLECTION; + @Override + public void put(final String fieldName, final Enum enumeration) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.ENUM); + this.put((FieldDescription) null, enumeration); + this.updateDataEndMarker(fieldHeader); } - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, dataType); - this.put((FieldDescription) null, collection, valueType); - this.updateDataEndMarker(fieldHeader); - } - - @Override - public void put(final String fieldName, final Enum enumeration) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.ENUM); - this.put((FieldDescription) null, enumeration); - this.updateDataEndMarker(fieldHeader); - } - - @Override - public void put(final String fieldName, final Map map, final Type keyType, final Type valueType) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.MAP); - this.put((FieldDescription) null, map, keyType, valueType); - this.updateDataEndMarker(fieldHeader); - } - - @Override - public void put(final FieldDescription fieldDescription, final boolean value) { - this.putFieldHeader(fieldDescription); - buffer.putBoolean(value); - } - - @Override - public void put(final FieldDescription fieldDescription, final boolean[] values, final int n) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final int valuesSize = values == null ? 0 : values.length; - final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); - buffer.putBooleanArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } - - @Override - public void put(final FieldDescription fieldDescription, final boolean[] values, final int[] dims) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final int bytesToCopy = putArraySizeDescriptor(dims); - buffer.putBooleanArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final String fieldName, final Map map, final Type keyType, final Type valueType) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.MAP); + this.put((FieldDescription) null, map, keyType, valueType); + this.updateDataEndMarker(fieldHeader); + } - @Override - public void put(final FieldDescription fieldDescription, final byte value) { - this.putFieldHeader(fieldDescription); - buffer.putByte(value); - } + @Override + public void put(final FieldDescription fieldDescription, final boolean value) { + this.putFieldHeader(fieldDescription); + buffer.putBoolean(value); + } - @Override - public void put(final FieldDescription fieldDescription, final byte[] values, final int n) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final int valuesSize = values == null ? 0 : values.length; - final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); - buffer.putByteArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final boolean[] values, final int n) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final int valuesSize = values == null ? 0 : values.length; + final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); + buffer.putBooleanArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final FieldDescription fieldDescription, final byte[] values, final int[] dims) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final int bytesToCopy = putArraySizeDescriptor(dims); - buffer.putByteArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final boolean[] values, final int[] dims) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final int bytesToCopy = putArraySizeDescriptor(dims); + buffer.putBooleanArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final FieldDescription fieldDescription, final char value) { - this.putFieldHeader(fieldDescription); - buffer.putChar(value); - } + @Override + public void put(final FieldDescription fieldDescription, final byte value) { + this.putFieldHeader(fieldDescription); + buffer.putByte(value); + } - @Override - public void put(final FieldDescription fieldDescription, final char[] values, final int n) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final int valuesSize = values == null ? 0 : values.length; - final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); - buffer.putCharArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final byte[] values, final int n) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final int valuesSize = values == null ? 0 : values.length; + final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); + buffer.putByteArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final FieldDescription fieldDescription, final char[] values, final int[] dims) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final int bytesToCopy = putArraySizeDescriptor(dims); - buffer.putCharArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final byte[] values, final int[] dims) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final int bytesToCopy = putArraySizeDescriptor(dims); + buffer.putByteArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final FieldDescription fieldDescription, final double value) { - this.putFieldHeader(fieldDescription); - buffer.putDouble(value); - } + @Override + public void put(final FieldDescription fieldDescription, final char value) { + this.putFieldHeader(fieldDescription); + buffer.putChar(value); + } - @Override - public void put(final FieldDescription fieldDescription, final double[] values, final int n) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final int valuesSize = values == null ? 0 : values.length; - final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); - buffer.putDoubleArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final char[] values, final int n) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final int valuesSize = values == null ? 0 : values.length; + final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); + buffer.putCharArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final FieldDescription fieldDescription, final double[] values, final int[] dims) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final int bytesToCopy = putArraySizeDescriptor(dims); - buffer.putDoubleArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final char[] values, final int[] dims) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final int bytesToCopy = putArraySizeDescriptor(dims); + buffer.putCharArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final FieldDescription fieldDescription, final float value) { - this.putFieldHeader(fieldDescription); - buffer.putFloat(value); - } + @Override + public void put(final FieldDescription fieldDescription, final double value) { + this.putFieldHeader(fieldDescription); + buffer.putDouble(value); + } - @Override - public void put(final FieldDescription fieldDescription, final float[] values, final int n) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final int valuesSize = values == null ? 0 : values.length; - final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); - buffer.putFloatArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final double[] values, final int n) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final int valuesSize = values == null ? 0 : values.length; + final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); + buffer.putDoubleArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final FieldDescription fieldDescription, final float[] values, final int[] dims) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final int bytesToCopy = putArraySizeDescriptor(dims); - buffer.putFloatArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final double[] values, final int[] dims) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final int bytesToCopy = putArraySizeDescriptor(dims); + buffer.putDoubleArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final FieldDescription fieldDescription, final int value) { - this.putFieldHeader(fieldDescription); - buffer.putInt(value); - } + @Override + public void put(final FieldDescription fieldDescription, final float value) { + this.putFieldHeader(fieldDescription); + buffer.putFloat(value); + } - @Override - public void put(final FieldDescription fieldDescription, final int[] values, final int n) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final int valuesSize = values == null ? 0 : values.length; - final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); - buffer.putIntArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final float[] values, final int n) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final int valuesSize = values == null ? 0 : values.length; + final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); + buffer.putFloatArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final FieldDescription fieldDescription, final int[] values, final int[] dims) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final int bytesToCopy = putArraySizeDescriptor(dims); - buffer.putIntArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final float[] values, final int[] dims) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final int bytesToCopy = putArraySizeDescriptor(dims); + buffer.putFloatArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final FieldDescription fieldDescription, final long value) { - this.putFieldHeader(fieldDescription); - buffer.putLong(value); - } + @Override + public void put(final FieldDescription fieldDescription, final int value) { + this.putFieldHeader(fieldDescription); + buffer.putInt(value); + } - @Override - public void put(final FieldDescription fieldDescription, final long[] values, final int n) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final int valuesSize = values == null ? 0 : values.length; - final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); - buffer.putLongArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final int[] values, final int n) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final int valuesSize = values == null ? 0 : values.length; + final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); + buffer.putIntArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final FieldDescription fieldDescription, final long[] values, final int[] dims) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final int bytesToCopy = putArraySizeDescriptor(dims); - buffer.putLongArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final int[] values, final int[] dims) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final int bytesToCopy = putArraySizeDescriptor(dims); + buffer.putIntArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final FieldDescription fieldDescription, final short value) { // NOPMD by rstein - this.putFieldHeader(fieldDescription); - buffer.putShort(value); - } + @Override + public void put(final FieldDescription fieldDescription, final long value) { + this.putFieldHeader(fieldDescription); + buffer.putLong(value); + } - @Override - public void put(final FieldDescription fieldDescription, final short[] values, final int n) { // NOPMD by rstein - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final int valuesSize = values == null ? 0 : values.length; - final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); - buffer.putShortArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final long[] values, final int n) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final int valuesSize = values == null ? 0 : values.length; + final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); + buffer.putLongArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final FieldDescription fieldDescription, final short[] values, final int[] dims) { // NOPMD by rstein - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final int bytesToCopy = putArraySizeDescriptor(dims); - buffer.putShortArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final long[] values, final int[] dims) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final int bytesToCopy = putArraySizeDescriptor(dims); + buffer.putLongArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final FieldDescription fieldDescription, final String string) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - buffer.putString(string); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final short value) { // NOPMD by rstein + this.putFieldHeader(fieldDescription); + buffer.putShort(value); + } - @Override - public void put(final FieldDescription fieldDescription, final String[] values, final int n) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final int valuesSize = values == null ? 0 : values.length; - final int nElements = n >= 0 ? Math.min(n, valuesSize) : valuesSize; - putArraySizeDescriptor(nElements); - buffer.putStringArray(values, nElements); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final short[] values, final int n) { // NOPMD by rstein + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final int valuesSize = values == null ? 0 : values.length; + final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); + buffer.putShortArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final FieldDescription fieldDescription, final String[] values, final int[] dims) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); - final int nElements = putArraySizeDescriptor(dims); - putArraySizeDescriptor(nElements); - buffer.putStringArray(values, nElements); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final short[] values, final int[] dims) { // NOPMD by rstein + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final int bytesToCopy = putArraySizeDescriptor(dims); + buffer.putShortArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final boolean value) { - this.putFieldHeader(fieldName, DataType.BOOL); - buffer.putBoolean(value); - } + @Override + public void put(final FieldDescription fieldDescription, final String string) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + buffer.putString(string); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final boolean[] values, final int n) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.BOOL_ARRAY); - final int valuesSize = values == null ? 0 : values.length; - final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); - buffer.putBooleanArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final String[] values, final int n) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final int valuesSize = values == null ? 0 : values.length; + final int nElements = n >= 0 ? Math.min(n, valuesSize) : valuesSize; + putArraySizeDescriptor(nElements); + buffer.putStringArray(values, nElements); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final boolean[] values, final int[] dims) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.BOOL_ARRAY); - final int bytesToCopy = putArraySizeDescriptor(dims); - buffer.putBooleanArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final FieldDescription fieldDescription, final String[] values, final int[] dims) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldDescription); + final int nElements = putArraySizeDescriptor(dims); + putArraySizeDescriptor(nElements); + buffer.putStringArray(values, nElements); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final byte value) { - this.putFieldHeader(fieldName, DataType.BYTE); - buffer.putByte(value); - } + @Override + public void put(final String fieldName, final boolean value) { + this.putFieldHeader(fieldName, DataType.BOOL); + buffer.putBoolean(value); + } - @Override - public void put(final String fieldName, final byte[] values, final int n) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.BYTE_ARRAY); - final int valuesSize = values == null ? 0 : values.length; - final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); - buffer.putByteArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final String fieldName, final boolean[] values, final int n) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.BOOL_ARRAY); + final int valuesSize = values == null ? 0 : values.length; + final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); + buffer.putBooleanArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final byte[] values, final int[] dims) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.BYTE_ARRAY); - final int bytesToCopy = putArraySizeDescriptor(dims); - buffer.putByteArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final String fieldName, final boolean[] values, final int[] dims) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.BOOL_ARRAY); + final int bytesToCopy = putArraySizeDescriptor(dims); + buffer.putBooleanArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final char value) { - this.putFieldHeader(fieldName, DataType.CHAR); - buffer.putChar(value); - } + @Override + public void put(final String fieldName, final byte value) { + this.putFieldHeader(fieldName, DataType.BYTE); + buffer.putByte(value); + } - @Override - public void put(final String fieldName, final char[] values, final int n) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.CHAR_ARRAY); - final int valuesSize = values == null ? 0 : values.length; - final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); - buffer.putCharArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final String fieldName, final byte[] values, final int n) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.BYTE_ARRAY); + final int valuesSize = values == null ? 0 : values.length; + final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); + buffer.putByteArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final char[] values, final int[] dims) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.CHAR_ARRAY); - final int bytesToCopy = putArraySizeDescriptor(dims); - buffer.putCharArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final String fieldName, final byte[] values, final int[] dims) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.BYTE_ARRAY); + final int bytesToCopy = putArraySizeDescriptor(dims); + buffer.putByteArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final double value) { - this.putFieldHeader(fieldName, DataType.DOUBLE); - buffer.putDouble(value); - } + @Override + public void put(final String fieldName, final char value) { + this.putFieldHeader(fieldName, DataType.CHAR); + buffer.putChar(value); + } - @Override - public void put(final String fieldName, final double[] values, final int n) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.DOUBLE_ARRAY); - final int valuesSize = values == null ? 0 : values.length; - final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); - buffer.putDoubleArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final String fieldName, final char[] values, final int n) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.CHAR_ARRAY); + final int valuesSize = values == null ? 0 : values.length; + final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); + buffer.putCharArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final double[] values, final int[] dims) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.DOUBLE_ARRAY); - final int bytesToCopy = putArraySizeDescriptor(dims); - buffer.putDoubleArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final String fieldName, final char[] values, final int[] dims) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.CHAR_ARRAY); + final int bytesToCopy = putArraySizeDescriptor(dims); + buffer.putCharArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final float value) { - this.putFieldHeader(fieldName, DataType.FLOAT); - buffer.putFloat(value); - } + @Override + public void put(final String fieldName, final double value) { + this.putFieldHeader(fieldName, DataType.DOUBLE); + buffer.putDouble(value); + } - @Override - public void put(final String fieldName, final float[] values, final int n) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.FLOAT_ARRAY); - final int valuesSize = values == null ? 0 : values.length; - final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); - buffer.putFloatArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final String fieldName, final double[] values, final int n) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.DOUBLE_ARRAY); + final int valuesSize = values == null ? 0 : values.length; + final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); + buffer.putDoubleArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final float[] values, final int[] dims) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.FLOAT_ARRAY); - final int bytesToCopy = putArraySizeDescriptor(dims); - buffer.putFloatArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final String fieldName, final double[] values, final int[] dims) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.DOUBLE_ARRAY); + final int bytesToCopy = putArraySizeDescriptor(dims); + buffer.putDoubleArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final int value) { - this.putFieldHeader(fieldName, DataType.INT); - buffer.putInt(value); - } + @Override + public void put(final String fieldName, final float value) { + this.putFieldHeader(fieldName, DataType.FLOAT); + buffer.putFloat(value); + } - @Override - public void put(final String fieldName, final int[] values, final int n) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.INT_ARRAY); - final int valuesSize = values == null ? 0 : values.length; - final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); - buffer.putIntArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final String fieldName, final float[] values, final int n) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.FLOAT_ARRAY); + final int valuesSize = values == null ? 0 : values.length; + final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); + buffer.putFloatArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final int[] values, final int[] dims) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.INT_ARRAY); - final int bytesToCopy = putArraySizeDescriptor(dims); - buffer.putIntArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final String fieldName, final float[] values, final int[] dims) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.FLOAT_ARRAY); + final int bytesToCopy = putArraySizeDescriptor(dims); + buffer.putFloatArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final long value) { - this.putFieldHeader(fieldName, DataType.LONG); - buffer.putLong(value); - } + @Override + public void put(final String fieldName, final int value) { + this.putFieldHeader(fieldName, DataType.INT); + buffer.putInt(value); + } - @Override - public void put(final String fieldName, final long[] values, final int n) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.LONG_ARRAY); - final int valuesSize = values == null ? 0 : values.length; - final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); - buffer.putLongArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final String fieldName, final int[] values, final int n) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.INT_ARRAY); + final int valuesSize = values == null ? 0 : values.length; + final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); + buffer.putIntArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final long[] values, final int[] dims) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.LONG_ARRAY); - final int bytesToCopy = putArraySizeDescriptor(dims); - buffer.putLongArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final String fieldName, final int[] values, final int[] dims) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.INT_ARRAY); + final int bytesToCopy = putArraySizeDescriptor(dims); + buffer.putIntArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final short value) { // NOPMD by rstein - this.putFieldHeader(fieldName, DataType.SHORT); - buffer.putShort(value); - } + @Override + public void put(final String fieldName, final long value) { + this.putFieldHeader(fieldName, DataType.LONG); + buffer.putLong(value); + } - @Override - public void put(final String fieldName, final short[] values, final int n) { // NOPMD by rstein - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.SHORT_ARRAY); - final int valuesSize = values == null ? 0 : values.length; - final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); - buffer.putShortArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final String fieldName, final long[] values, final int n) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.LONG_ARRAY); + final int valuesSize = values == null ? 0 : values.length; + final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); + buffer.putLongArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final short[] values, final int[] dims) { // NOPMD by rstein - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.SHORT_ARRAY); - final int bytesToCopy = putArraySizeDescriptor(dims); - buffer.putShortArray(values, bytesToCopy); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final String fieldName, final long[] values, final int[] dims) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.LONG_ARRAY); + final int bytesToCopy = putArraySizeDescriptor(dims); + buffer.putLongArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final String string) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.STRING); - buffer.putString(string); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final String fieldName, final short value) { // NOPMD by rstein + this.putFieldHeader(fieldName, DataType.SHORT); + buffer.putShort(value); + } - @Override - public void put(final String fieldName, final String[] values, final int n) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.STRING_ARRAY); - final int valuesSize = values == null ? 0 : values.length; - final int nElements = n >= 0 ? Math.min(n, valuesSize) : valuesSize; - putArraySizeDescriptor(nElements); - buffer.putStringArray(values, nElements); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final String fieldName, final short[] values, final int n) { // NOPMD by rstein + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.SHORT_ARRAY); + final int valuesSize = values == null ? 0 : values.length; + final int bytesToCopy = putArraySizeDescriptor(n >= 0 ? Math.min(n, valuesSize) : valuesSize); + buffer.putShortArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public void put(final String fieldName, final String[] values, final int[] dims) { - final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.STRING_ARRAY); - final int nElements = putArraySizeDescriptor(dims); - putArraySizeDescriptor(nElements); - buffer.putStringArray(values, nElements); - updateDataEndMarker(fieldHeader); - } + @Override + public void put(final String fieldName, final short[] values, final int[] dims) { // NOPMD by rstein + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.SHORT_ARRAY); + final int bytesToCopy = putArraySizeDescriptor(dims); + buffer.putShortArray(values, bytesToCopy); + updateDataEndMarker(fieldHeader); + } - @Override - public int putArraySizeDescriptor(final int n) { - buffer.putInt(1); // number of dimensions - buffer.putInt(n); // vector size for each dimension - return n; - } + @Override + public void put(final String fieldName, final String string) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.STRING); + buffer.putString(string); + updateDataEndMarker(fieldHeader); + } - @Override - public int putArraySizeDescriptor(final int[] dims) { - buffer.putInt(dims.length); // number of dimensions - int nElements = 1; - for (final int dim : dims) { - nElements *= dim; - buffer.putInt(dim); // vector size for each dimension - } - return nElements; - } + @Override + public void put(final String fieldName, final String[] values, final int n) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.STRING_ARRAY); + final int valuesSize = values == null ? 0 : values.length; + final int nElements = n >= 0 ? Math.min(n, valuesSize) : valuesSize; + putArraySizeDescriptor(nElements); + buffer.putStringArray(values, nElements); + updateDataEndMarker(fieldHeader); + } - @Override - public WireDataFieldDescription putCustomData(final FieldDescription fieldDescription, final E rootObject, Class type, final FieldSerialiser serialiser) { - if (parent == null) { - parent = lastFieldHeader = getRootElement(); + @Override + public void put(final String fieldName, final String[] values, final int[] dims) { + final WireDataFieldDescription fieldHeader = putFieldHeader(fieldName, DataType.STRING_ARRAY); + final int nElements = putArraySizeDescriptor(dims); + putArraySizeDescriptor(nElements); + buffer.putStringArray(values, nElements); + updateDataEndMarker(fieldHeader); } - final WireDataFieldDescription oldParent = parent; - final WireDataFieldDescription ret = putFieldHeader(fieldDescription); - buffer.putByte(ret.getFieldStart(), getDataType(DataType.OTHER)); - parent = lastFieldHeader; - // write generic class description and type arguments (if any) to aid reconstruction - buffer.putStringISO8859(serialiser.getClassPrototype().getTypeName()); // primary type - buffer.putStringISO8859(serialiser.getGenericsPrototypes().isEmpty() ? "" : serialiser.getGenericsPrototypes().get(0).getTypeName()); // secondary type if any - serialiser.getWriterFunction().accept(this, rootObject, fieldDescription instanceof ClassFieldDescription ? (ClassFieldDescription) fieldDescription : null); - putEndMarker(fieldDescription); - parent = oldParent; - return ret; - } - @Override - public void putEndMarker(final FieldDescription fieldDescription) { - updateDataEndMarker(parent); - updateDataEndMarker(lastFieldHeader); - if (parent.getParent() != null) { - parent = (WireDataFieldDescription) parent.getParent(); + @Override + public int putArraySizeDescriptor(final int n) { + buffer.putInt(1); // number of dimensions + buffer.putInt(n); // vector size for each dimension + return n; } - putFieldHeader(fieldDescription); - buffer.putByte(lastFieldHeader.getFieldStart(), getDataType(DataType.END_MARKER)); - } + @Override + public int putArraySizeDescriptor(final int[] dims) { + buffer.putInt(dims.length); // number of dimensions + int nElements = 1; + for (final int dim : dims) { + nElements *= dim; + buffer.putInt(dim); // vector size for each dimension + } + return nElements; + } - @Override - public WireDataFieldDescription putFieldHeader(final FieldDescription fieldDescription) { - if (fieldDescription == null) { - // early return - return null; + @Override + public WireDataFieldDescription putCustomData(final FieldDescription fieldDescription, final E rootObject, Class type, final FieldSerialiser serialiser) { + if (parent == null) { + parent = lastFieldHeader = getRootElement(); + } + final WireDataFieldDescription oldParent = parent; + final WireDataFieldDescription ret = putFieldHeader(fieldDescription); + buffer.putByte(ret.getFieldStart(), getDataType(DataType.OTHER)); + parent = lastFieldHeader; + // write generic class description and type arguments (if any) to aid reconstruction + buffer.putStringISO8859(serialiser.getClassPrototype().getTypeName()); // primary type + buffer.putStringISO8859(serialiser.getGenericsPrototypes().isEmpty() ? "" : serialiser.getGenericsPrototypes().get(0).getTypeName()); // secondary type if any + serialiser.getWriterFunction().accept(this, rootObject, fieldDescription instanceof ClassFieldDescription ? (ClassFieldDescription) fieldDescription : null); + putEndMarker(fieldDescription); + parent = oldParent; + return ret; } - final DataType dataType = fieldDescription.getDataType(); - if (isPutFieldMetaData()) { - buffer.ensureAdditionalCapacity(bufferIncrements); + + @Override + public void putEndMarker(final FieldDescription fieldDescription) { + updateDataEndMarker(parent); + updateDataEndMarker(lastFieldHeader); + if (parent.getParent() != null) { + parent = (WireDataFieldDescription) parent.getParent(); + } + + putFieldHeader(fieldDescription); + buffer.putByte(lastFieldHeader.getFieldStart(), getDataType(DataType.END_MARKER)); } - final boolean isScalar = dataType.isScalar(); @Override public WireDataFieldDescription putFieldHeader(final FieldDescription fieldDescription) { @@ -1472,12 +1470,17 @@ public WireDataFieldDescription putFieldHeader(final FieldDescription fieldDescr final int dataStartOffset = buffer.position() - headerStart; buffer.putInt(headerStart + 1, dataStartOffset); // write offset to dataStart - if (isPutFieldMetaData() && fieldDescription.isAnnotationPresent() && dataType != DataType.END_MARKER) { - buffer.putString(fieldDescription.getFieldUnit()); - buffer.putString(fieldDescription.getFieldDescription()); - buffer.putString(fieldDescription.getFieldDirection()); - final String[] groups = fieldDescription.getFieldGroups().toArray(new String[0]); - buffer.putStringArray(groups, groups.length); + // from hereon there are data-specific structures + buffer.ensureAdditionalCapacity(16); // allocate 16 bytes to account for a potential array header (safe-bet) + + lastFieldHeader = new WireDataFieldDescription(this, parent, fieldDescription.getFieldName(), dataType, headerStart, dataStartOffset, dataSize); + if (isPutFieldMetaData() && fieldDescription.isAnnotationPresent()) { + lastFieldHeader.setFieldUnit(fieldDescription.getFieldUnit()); + lastFieldHeader.setFieldDescription(fieldDescription.getFieldDescription()); + lastFieldHeader.setFieldDirection(fieldDescription.getFieldDirection()); + lastFieldHeader.setFieldGroups(fieldDescription.getFieldGroups()); + } + return lastFieldHeader; } @Override @@ -1501,65 +1504,73 @@ public WireDataFieldDescription putFieldHeader(final String fieldName, final Dat final int dataStartOffset = (fieldHeaderDataStart - headerStart); buffer.putInt(headerStart + 1, dataStartOffset); // write offset to dataStart - public void putGenericArrayAsPrimitive(final DataType dataType, final Object[] data, final int nToCopy) { - putArraySizeDescriptor(nToCopy); - switch (dataType) { - case BOOL: - buffer.putBooleanArray(GenericsHelper.toBoolPrimitive(data), nToCopy); - break; - case BYTE: - buffer.putByteArray(GenericsHelper.toBytePrimitive(data), nToCopy); - break; - case CHAR: - buffer.putCharArray(GenericsHelper.toCharPrimitive(data), nToCopy); - break; - case SHORT: - buffer.putShortArray(GenericsHelper.toShortPrimitive(data), nToCopy); - break; - case INT: - buffer.putIntArray(GenericsHelper.toIntegerPrimitive(data), nToCopy); - break; - case LONG: - buffer.putLongArray(GenericsHelper.toLongPrimitive(data), nToCopy); - break; - case FLOAT: - buffer.putFloatArray(GenericsHelper.toFloatPrimitive(data), nToCopy); - break; - case DOUBLE: - buffer.putDoubleArray(GenericsHelper.toDoublePrimitive(data), nToCopy); - break; - case STRING: - buffer.putStringArray(GenericsHelper.toStringPrimitive(data), nToCopy); - break; - case OTHER: - break; - default: - throw new IllegalArgumentException("type not implemented - " + data[0].getClass().getSimpleName()); - } - } + // from hereon there are data-specific structures + buffer.ensureAdditionalCapacity(16); // allocate 16 bytes to account for a potential array header (safe-bet) lastFieldHeader = new WireDataFieldDescription(this, parent, fieldName, dataType, headerStart, dataStartOffset, dataSize); return lastFieldHeader; } - } - @Override - public void putStartMarker(final FieldDescription fieldDescription) { - putFieldHeader(fieldDescription); - buffer.putByte(lastFieldHeader.getFieldStart(), getDataType(DataType.START_MARKER)); + public void putGenericArrayAsPrimitive(final DataType dataType, final Object[] data, final int nToCopy) { + putArraySizeDescriptor(nToCopy); + switch (dataType) { + case BOOL: + buffer.putBooleanArray(GenericsHelper.toBoolPrimitive(data), nToCopy); + break; + case BYTE: + buffer.putByteArray(GenericsHelper.toBytePrimitive(data), nToCopy); + break; + case CHAR: + buffer.putCharArray(GenericsHelper.toCharPrimitive(data), nToCopy); + break; + case SHORT: + buffer.putShortArray(GenericsHelper.toShortPrimitive(data), nToCopy); + break; + case INT: + buffer.putIntArray(GenericsHelper.toIntegerPrimitive(data), nToCopy); + break; + case LONG: + buffer.putLongArray(GenericsHelper.toLongPrimitive(data), nToCopy); + break; + case FLOAT: + buffer.putFloatArray(GenericsHelper.toFloatPrimitive(data), nToCopy); + break; + case DOUBLE: + buffer.putDoubleArray(GenericsHelper.toDoublePrimitive(data), nToCopy); + break; + case STRING: + buffer.putStringArray(GenericsHelper.toStringPrimitive(data), nToCopy); + break; + case OTHER: + break; + default: + throw new IllegalArgumentException("type not implemented - " + data[0].getClass().getSimpleName()); + } + } - parent = lastFieldHeader; - } + @Override + public void putHeaderInfo(final FieldDescription... field) { + parent = lastFieldHeader = getRootElement(); - @Override - public void updateDataEndMarker(final WireDataFieldDescription fieldHeader) { - if (fieldHeader == null) { - // N.B. early return in case field header hasn't been written - return; + buffer.ensureAdditionalCapacity(ADDITIONAL_HEADER_INFO_SIZE); + buffer.putInt(VERSION_MAGIC_NUMBER); + buffer.putStringISO8859(PROTOCOL_NAME); + buffer.putByte(VERSION_MAJOR); + buffer.putByte(VERSION_MINOR); + buffer.putByte(VERSION_MICRO); + if (field.length == 0 || field[0] == null) { + putStartMarker(new WireDataFieldDescription(this, null, "OBJ_ROOT_START", DataType.START_MARKER, -1, -1, -1)); + } else { + putStartMarker(field[0]); + } } - final int sizeMarkerEnd = buffer.position(); - if (isPutFieldMetaData() && sizeMarkerEnd >= buffer.capacity()) { - throw new IllegalStateException("buffer position " + sizeMarkerEnd + " is beyond buffer capacity " + buffer.capacity()); + + @Override + public void putStartMarker(final FieldDescription fieldDescription) { + putFieldHeader(fieldDescription); + buffer.putByte(lastFieldHeader.getFieldStart(), getDataType(DataType.START_MARKER)); + + parent = lastFieldHeader; } @Override @@ -1580,17 +1591,16 @@ public void updateDataEndMarker(final WireDataFieldDescription fieldHeader) { buffer.putInt(headerStart + 5, dataSize); // 5 bytes = 1 byte for dataType, 4 bytes for dataOffset } } - } - @Override - public void setFieldSerialiserLookupFunction(final BiFunction> serialiserLookupFunction) { - this.fieldSerialiserLookupFunction = serialiserLookupFunction; - } + @Override + public void setFieldSerialiserLookupFunction(final BiFunction> serialiserLookupFunction) { + this.fieldSerialiserLookupFunction = serialiserLookupFunction; + } - @Override - public BiFunction> getSerialiserLookupFunction() { - return fieldSerialiserLookupFunction; - } + @Override + public BiFunction> getSerialiserLookupFunction() { + return fieldSerialiserLookupFunction; + } @SuppressWarnings(UNCHECKED_CAST_SUPPRESSION) protected E[] getGenericArrayAsBoxedPrimitive(final DataType dataType) { diff --git a/serialiser/src/main/java/io/opencmw/serialiser/spi/iobuffer/DataSetSerialiser.java b/serialiser/src/main/java/io/opencmw/serialiser/spi/iobuffer/DataSetSerialiser.java index e1229edd..68d4750c 100644 --- a/serialiser/src/main/java/io/opencmw/serialiser/spi/iobuffer/DataSetSerialiser.java +++ b/serialiser/src/main/java/io/opencmw/serialiser/spi/iobuffer/DataSetSerialiser.java @@ -243,85 +243,114 @@ protected void parseHeaders(final IoSerialiser ioSerialiser, final DataSetBuilde // check for axis descriptions (all fields starting with AXIS) for (FieldDescription fieldDescription : fieldRoot.getChildren()) { - parseHeader(ioSerialiser, builder, fieldDescription); - } - } - - protected void parseMetaData(final IoSerialiser ioSerialiser, final DataSetBuilder builder, final FieldDescription rootField) { - if (checkFieldCompatibility(rootField, INFO_LIST.hashCode(), INFO_LIST, DataType.STRING_ARRAY) != null) { - builder.setMetaInfoList(ioSerialiser.getStringArray()); - } + parseHeader(ioSerialiser, builder, fieldDescription); + } + } - if (checkFieldCompatibility(rootField, WARNING_LIST.hashCode(), WARNING_LIST, DataType.STRING_ARRAY) != null) { - builder.setMetaWarningList(ioSerialiser.getStringArray()); - } + protected void parseMetaData(final IoSerialiser ioSerialiser, final DataSetBuilder builder, final FieldDescription rootField) { + if (checkFieldCompatibility(rootField, INFO_LIST.hashCode(), INFO_LIST, DataType.STRING_ARRAY) != null) { + builder.setMetaInfoList(ioSerialiser.getStringArray()); + } - if (checkFieldCompatibility(rootField, ERROR_LIST.hashCode(), ERROR_LIST, DataType.STRING_ARRAY) != null) { - builder.setMetaErrorList(ioSerialiser.getStringArray()); - } + if (checkFieldCompatibility(rootField, WARNING_LIST.hashCode(), WARNING_LIST, DataType.STRING_ARRAY) != null) { + builder.setMetaWarningList(ioSerialiser.getStringArray()); + } - if (checkFieldCompatibility(rootField, META_INFO.hashCode(), META_INFO, DataType.MAP) != null) { - Map map = new HashMap<>(); // NOPMD - thread-safe usage - map = ioSerialiser.getMap(map); - builder.setMetaInfoMap(map); - } - } + if (checkFieldCompatibility(rootField, ERROR_LIST.hashCode(), ERROR_LIST, DataType.STRING_ARRAY) != null) { + builder.setMetaErrorList(ioSerialiser.getStringArray()); + } - protected void parseNumericData(final IoSerialiser ioSerialiser, final DataSetBuilder builder, final DataSet origDataSet, final FieldDescription rootField) { - // check for numeric data - for (FieldDescription fieldDescription : rootField.getChildren()) { - final String fieldName = fieldDescription.getFieldName(); - if (fieldName == null || (fieldDescription.getDataType() != DataType.DOUBLE_ARRAY && fieldDescription.getDataType() != DataType.FLOAT_ARRAY)) { - continue; - } - if (fieldName.startsWith(ARRAY_PREFIX)) { - readValues(ioSerialiser, builder, origDataSet, fieldDescription, fieldName); - } else if (fieldName.startsWith(EP_PREFIX)) { - readPosError(ioSerialiser, builder, origDataSet, fieldDescription, fieldName); - } else if (fieldName.startsWith(EN_PREFIX)) { - readNegError(ioSerialiser, builder, origDataSet, fieldDescription, fieldName); + if (checkFieldCompatibility(rootField, META_INFO.hashCode(), META_INFO, DataType.MAP) != null) { + Map map = new HashMap<>(); // NOPMD - thread-safe usage + map = ioSerialiser.getMap(map); + builder.setMetaInfoMap(map); + } } - } - } - @SuppressWarnings("PMD.NPathComplexity") - protected void writeDataLabelsToStream(final DataSet dataSet) { - if (dataSet instanceof AbstractDataSet) { - final StringHashMapList labelMap = ((AbstractDataSet) dataSet).getDataLabelMap(); - if (!labelMap.isEmpty()) { - ioSerialiser.put(DATA_LABELS, labelMap, Integer.class, String.class); - } - final StringHashMapList styleMap = ((AbstractDataSet) dataSet).getDataStyleMap(); - if (!styleMap.isEmpty()) { - ioSerialiser.put(DATA_STYLES, styleMap, Integer.class, String.class); + protected void parseNumericData(final IoSerialiser ioSerialiser, final DataSetBuilder builder, final DataSet origDataSet, final FieldDescription rootField) { + // check for numeric data + for (FieldDescription fieldDescription : rootField.getChildren()) { + final String fieldName = fieldDescription.getFieldName(); + if (fieldName == null || (fieldDescription.getDataType() != DataType.DOUBLE_ARRAY && fieldDescription.getDataType() != DataType.FLOAT_ARRAY)) { + continue; + } + if (fieldName.startsWith(ARRAY_PREFIX)) { + readValues(ioSerialiser, builder, origDataSet, fieldDescription, fieldName); + } else if (fieldName.startsWith(EP_PREFIX)) { + readPosError(ioSerialiser, builder, origDataSet, fieldDescription, fieldName); + } else if (fieldName.startsWith(EN_PREFIX)) { + readNegError(ioSerialiser, builder, origDataSet, fieldDescription, fieldName); + } + } } - return; - } - final int dataCount = dataSet.getDataCount(); - final Map labelMap = new HashMap<>(); // NOPMD - protected by lock and faster - for (int index = 0; index < dataCount; index++) { - final String label = dataSet.getDataLabel(index); - if ((label != null) && !label.isEmpty()) { - labelMap.put(index, label); + @SuppressWarnings("PMD.NPathComplexity") + protected void writeDataLabelsToStream(final DataSet dataSet) { + if (dataSet instanceof AbstractDataSet) { + final StringHashMapList labelMap = ((AbstractDataSet) dataSet).getDataLabelMap(); + if (!labelMap.isEmpty()) { + ioSerialiser.put(DATA_LABELS, labelMap, Integer.class, String.class); + } + final StringHashMapList styleMap = ((AbstractDataSet) dataSet).getDataStyleMap(); + if (!styleMap.isEmpty()) { + ioSerialiser.put(DATA_STYLES, styleMap, Integer.class, String.class); + } + return; + } + + final int dataCount = dataSet.getDataCount(); + final Map labelMap = new HashMap<>(); // NOPMD - protected by lock and faster + for (int index = 0; index < dataCount; index++) { + final String label = dataSet.getDataLabel(index); + if ((label != null) && !label.isEmpty()) { + labelMap.put(index, label); + } + } + if (!labelMap.isEmpty()) { + ioSerialiser.put(DATA_LABELS, labelMap, Integer.class, String.class); + } + + final Map styleMap = new HashMap<>(); // NOPMD - protected by lock and faster + for (int index = 0; index < dataCount; index++) { + final String style = dataSet.getStyle(index); + if ((style != null) && !style.isEmpty()) { + styleMap.put(index, style); + } + } + if (!styleMap.isEmpty()) { + ioSerialiser.put(DATA_STYLES, styleMap, Integer.class, String.class); + } } - } - if (!labelMap.isEmpty()) { - ioSerialiser.put(DATA_LABELS, labelMap, Integer.class, String.class); - } - final Map styleMap = new HashMap<>(); // NOPMD - protected by lock and faster - for (int index = 0; index < dataCount; index++) { - final String style = dataSet.getStyle(index); - if ((style != null) && !style.isEmpty()) { - styleMap.put(index, style); + protected void writeHeaderDataToStream(final DataSet dataSet) { + // common header data + ioSerialiser.put(DATA_SET_NAME, dataSet.getName()); + ioSerialiser.put(DIMENSIONS, dataSet.getDimension()); + final List axisDescriptions = dataSet.getAxisDescriptions(); + StringBuilder builder = new StringBuilder(60); + for (int i = 0; i < axisDescriptions.size(); i++) { + builder.setLength(0); + final String prefix = builder.append(AXIS).append(i).append('.').toString(); + builder.setLength(0); + final String name = builder.append(prefix).append(NAME).toString(); + builder.setLength(0); + final String unit = builder.append(prefix).append(UNIT).toString(); + builder.setLength(0); + final String minName = builder.append(prefix).append(MIN).toString(); + builder.setLength(0); + final String maxName = builder.append(prefix).append(MAX).toString(); + + ioSerialiser.put(name, dataSet.getAxisDescription(i).getName()); + ioSerialiser.put(unit, dataSet.getAxisDescription(i).getUnit()); + ioSerialiser.put(minName, dataSet.getAxisDescription(i).getMin()); + ioSerialiser.put(maxName, dataSet.getAxisDescription(i).getMax()); + } } - ioSerialiser.put(INFO_LIST, metaDataSet.getInfoList().toArray(new String[0])); - ioSerialiser.put(WARNING_LIST, metaDataSet.getWarningList().toArray(new String[0])); - ioSerialiser.put(ERROR_LIST, metaDataSet.getErrorList().toArray(new String[0])); - ioSerialiser.put(META_INFO, metaDataSet.getMetaInfo(), String.class, String.class); - } + protected void writeMetaDataToStream(final DataSet dataSet) { + if (!(dataSet instanceof DataSetMetaData metaDataSet)) { + return; + } ioSerialiser.put(INFO_LIST, metaDataSet.getInfoList().toArray(new String[0])); ioSerialiser.put(WARNING_LIST, metaDataSet.getWarningList().toArray(new String[0])); @@ -366,12 +395,6 @@ protected void writeNumericBinaryDataToBufferDouble(final DataSet dataSet) { } } } - return; // GridDataSet does not provide errors - } - for (int dimIndex = 0; dimIndex < nDim; dimIndex++) { - final int nsamples = dataSet.getDataCount(); - ioSerialiser.put(ARRAY_PREFIX + dimIndex, MathUtils.toFloats(dataSet.getValues(dimIndex)), nsamples); - } /** * @param dataSet to be exported @@ -412,68 +435,68 @@ protected void writeNumericBinaryDataToBufferFloat(final DataSet dataSet) { } } - private void parseHeader(final IoSerialiser ioSerialiser, final DataSetBuilder builder, FieldDescription fieldDescription) { - final String fieldName = fieldDescription.getFieldName(); - if (fieldName == null || !fieldName.startsWith(AXIS)) { - return; // not axis related field - } - final String[] parsed = fieldName.split("\\."); - if (parsed.length <= 1) { - return; // couldn't parse axis field - } - final int dimension = getDimIndex(parsed[0], AXIS); - if (dimension < 0) { - return; // couldn't parse dimIndex - } - ioSerialiser.getBuffer().position(fieldDescription.getDataStartPosition()); - switch (parsed[1]) { - case MIN: - builder.setAxisMin(dimension, ioSerialiser.getBuffer().getDouble()); - break; - case MAX: - builder.setAxisMax(dimension, ioSerialiser.getBuffer().getDouble()); - break; - case NAME: - builder.setAxisName(dimension, ioSerialiser.getBuffer().getString()); - break; - case UNIT: - builder.setAxisUnit(dimension, ioSerialiser.getBuffer().getString()); - break; - default: - LOGGER.atWarn().addArgument(parsed[1]).log("parseHeader(): encountered unknown tag {} - ignore"); - break; - } - } + private void parseHeader(final IoSerialiser ioSerialiser, final DataSetBuilder builder, FieldDescription fieldDescription) { + final String fieldName = fieldDescription.getFieldName(); + if (fieldName == null || !fieldName.startsWith(AXIS)) { + return; // not axis related field + } + final String[] parsed = fieldName.split("\\."); + if (parsed.length <= 1) { + return; // couldn't parse axis field + } + final int dimension = getDimIndex(parsed[0], AXIS); + if (dimension < 0) { + return; // couldn't parse dimIndex + } + ioSerialiser.getBuffer().position(fieldDescription.getDataStartPosition()); + switch (parsed[1]) { + case MIN: + builder.setAxisMin(dimension, ioSerialiser.getBuffer().getDouble()); + break; + case MAX: + builder.setAxisMax(dimension, ioSerialiser.getBuffer().getDouble()); + break; + case NAME: + builder.setAxisName(dimension, ioSerialiser.getBuffer().getString()); + break; + case UNIT: + builder.setAxisUnit(dimension, ioSerialiser.getBuffer().getString()); + break; + default: + LOGGER.atWarn().addArgument(parsed[1]).log("parseHeader(): encountered unknown tag {} - ignore"); + break; + } + } - private void readNegError(final IoSerialiser ioSerialiser, final DataSetBuilder builder, final DataSet origDataSet, FieldDescription fieldDescription, final String fieldName) { - int dimIndex = getDimIndex(fieldName, EN_PREFIX); - if (dimIndex >= 0) { - ioSerialiser.getBuffer().position(fieldDescription.getDataStartPosition()); - final double[] origErrorArray = (origDataSet instanceof DataSetError) ? ((DataSetError) origDataSet).getErrorsNegative(dimIndex) : null; - builder.setNegErrorNoCopy(dimIndex, getDoubleArray(ioSerialiser, origErrorArray, fieldDescription.getDataType())); - } - } + private void readNegError(final IoSerialiser ioSerialiser, final DataSetBuilder builder, final DataSet origDataSet, FieldDescription fieldDescription, final String fieldName) { + int dimIndex = getDimIndex(fieldName, EN_PREFIX); + if (dimIndex >= 0) { + ioSerialiser.getBuffer().position(fieldDescription.getDataStartPosition()); + final double[] origErrorArray = (origDataSet instanceof DataSetError) ? ((DataSetError) origDataSet).getErrorsNegative(dimIndex) : null; + builder.setNegErrorNoCopy(dimIndex, getDoubleArray(ioSerialiser, origErrorArray, fieldDescription.getDataType())); + } + } - private void readPosError(final IoSerialiser ioSerialiser, final DataSetBuilder builder, final DataSet origDataSet, FieldDescription fieldDescription, - final String fieldName) { - int dimIndex = getDimIndex(fieldName, EP_PREFIX); - if (dimIndex >= 0) { - ioSerialiser.getBuffer().position(fieldDescription.getDataStartPosition()); - final double[] origErrorArray = (origDataSet instanceof DataSetError) ? ((DataSetError) origDataSet).getErrorsPositive(dimIndex) : null; - builder.setPosErrorNoCopy(dimIndex, getDoubleArray(ioSerialiser, origErrorArray, fieldDescription.getDataType())); - } - } + private void readPosError(final IoSerialiser ioSerialiser, final DataSetBuilder builder, final DataSet origDataSet, FieldDescription fieldDescription, + final String fieldName) { + int dimIndex = getDimIndex(fieldName, EP_PREFIX); + if (dimIndex >= 0) { + ioSerialiser.getBuffer().position(fieldDescription.getDataStartPosition()); + final double[] origErrorArray = (origDataSet instanceof DataSetError) ? ((DataSetError) origDataSet).getErrorsPositive(dimIndex) : null; + builder.setPosErrorNoCopy(dimIndex, getDoubleArray(ioSerialiser, origErrorArray, fieldDescription.getDataType())); + } + } - private void readValues(final IoSerialiser ioSerialiser, final DataSetBuilder builder, final DataSet origDataSet, FieldDescription fieldDescription, - final String fieldName) { - int dimIndex = getDimIndex(fieldName, ARRAY_PREFIX); - if (dimIndex >= 0) { - ioSerialiser.getBuffer().position(fieldDescription.getDataStartPosition()); - builder.setValuesNoCopy(dimIndex, getDoubleArray(ioSerialiser, origDataSet == null ? null : origDataSet.getValues(dimIndex), fieldDescription.getDataType())); - } - } + private void readValues(final IoSerialiser ioSerialiser, final DataSetBuilder builder, final DataSet origDataSet, FieldDescription fieldDescription, + final String fieldName) { + int dimIndex = getDimIndex(fieldName, ARRAY_PREFIX); + if (dimIndex >= 0) { + ioSerialiser.getBuffer().position(fieldDescription.getDataStartPosition()); + builder.setValuesNoCopy(dimIndex, getDoubleArray(ioSerialiser, origDataSet == null ? null : origDataSet.getValues(dimIndex), fieldDescription.getDataType())); + } + } - public static DataSetSerialiser withIoSerialiser(final IoSerialiser ioSerialiser) { - return new DataSetSerialiser(ioSerialiser); + public static DataSetSerialiser withIoSerialiser(final IoSerialiser ioSerialiser) { + return new DataSetSerialiser(ioSerialiser); + } } -} From 632ef46eaf62600110b6f81c0be958dfcec67427 Mon Sep 17 00:00:00 2001 From: Alexander Krimm Date: Tue, 2 Dec 2025 15:57:48 +0100 Subject: [PATCH 7/7] DnsDataSourceTests: increase Timeout for CI Signed-off-by: Alexander Krimm --- .../src/test/java/io/opencmw/client/DnsDataSourceTests.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/test/java/io/opencmw/client/DnsDataSourceTests.java b/client/src/test/java/io/opencmw/client/DnsDataSourceTests.java index e8e88c25..5d189063 100644 --- a/client/src/test/java/io/opencmw/client/DnsDataSourceTests.java +++ b/client/src/test/java/io/opencmw/client/DnsDataSourceTests.java @@ -45,7 +45,7 @@ @Timeout(60) class DnsDataSourceTests { private final static int TIMEOUT_STARTUP = 5; // [s] - private final static int TIMEOUT = 1000; // [ms] + private final static int TIMEOUT = 2000; // [ms] private static MajordomoBroker dnsBroker; private static MajordomoBroker brokerB; private static MajordomoBroker brokerC; @@ -165,8 +165,8 @@ void testWithWorkerStartStopping() throws IOException { await().alias("subscribe and receive from an existing 'deviceD/property' - first stage").atMost(Duration.ofSeconds(TIMEOUT_STARTUP)).until(() -> notificationCounterD.get() >= 10); assertNotEquals(0, notificationCounterD.get()); brokerD.stopBroker(); - //LockSupport.parkNanos(Duration.ofMillis(TIMEOUT).toNanos()); // wait until the old brokerD and connected services have shut down - // reset counter + // LockSupport.parkNanos(Duration.ofMillis(TIMEOUT).toNanos()); // wait until the old brokerD and connected services have shut down + // reset counter dnsBroker.getDnsCache().clear(); notificationCounterD.set(0); assertEquals(0, notificationCounterD.get(), "NotificationListener not acquiring any more new events");