2011-07-28 5 views
3

J'essaye de faire une insertion sûre en utilisant GORM pour l'API de bas niveau de Mongo.Comment faire des insertions sécurisées en utilisant GORM pour l'API de bas niveau de Mongo?

J'ai reproduit le problème dans un projet Grails propre comme suit:

  1. Créer une nouvelle Grails projettent
  2. Désinstaller le plugin Hibernate
  3. Installer le Gorm pour le plugin Mongo
  4. Créer une contrôleur avec l'action suivante

    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. Lors du tir de l'action, l'exception suivante est générée:

    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. Si je change l'action d'utiliser l'API Mongo Java comme suit:

    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. Maintenant, il fonctionne et le document est persisté dans la base de données Mongo comme prévu.

Ma question est la suivante: Est-ce un bug avec l'emballage GMongo, ou alors comment doit se faire en toute sécurité écritures en utilisant l'API de bas niveau?

Répondre

4

Cela apparaît en raison de la bibliothèque GMongo et comment il corrige l'objet DBCollection pour gérer le passage des objets Map à la méthode insert et les convertit. Il suppose que tous les arguments de la méthode insert sont des objets Map et essaient alors d'obtenir la propriété value à partir du Map.Entry.

En regardant le source of Patcher.groovy from GMongo library, vous verrez la fonction _convert() qui tente de le faire. Il ressemble à une fourche du projet Github avec le type vérifier sur l'argument (soit pour voir si c'est un WriteConcern ou pour vérifier si c'est effectivement un Map avant de passer au _converAllCharSeqToString) est nécessaire.

EDIT:

J'ai créé un pull request sur Github pour le changement de code approprié, mais comme avec toutes les choses Groovy, patcher la classe peut aussi aider. Vous pouvez « patch » la classe WriteConcern dans votre BootStrap.groovy d'avoir une méthode getValue et qui vous permettra de passer le paramètre:

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

Merci pour l'explication. Monkeypatching la classe WriteConcern comme vous l'avez dit fonctionne très bien. – AndrewW

Questions connexes