I am trying to do a safe insert using GORM for Mongo’s low-level API.
I have reproduced the problem in a clean Grails project like follows:
- Create a new Grails project
- Uninstall the Hibernate plugin
- Install the GORM for Mongo plugin
-
Create a controller with the following action
import com.mongodb.* class TestController { def mongo def index = { def database = mongo.getDB("ExampleDatabase") def collection = database.getCollection("ExampleCollection") def document = new BasicDBObject(); document.put("key", "value") collection.insert(document, WriteConcern.SAFE) render "" } } -
When firing the action, the following exception is thrown:
2011-07-27 12:53:03,161 [http-8080-1] ERROR errors.GrailsExceptionResolver - Exception occurred when processing request: [GET] /WriteConcern.SAFE-test/test/index Stacktrace follows: groovy.lang.MissingPropertyException: No such property: value for class: com.mongodb.WriteConcern at com.gmongo.internal.Patcher$__converAllCharSeqToString_closure2.doCall(Patcher.groovy:81) at com.gmongo.internal.Patcher._converAllCharSeqToString(Patcher.groovy:80) at com.gmongo.internal.Patcher$_converAllCharSeqToString.callStatic(Unknown Source) at com.gmongo.internal.Patcher$_converAllCharSeqToString.callStatic(Unknown Source) at com.gmongo.internal.Patcher._convert(Patcher.groovy:69) at com.gmongo.internal.Patcher$_convert.callStatic(Unknown Source) at com.gmongo.internal.Patcher$__patchInternal_closure1.doCall(Patcher.groovy:31) at writeconcern.safe.test.TestController$_closure1.doCall(TestController.groovy:17) at writeconcern.safe.test.TestController$_closure1.doCall(TestController.groovy) at java.lang.Thread.run(Thread.java:680) -
If I change the action to use the Mongo Java API as follows:
def index = { def database = new Mongo().getDB("ExampleDatabase") def collection = database.getCollection("ExampleCollection") def document = new BasicDBObject(); document.put("key", "value") collection.insert(document, WriteConcern.SAFE) render "" } -
Now it works and the document is persisted to the Mongo database as expected.
My question is this: Is this a bug with the GMongo wrapper, or then how should safe writes be done using the low level API?
This appears due to the GMongo library and how it patches the
DBCollectionobject to handle passing ofMapobjects to theinsertmethod and converts them. It assumes that all of the arguments of theinsertmethod areMapobjects and will then try to get thevalueproperty from theMap.Entry.Looking at the source of Patcher.groovy from GMongo library you’ll see the function
_convert()that attempts to do this. It looks like a fork of the Github project with type check on the argument (either to see if it’s aWriteConcernor to check if it’s actually aMapbefore passing to the_converAllCharSeqToString) is necessary.EDIT:
I created a pull request on Github for the appropriate code change, but as with all things Groovy, patching the class can also help. You can “patch” the
WriteConcernclass in yourBootStrap.groovyto have agetValuemethod and that will allow you to pass the parameter in: