preface

In MongoDB, ObjectId is a 12-byte BSON data (we can see the 24-bit hexadecimal form in the visual database tool). The data structure is as follows:

  • before4Bytes for the timestamp (timestamp);
  • And then the3One-byte machine identifier (randomValue1);
  • Then the2One byte is the processid (randomValue2);
  • The last of the3One byte is the random counter value (counter).

This article uses the Java serialization toolkit based on Gson. The complete code used in this article has been uploaded to GitHub. Here is how to solve the serialization problem.

basis

Since the next solution requires customizing the serialized classes of ObjectId, you need to start with the underlying concrete storage format:

Gson gson = new Gson();
TestEntity id = new TestEntity(new ObjectId("600a47a0076abd67f0d588f6"));
System.out.println(gson.fromJson(gson.toJson(id), Document.class));

// TestEntity has the following class structure
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TestEntity {

    private ObjectId _id;
}

/** * output: * Document{{_id= * {* timestamp=1.611286432E9, * counter=1.399423E7, * randomValue1=486077.0, * randomValue2=26608.0 *} *}} */
Copy the code

As you can see from the above code and output, if you convert the entity to Document when serializing it for insertion, you will get the wrong result. This section introduces the hexadecimal string 600A47A0 076ABd 67f0 d588f6 and {timestamp=1.611286432E9, counter=1.399423E7, RandomValue1 =486077.0, randomValue2=26608.0}

Seeing that the 24-bit hexadecimal string is exactly equal to the value of the corresponding field in the object, the serialization solution begins in earnest.

Serialization problem resolution

This annotation requires passing in a custom serialization resolution class that inherits TypeAdapter

class. Here is the code:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class TestEntity {

    // Define a class named MongoObjectId for the customized serialization of ObjectId
    @JsonAdapter(MongoObjectId.class)
    private ObjectId _id;
}
Copy the code

Here is the code for the custom serialization parsing class:

public class MongoObjectId extends TypeAdapter<ObjectId> {

    @Override
    public void write(JsonWriter out, ObjectId value) throws IOException {
        // For values that need to be serialized
        // Write a null value in out if it is null
        Otherwise, write the hexadecimal string form of the ObjectId
        // Tips: The toString method of the ObjectId class has been overwritten to return the hexadecimal string form of the ObjectId class
        if (value == null) {
            out.nullValue();
            return;
        }
        out.value(value.toString());
    }

    @Override
    public ObjectId read(JsonReader in) throws IOException {
        // in.beginObject() indicates that an object is read
        Timestamp =1.611286432E9, counter=1.399423E7, randomValue1=486077.0, randomValue2=26608.0}
        in.beginObject();
        int i = 0;
        // Store the next four readings in an array
        long[] nums = new long[4];
        while (in.hasNext()) {
            // Read the object name first
            in.nextName();
            // Then store the values in the array
            nums[i++] = in.nextLong();
        }
        // in.endobject () indicates that the object has been read
        in.endObject();
        if (i == 0) {
            return null;
        }
        // Convert the obtained data to a hexadecimal string for obtaining the ObjectId object
        return new ObjectId(String.format("%08x%06x%04x%06x", nums[0], nums[2], nums[3], nums[1])); }}Copy the code

Then use the above test code:

Gson gson = new Gson();
TestEntity id = new TestEntity(new ObjectId("600a47a0076abd67f0d588f6"));
System.out.println(gson.fromJson(gson.toJson(id), Document.class));

The following output is displayed: * Document{{_id=600a47a0076abd67f0d588f6}} */
Copy the code

You can see that the serialization of the ObjectId is resolved by adding the @jsonAdapter (Mongoobjectid.class) annotation to the ObjectId variable.

conclusion

This article provided you with a brief look at the low-level storage format for MongoDB’s ObjectId data type and how to solve serialization problems with an annotation in Gson.