问题
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