I am working on migrating a Java backend to Node.js, but I only have access to the database, not the original Java source code. One of the columns in the database appears to store serialized java.util.HashSet objects.
I am trying to generate the correct serialized format in Node.js so that new entries match the old ones, but the ones I generate look different from the existing records. Here’s an example of what I get vs. what the database contains:
Old entries (correct format): Properly serialized java.util.HashSet objects.
New entry (my output, incorrect): The structure appears different at the top.
export function serializeSpringBootHashSet(items: number[]): Buffer {
// Magic header for Java serialization
const magicHeader = Buffer.from([
0xac, 0xed, // STREAM_MAGIC
0x00, 0x05 // STREAM_VERSION
]);
// Java HashSet class descriptor with potential "°DÄ" appearance
const hashSetClassDesc = Buffer.from([
0x73, 0x72, // 'sr' (serialized object)
0x00, 0x13, // Class name length (19 bytes: "java.util.HashSet°D")
0x6a, 0x61, 0x76, 0x61, 0x2e, 0x75, 0x74, 0x69, 0x6c, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x53, 0x65, 0x74,
0xc2, 0xb0, // UTF-8 for '°'
0x44, // 'D'
0x12, 0xc4, 0x1a, 0x03, 0x00, 0x00, // Class metadata
0x78, 0x70 // End of object marker
]);
// Prepare items serialization (same as original)
const serializeItems = items.flatMap(item => {
return [
0x73, 0x72, // sr
0x00, 0x0e, // class name length
0x6a, 0x61, 0x76, 0x61, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x4c, 0x6f, 0x6e, 0x67,
0x3b, 0x8b, 0xe4, 0x90, 0xcc, 0x8f, 0x23, 0xdf, 0x02, 0x00, 0x01, 0x4a, 0x00, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x78, 0x72, 0x00, 0x10,
0x6a, 0x61, 0x76, 0x61, 0x2e, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72,
0x86, 0xac, 0x95, 0x1d, 0x0b, 0x94, 0xe0, 0x8b, 0x02, 0x00, 0x00, 0x78, 0x70,
...[
(item >> 56) & 0xFF,
(item >> 48) & 0xFF,
(item >> 40) & 0xFF,
(item >> 32) & 0xFF,
(item >> 24) & 0xFF,
(item >> 16) & 0xFF,
(item >> 8) & 0xFF,
item & 0xFF
]
];
});
// Construct the full serialized buffer
const contentBuffer = Buffer.from([
...magicHeader,
...hashSetClassDesc,
0x77, 0x0c, 0x00, 0x00, 0x00, 0x02, 0x3f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
...serializeItems,
0x78, 0x70
]);
return contentBuffer;
}
What’s wrong?
The first part of my serialized data does not match the existing ones in the database.
I suspect there is an issue with how I construct the class descriptor (java.util.HashSet).
There may also be an issue with the way I serialize numbers.

