@@ -244,17 +244,10 @@ public ObjectId(final String hexString) {
244
244
* @throws IllegalArgumentException if array is null or not of length 12
245
245
*/
246
246
public ObjectId (final byte [] bytes ) {
247
- if (bytes == null ) {
248
- throw new IllegalArgumentException ();
249
- }
250
- if (bytes .length != 12 ) {
251
- throw new IllegalArgumentException ("need 12 bytes" );
252
- }
253
-
254
- timestamp = makeInt (bytes [0 ], bytes [1 ], bytes [2 ], bytes [3 ]);
255
- machineIdentifier = makeInt ((byte ) 0 , bytes [4 ], bytes [5 ], bytes [6 ]);
256
- processIdentifier = (short ) makeInt ((byte ) 0 , (byte ) 0 , bytes [7 ], bytes [8 ]);
257
- counter = makeInt ((byte ) 0 , bytes [9 ], bytes [10 ], bytes [11 ]);
247
+ // This null check allows the delegate constructor to throw the expected IllegalArgumentException.
248
+ // (ByteBuffer.wrap throws NullPointerException if bytes is null, which violates ObjectId's contract
249
+ // to callers.)
250
+ this (bytes != null ? ByteBuffer .wrap (bytes ) : null );
258
251
}
259
252
260
253
/**
@@ -268,6 +261,28 @@ public ObjectId(final byte[] bytes) {
268
261
this (legacyToBytes (timestamp , machineAndProcessIdentifier , counter ));
269
262
}
270
263
264
+ /**
265
+ * Constructs a new instance from the given ByteBuffer
266
+ *
267
+ * @param buffer the ByteBuffer
268
+ * @throws IllegalArgumentException if the buffer is null or does not have at least 12 bytes remaining
269
+ */
270
+ public ObjectId (final ByteBuffer buffer ) {
271
+ if (buffer == null ) {
272
+ throw new IllegalArgumentException ();
273
+ }
274
+ if (buffer .remaining () < 12 ) {
275
+ throw new IllegalArgumentException ("need 12 bytes" );
276
+ }
277
+
278
+ // Note: Cannot use ByteBuffer.getInt because it depends on tbe buffer's byte order
279
+ // and ObjectId's are always in big-endian order.
280
+ timestamp = makeInt (buffer .get (), buffer .get (), buffer .get (), buffer .get ());
281
+ machineIdentifier = makeInt ((byte ) 0 , buffer .get (), buffer .get (), buffer .get ());
282
+ processIdentifier = (short ) makeInt ((byte ) 0 , (byte ) 0 , buffer .get (), buffer .get ());
283
+ counter = makeInt ((byte ) 0 , buffer .get (), buffer .get (), buffer .get ());
284
+ }
285
+
271
286
private static byte [] legacyToBytes (final int timestamp , final int machineAndProcessIdentifier , final int counter ) {
272
287
byte [] bytes = new byte [12 ];
273
288
bytes [0 ] = int3 (timestamp );
@@ -291,22 +306,40 @@ private static byte[] legacyToBytes(final int timestamp, final int machineAndPro
291
306
* @return the byte array
292
307
*/
293
308
public byte [] toByteArray () {
294
- byte [] bytes = new byte [12 ];
295
- bytes [0 ] = int3 (timestamp );
296
- bytes [1 ] = int2 (timestamp );
297
- bytes [2 ] = int1 (timestamp );
298
- bytes [3 ] = int0 (timestamp );
299
- bytes [4 ] = int2 (machineIdentifier );
300
- bytes [5 ] = int1 (machineIdentifier );
301
- bytes [6 ] = int0 (machineIdentifier );
302
- bytes [7 ] = short1 (processIdentifier );
303
- bytes [8 ] = short0 (processIdentifier );
304
- bytes [9 ] = int2 (counter );
305
- bytes [10 ] = int1 (counter );
306
- bytes [11 ] = int0 (counter );
307
- return bytes ;
309
+ ByteBuffer buffer = ByteBuffer .allocate (12 );
310
+ putToByteBuffer (buffer );
311
+ return buffer .array (); // using .allocate ensures there is a backing array that can be returned
308
312
}
309
313
314
+ /**
315
+ * Convert to bytes and put those bytes to the provided ByteBuffer.
316
+ * Note that the numbers are stored in big-endian order.
317
+ *
318
+ * @param buffer the ByteBuffer
319
+ * @throws IllegalArgumentException if the buffer is null or does not have at least 12 bytes remaining
320
+ */
321
+ public void putToByteBuffer (final ByteBuffer buffer ) {
322
+ if (buffer == null ) {
323
+ throw new IllegalArgumentException ();
324
+ }
325
+ if (buffer .remaining () < 12 ) {
326
+ throw new IllegalArgumentException ("need 12 bytes" );
327
+ }
328
+
329
+ buffer .put (int3 (timestamp ));
330
+ buffer .put (int2 (timestamp ));
331
+ buffer .put (int1 (timestamp ));
332
+ buffer .put (int0 (timestamp ));
333
+ buffer .put (int2 (machineIdentifier ));
334
+ buffer .put (int1 (machineIdentifier ));
335
+ buffer .put (int0 (machineIdentifier ));
336
+ buffer .put (short1 (processIdentifier ));
337
+ buffer .put (short0 (processIdentifier ));
338
+ buffer .put (int2 (counter ));
339
+ buffer .put (int1 (counter ));
340
+ buffer .put (int0 (counter ));
341
+ }
342
+
310
343
/**
311
344
* Gets the timestamp (number of seconds since the Unix epoch).
312
345
*
0 commit comments