How to deserialize json document obtained from mongoDB into a POJO?… (Migrating from Morphia to Java Mongo Driver 3.0)

笑着哭i 提交于 2019-12-12 13:29:06

问题


BACKGROUND

Initially, Morphia was being used to interact with a mongo database. This was fine and worked nicely, but there was one caveat... Some mapping exception was being spilled and clogging the logs. See my Unresolved Question on that particular issue. <=== This didn't stop the application from functioning correctly. Morphia helped in getting the documents mapped to their corresponding entities (basically POJOs) and these were easily rendered to the Views.

However, after much deliberation and because that exception issue wasnt resolved, and thanks to the MongoDB Java Driver 3.0's new features, I have decided to move off from Morphia to MongoDB-Java-Driver3.0(MJD3.0)


On inspecting Documents (previously stored by morphia) I can see:
"_id" : ObjectId("55706df5e4b00146ea69622b"),
"className" : "packageName.NewsCategory",
"categoryName" : "Maritime",
"uid" : NumberLong(11),
"createdAt" : ISODate("2015-06-04T15:25:41.096Z"),
"updatedAt" : ISODate("2015-06-04T15:25:41.096Z"),
"active" : true

Also, the model, NewsCategory, looks something like this;

public class NewsCategory{
    private ObjectId id;
    private String categoryName;
    private Long uid;
    private Date createdAt;
    private Date updatedAt;
    private boolean active;

    //getters...
    //setters...
}


MY STRATEGY

Because I was formerly using Morphia, the Models (as POJOs) were being passed as attributes to the Views ( .vm - velocity templates ) where values are being read from the fields as: $!newsCategory.id, $!newsCategory.categoryName, $!newsCategory.createdAt e.g

<a href="/news/categories/$!newsCategory.id"> Edit </a>

Now, because I do not want to modify the Servelet and/or View Layer, I ensure that in the business Layer, the json string gets deserialized into the corresponding Model using gson;

NewsCategory newsCategory = new GsonBuilder().create().fromJson(json, NewsCategory.class);


CHALLENGE - 1

With document Type being org.bson.Document and using MongoDB-Java-Driver3.0 (MJD3.0), The NewsCategory document is correctly retrieved from MongoDB, no problem, and when I call

String json = document.toJson(); ...here's what the json structure looks like;

{
    "_id": {
        "$oid": "54ad4568e451500a45f60200"
    },
    "className": "packageName.NewsCategory",
    "categoryName": "General",
    "uid": {
        "$numberLong": "1"
    },
    "createdAt": {
        "$date": 1420641640457
    },
    "updatedAt": {
        "$date": 1429285029337
    },
    "active": true
}


THE PROBLEM

This json structure derived from document.toJson() cannot be easily deserialized to the corresponding NewsCategory model using my earlier described strategy, thanks to those field types present in the format.


CHALLENGE - 2

I directly converted the document to json using gson as follows;

String json = new GsonBuilder().create().toJson(document); ...and here's what the json structure looks like;

{
    "_id": {
        "timestamp": 1420641640,
        "machineIdentifier": 14963024,
        "processIdentifier": 2629,
        "counter": 16122368
    },
    "className": "packageName.NewsCategory",
    "categoryName": "General",
    "uid": 1,
    "createdAt": "Jan 7, 2015 3:40:40 PM",
    "updatedAt": "Apr 17, 2015 4:37:09 PM",
    "active": true
}

This is way more desirable, and I can get the NewsCategory object using my usual strategy as;

NewsCategory newsCategory = new GsonBuilder().create().fromJson(json, NewsCategory.class);


ANOTHER PROBLEM THOUGH

The _id field has been broken into it's ObjectId components, hence the id cannot be retrieved as newsCategory.id or even newsCategory._id.

However while I was formerly using morphia, it could simply be retrieved by just using newsCategory.id


MAIN QUESTIONS

What is the appropriate way to deserialize these json strings into the corresponding NewsCategory Model while still ensuring that all the necessary fields are still normally accessible in the Views using the regular dot(.) annotations (especially that id field)?

An approach for both CHALLENGES 1 & 2 described above would be highly appreciated.

Thanks!

EDIT:

I've tried @cichystefan's approach and the challenge still remains how to access the value of the _id field

With newsCategory now being of type org.bson.Document, for quite obvious reasons, $!newsCategory.id is apparently either empty or null, because when I inspect an html section in the view defined as <a href="/news/categories/$!newsCategory.id"> in google chrome here's what I see... <a href="/news/categories/">...

Now, instinct says to fetch the _id part by doing $!newsCategory._id but this just spills the whole document as a string and appends the ._id part at the end of the string.

<a href="/news/categories/Document{{_id=54ad4568e451500a45f60200, className=packageName.NewsCategory, categoryName=General, uid=1, version=2, createdAt=Wed Jan 07 15:40:40 WAT 2015, updatedAt=Fri Apr 17 16:37:09 WAT 2015, active=true}}._id">


回答1:


Why do you want to do anything with JSON at all? Can't you simply use retrieved Document object (driver has already parsed JSON to prepare that object for you) and map it to your POJO in code?

(and who knows, maybe in many cases conversion may be not needed at all, as Document implements Map, you have names in POJO and Document that match each other, and therefore it should be treated well by a template engine that is not complex...)




回答2:


I discovered my self that deserialize Documents to POJO with GSON will not work for the _id without some modifications. Resulting that the _id was different in the POJO from the original _id stored in MongoDB.

Look at this solution to solve it. Converting BSON Type ObjectId to JSON (Storing in Mongodb) -Java




回答3:


What about traversing over the document's JSON and replace all "_id : { "$oid" : "..." } with id?

ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(bsonFile);
replaceIds(jsonNode);

void replaceIds(JsonNode rootNode) {
    if (rootNode.has("_id")) {
        String id = rootNode.get("_id").get("$oid").asText();
        ObjectNode objectNode = (ObjectNode) rootNode;
        objectNode.remove("_id");
        objectNode.put("id", id);
     }
    for (JsonNode childeNode : rootNode) {
        replaceIds(childeNode);
    }
}

This will flatten all _id parts. Of course, if your POJOs fields do not all have the "id" name, you'll need also to traverse over your object and find the corresponding name - It shouldn't be too hard! After all, you are looking just for ObjectId and can assume the ordering is the same as long as you do not have old objects in your repository from a time were the fields were ordered differently.



来源:https://stackoverflow.com/questions/32115005/how-to-deserialize-json-document-obtained-from-mongodb-into-a-pojo-migratin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!