将BSON类型的ObjectId转换为JSON(存储在Mongodb中)-Java

6

使用 new ObjectId() 方法输出的结果如下:

"_id" : { "_time" : 1374347520 , "_machine" : -1025067326 , "_inc" : 585905201 , "_new" : false}

但实际上我想要的格式是:

"_id":{"$oid":51eae100c2e6b6c222ec3431}

这是 MongoDB ID 的常规格式。在 Java 中有什么更好的方法来实现这个格式呢?

更新:

我的 value object 如下:

import com.google.gson.annotations.SerializedName;
import org.bson.types.ObjectId;

public class TaskObject {

    @SerializedName("_id")
    private ObjectId _id;

    @SerializedName("revNo")
    private int revNo;
}

我正试图将此内容以自定义 _id 存储到 MongoDB

TaskObject taskObject = new TaskObject();
taskObject.set_id(new ObjectId());
TaskMongoDBClient.getInstance().
        persistNewTaskData(new Gson().toJson(taskObject));

在mongodb中存储的内容如下所示。
_id: { "_time" : 1397464341 , "_machine" : 1441187434 , "_inc" : -1687457948 , "_new" : true}
而不是_id:{"$oid":xxxx},我可以通过使用oid值查询。
我在这里做错了什么?请帮忙。
谢谢

我添加了更多细节。 - Chinthaka Dharmasiri
你的意思是想在Json中添加新属性$oid吗? - Asif Bhutto
很抱歉,目前我无法找到更好的方法来进一步解释我的问题。如果你们中有人曾经处于这种情境,请告诉我你们的方法或者更兼容BSON数据类型的库是什么。 - Chinthaka Dharmasiri
http://api.mongodb.org/java/current/org/bson/types/ObjectId.html - Chinthaka Dharmasiri
1个回答

14

有至少两种可能的方法来实现这个。可能最正确的方法是使用GSON TypeAdapter 来配置如何将ObjectId写入(和读取)JSON。你需要创建一个实现TypeAdapter的东西,并将其注册到GsonBuilder中,这样GSON就知道有一种特殊的方法来处理ObjectIds。

我编写了一个小测试来证明这个方法可以工作,使用您的用例和示例对象(但出于简洁起见省略了revNo字段):

@Test
public void shouldWriteCorrectJSON() {
    // given
    TaskObject taskObject = new TaskObject();
    taskObject._id = new ObjectId("51eae100c2e6b6c222ec3431");

    Gson gson = new GsonBuilder().registerTypeAdapter(ObjectId.class, new ObjectIdTypeAdapter()).create();

    // when
    String gsonString = gson.toJson(taskObject);

    // then
    assertThat(gsonString, is("{\"_id\":{\"$oid\":\"51eae100c2e6b6c222ec3431\"}}"));
}

private class ObjectIdTypeAdapter extends TypeAdapter<ObjectId> {
    @Override
    public void write(final JsonWriter out, final ObjectId value) throws IOException {
        out.beginObject()
           .name("$oid")
           .value(value.toString())
           .endObject();
    }

    @Override
    public ObjectId read(final JsonReader in) throws IOException {
        in.beginObject();
        assert "$oid".equals(in.nextName());
        String objectId = in.nextString();
        in.endObject();
        return new ObjectId(objectId);
    }
}

请注意,该测试断言JSON的格式应该是您期望的样子,并且我必须创建一个ObjectIdTypeAdapter,它知道ObjectId字段的名称为"$oid",值仅为ObjectID的字符串值,并且不会单独序列化所有字段。

还要注意,如果您更改对象写入JSON的方式,您也需要更改读取的方式。因此,我还实现了read来检查字段名称是否正确(如果不正确,您应该在这里抛出异常而不是使用简单的assert),然后读取该值并从该字符串值创建ObjectId。

在实际情况中,您可能还需要检查这两种情况下的null值。

���为我是一个负责任的编码人员,所以我还编写了一个测试来展示读取情况也可以正常工作:

@Test
public void shouldReadFromJSON() {
    // given
    Gson gson = new GsonBuilder().registerTypeAdapter(ObjectId.class, new ObjectIdTypeAdapter()).create();

    // when
    TaskObject actualTaskObject = gson.fromJson("{\"_id\":{\"$oid\":\"51eae100c2e6b6c222ec3431\"}}", TaskObject.class);

    // then
    TaskObject taskObject = new TaskObject();
    taskObject._id = new ObjectId("51eae100c2e6b6c222ec3431");
    assertThat(actualTaskObject._id, is(taskObject._id));
}

更多阅读:


TypeAdapter似乎提供格式验证,这是我的原始问题的正确答案。让我试一试并将其标记为被接受的答案。 无论如何,我所做的是,我没有使用Mongo中默认的_id字段中的$oid子值,而是采用了以下解决方法。 TaskObject _id已更改为String类型。 我的赋值看起来像这样。 _id = ObjectId.get().toString(); 这以 "_id: 535e3b090557f05f783c2805" 格式保存。 - Chinthaka Dharmasiri
是的,使用字符串来表示ID也是相当常见的 - 可以说这是一个更好的答案,因为它可以防止Mongo特定的ObjectID类泄露到您的领域对象中。 - Trisha
@Trisha 很好,你写了两个测试,但是我在第二个(读取)测试中遇到了麻烦。我稍微修改了一下(我需要读取Long而不是objectids),但本质上它是相同的。你能否看出这里有什么问题?http://stackoverflow.com/questions/36134737/read-bson-mongodb-into-pojo-using-gson-and-typeadapter - p.streef

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接