Today , I met with a problem that I have a field whose type is a class code-generated Protobuf. If I used Morphia to automatically map this field to an embedded Mongo document, morphia will map each of its member field by reflection which was not wanted by me. So here came the requirement that I want to manually map that field. For example I have a annotated class :
@Entity(value ="Resources", noClassnameStored = true)
public class ResourceDO implements IResource {
@Id
private String systemId;
...
@Embedded
Rule rule;
...
}
I wanted to manually encode (to BSON Object) and decode (from BSON Object) the "rule" field. And the class Rule is of a recursive form :
public class Rule {
String id ;
Rule rule;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Rule getRule() {
return rule;
}
public void setRule(Rule rule) {
this.rule = rule;
}
}
I found that Morphia.getMapper().getConverters() can get all the default converters provided by Morphia. And the DefaultConverter also provide a addConverter() method , so I realized the following converter:
public class RuleConverter extends TypeConverter {
public RuleConverter(){
super(Rule.class);
}
@Override
public Object decode(Class targetClass, Object fromDBObject,
MappedField optionalExtraInfo) throws MappingException {
if (fromDBObject == null) return null;
BSONObject bson = (BSONObject) fromDBObject;
Rule root = new Rule();
String id = (String)bson.get("id");
root.setId(id);
Rule parent = root;
while ( bson.get("rule")!= null ){
bson = (BSONObject)bson.get("rule");
Rule rule = new Rule();
id = (String)bson.get("id");
rule.setId(id);
parent.setRule(rule);
parent = rule;
}
return root;
}
@Override
public boolean isSupported(Class<?> c, MappedField optionalExtraInfo) {
return oneOf(c, supportTypes);
}
@Override
public Object encode(Object value, MappedField optionalExtraInfo) {
Rule rule = (Rule) value;
BSONObject root = new BasicBSONObject();
String id = rule.getId();
root.put("id", id);
BSONObject parent = start;
while ( rule.getRule() != null ){
rule = rule.getRule();
BSONObject bson = new BasicBSONObject();
id = rule.getId();
bson.put("id", id);
parent.put("rule", bson);
parent = bson;
}
return root;
}
}
However , I found , when I inserted the resource , it works well, for example :
{
_id : XXXXXXX ,
....,
rule : {
id : "1",
rule : {
id : "2"
}
}
}
But when I loaded the resource, the fromObject passed to my decode method is :
{
id : "2"
}
When I looked at the source codes of Morphia, it was because that Mapper.readMappedField() will invoke EmbeddedMapper.fromObject() to read my filed. And EmbeddedMapper will strip the other fileds of the BSON Object by invoking :
Object dbVal = mf.getDbObjectValue(dbObject);
And then the BSON Object will become.
{
id : "1",
rule : {
id : "2"
}
}
Then it will invoke DefaultConverters.fromDBObject() which will again invoke :
Object dbVal = mf.getDbObjectValue(dbObject);
to strip the outer layer of the BSON Object , so the BSON Object passed to the decode method of my converter became :
{
id : "2"
}
So, based on the following codes of Mapper.readMappedField() :
private void readMappedField(DBObject dbObject, MappedField mf, Object entity, EntityCache cache) {
if (mf.hasAnnotation(Property.class) || mf.hasAnnotation(Serialized.class)
|| mf.isTypeMongoCompatible() || converters.hasSimpleValueConverter(mf))
opts.valueMapper.fromDBObject(dbObject, mf, entity, cache, this);
else if (mf.hasAnnotation(Embedded.class))
opts.embeddedMapper.fromDBObject(dbObject, mf, entity, cache, this);
else if (mf.hasAnnotation(Reference.class))
opts.referenceMapper.fromDBObject(dbObject, mf, entity, cache, this);
else {
opts.defaultMapper.fromDBObject(dbObject, mf, entity, cache, this);
}
}
I add a tag @Property(value="rule") to my "rule" field, thus make Mapper to invoke ValueMapper.fromDBObject() which work around the problem.
分享到:
相关推荐
These tutorials describe how to map your classes to your tables manually (rather than with an automated tool like SqlMetal) so that you can have support for M:M relationships and data binding against ...
The corpus comes with a User Manual detailing corpus design specifications and part-of-speech tags. The XML structure of the corpus was validated using the parser built in Xaira. Part-of-speech ...
Simple application that shows how to use the Data Control to connect to the Biblio.mdb database and display all authors in the Authors table.
The ggplot section notes the library’s historical relationship with R and the Grammar of Graphics and illustrates how to use ggplot to build some common statistical plots. Finally, the seaborn ...
One of my jobs was to write programs that processed the information, deduced the fields, extracted compound addresses and telephone numbers, and tidied up the results to put into a new version of the ...
The World Wide Web has been credited with bringing the Internet to the masses. The Internet was previously the stomping ground of academics and a small, elite group of computer professionals, mostly...
A clustered index is like a telephone directory in which all of the rows for customers with the same last name are clustered together in the same part of the book. Just as the organization of a ...
Explore the common problems developers face when using Xcode, and find out how to get the most out of your IDE. Dig into Xcode, and you’ll discover it’s richer and more powerful than you might have...
In this tutorial, we'll cover some of the basics of Unicode-encoded text and Unicode files, and how to view and manipulate it in UltraEdit. Search and delete lines found UEStudio and UltraEdit provide...
You'll start with a broad overview of AWS and learn how to spin-up servers manually and from the command line. Then you'll explore infrastructure automation with the AWS CloudFormation service, where...
By the end of the book, you will manually maintain the EMF model for an Xtext DSL and will see how an Xtext DSL can also be used in IntelliJ. Style and approach A step-by step-tutorial with ...
Artificial Neural Networks with Java also teaches you how to prepare the data to be used in neural network development and suggests various techniques of data preparation for many unconventional ...
Learning to schedule the execution of scrapers achieves the goal of complete automation, and the final introduction of basic object-oriented programming (OOP) in the development of a scraping class ...
The goal was to detect figures and part labels in U.S. patent drawing pages. The challenge drew 232 teams of two, of which 70 teams (30%) submitted solutions. Collectively, teams submitted 1,797 ...
In practice, the running time of the parser on a test sentence is linear with respect to the sentence length. We also demonstrate that the parser can train from other domains without modification to ...
'This sample demostrates the use of an ole object ptr being passed to 'an external (and optionally remote) ole server. The ole server then 'periodically calls a method on this object ptr. This has the...
With the methods introduced by this book, software engineers should gain a good understanding of the limited automation provided by the available testing tools and how to improve the current test ...