Skip to content

fix: serialize null as kdb+ generic null (::) instead of throwing NPE - #106

Merged
sshanks-kx merged 2 commits into
KxSystems:masterfrom
belowzeroff:fix/null-generic-null-serialization
Jul 30, 2026
Merged

fix: serialize null as kdb+ generic null (::) instead of throwing NPE#106
sshanks-kx merged 2 commits into
KxSystems:masterfrom
belowzeroff:fix/null-generic-null-serialization

Conversation

@belowzeroff

Copy link
Copy Markdown
Contributor

Summary

A general list received from kdb+ can contain the generic null ::, which this client deserializes to a Java null (e.g. (1;::;3)Object[]{1L, null, 3L}). Serializing such a list back — or any Object that is null — threw a bare NullPointerException (from n()Array.getLength(null)), so kdb+ data containing :: could not be round-tripped.

Reproduction

c c = new c();
// v = deserialized (1;::) => Object[]{1L, null}
Object[] v = { Long.valueOf(1), null };
c.serialize(1, v, false); // -> java.lang.NullPointerException

Change

Serialize a null Object as the kdb+ generic null :: (type 101 followed by a 0 byte) — the exact inverse of how it is deserialized — and account for it as 2 bytes in nx(). A null inside a typed array (e.g. String[]) is unaffected and still serializes as that type's null.

Testing

Added testSerializeDeserializeGenericNull, round-tripping a bare null and a general list containing a null element. Full suite green (85 tests, no regressions).

A general list received from kdb+ can contain the generic null :: which
deserializes to a Java null (e.g. `(1;::;3)` -> Object[]{1L, null, 3L}).
Serializing such a list back — or any Object containing null — threw a bare
NullPointerException from n()/Array.getLength(null), so kdb+ data containing
:: could not be round-tripped.

Serialize a null Object as the kdb+ generic null :: (type 101 followed by a 0
byte), the exact inverse of how it is deserialized, and account for it as 2
bytes in nx(). Add a round-trip unit test for a bare null and for a general
list containing a null element.
w((byte)0);
return;
}
int type=t(x);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

method 't' is for the type number of the object, so checking null and returning type number 101 should prob be in there. will also allow the subsequent line to w the type number, rather than having it twice. the the type 101 can be checked as per other types.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, thanks. Moved the null check into t() (returns type number 101 for the generic null ::), so w/nx now handle it through the normal type dispatch and the type byte is written once. The serialized bytes are unchanged. Pushed in 6d81e0b.

Address review feedback on PR KxSystems#106: instead of special-casing null in w()
and nx(), t(null) now returns the generic-null type number 101, so :: is
written through the normal type dispatch and the type byte is emitted once.
No change to the serialized bytes; adds a t(null)==101 assertion.
@belowzeroff
belowzeroff requested a review from sshanks-kx July 30, 2026 09:32
@sshanks-kx
sshanks-kx merged commit 7db9e2f into KxSystems:master Jul 30, 2026
1 check passed
@belowzeroff
belowzeroff deleted the fix/null-generic-null-serialization branch July 31, 2026 06:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants