Как сделать безопасные вставки, используя GORM для низкоуровневого API Mongo? - PullRequest
3 голосов
/ 28 июля 2011

Я пытаюсь сделать безопасную вставку, используя GORM для низкоуровневого API Монго.

Я воспроизвел проблему в чистом проекте Grails следующим образом:

  1. Создать новый проект Grails
  2. Удалите плагин Hibernate
  3. Установить плагин GORM for Mongo
  4. Создать контроллер со следующим действием

    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 ""
    
        }
    }
    
  5. При запуске действия выдается следующее исключение:

    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)
    
  6. Если я изменю действие для использования API Mongo Java следующим образом:

    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 ""
    
    }
    
  7. Теперь это работает, и документ сохраняется в базе данных Mongo, как и ожидалось.

У меня такой вопрос: это ошибка в обертке GMongo, или же тогда как делать безопасные записи с использованием низкоуровневого API?

1 Ответ

4 голосов
/ 28 июля 2011

Это появляется из-за библиотеки GMongo и того, как она исправляет объект DBCollection для обработки передачи объектов Map в метод insert и преобразует их. Предполагается, что все аргументы метода insert являются Map объектами, и затем попытается получить свойство value из Map.Entry.

Глядя на источник Patcher.groovy из библиотеки GMongo , вы увидите функцию _convert(), которая пытается это сделать. Это похоже на разветвление проекта Github с проверкой типа аргумента (необходимо проверить, является ли это WriteConcern или проверить, действительно ли это Map перед передачей на _converAllCharSeqToString).

EDIT:

Я создал запрос на получение на Github для соответствующего изменения кода, но, как и во всем Groovy, исправление класса также может помочь. Вы можете «пропатчить» класс WriteConcern в вашем BootStrap.groovy, чтобы иметь метод getValue, который позволит вам передать параметр в:

def init = { servletContext ->
    com.mongodb.WriteConcern.metaClass.getValue  = { null }
}
...