@@ -244,17 +244,10 @@ public ObjectId(final String hexString) {
244244 * @throws IllegalArgumentException if array is null or not of length 12
245245 */
246246 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 );
258251 }
259252
260253 /**
@@ -268,6 +261,28 @@ public ObjectId(final byte[] bytes) {
268261 this (legacyToBytes (timestamp , machineAndProcessIdentifier , counter ));
269262 }
270263
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+
271286 private static byte [] legacyToBytes (final int timestamp , final int machineAndProcessIdentifier , final int counter ) {
272287 byte [] bytes = new byte [12 ];
273288 bytes [0 ] = int3 (timestamp );
@@ -291,22 +306,40 @@ private static byte[] legacyToBytes(final int timestamp, final int machineAndPro
291306 * @return the byte array
292307 */
293308 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
308312 }
309313
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+
310343 /**
311344 * Gets the timestamp (number of seconds since the Unix epoch).
312345 *
0 commit comments