Spring Data MongoDB
  1. Spring Data MongoDB
  2. DATAMONGO-488

Stackoverflow when querying document with cycle reference using @DBRef

    Details

    • Type: Bug Bug
    • Status: Waiting for Feedback
    • Priority: Minor Minor
    • Resolution: Unresolved
    • Affects Version/s: 1.0.2
    • Fix Version/s: None
    • Component/s: Core
    • Labels:
      None
    • Environment:
      linux mint 13, java 7, mongodb 2.0.4

      Description

      Given two documents which reference each other with a DBRef

      @Document
      class Site {
          @DBRef User admin;
      }
      
      @Document
      class User {
          @DBRef Site site;
      }
      
      Site siteSaved = siteRepository.save(new Site());
      User userSaved = userRepository.save(new User(siteSaved));
      siteSaved.setAdmin(userSaved);
      siteRepository.save(siteSaved);
      
      siteRepository.findOne(siteSaved.id); // stackoverflow here
      
      java.lang.StackOverflowError
      	at org.bson.BasicBSONEncoder._put(BasicBSONEncoder.java:417)
      	at org.bson.BasicBSONEncoder.putObjectId(BasicBSONEncoder.java:388)
      	at org.bson.BasicBSONEncoder._putObjectField(BasicBSONEncoder.java:188)
      	at org.bson.BasicBSONEncoder.putObject(BasicBSONEncoder.java:121)
      	at org.bson.BasicBSONEncoder.putObject(BasicBSONEncoder.java:86)
      	at com.mongodb.DefaultDBEncoder.writeObject(DefaultDBEncoder.java:27)
      	at com.mongodb.OutMessage.putObject(OutMessage.java:142)
      	at com.mongodb.OutMessage._appendQuery(OutMessage.java:85)
      	at com.mongodb.OutMessage.query(OutMessage.java:44)
      	at com.mongodb.OutMessage.query(OutMessage.java:38)
      	at com.mongodb.DBApiLayer$MyCollection.__find(DBApiLayer.java:303)
      	at com.mongodb.DBCollection.findOne(DBCollection.java:332)
      	at com.mongodb.DBCollection.findOne(DBCollection.java:318)
      	at com.mongodb.DBRefBase.fetch(DBRefBase.java:52)
      	at org.springframework.data.mongodb.core.convert.MappingMongoConverter$DelegatingParameterValueProvider.getParameterValue(MappingMongoConverter.java:950)
      	at org.springframework.data.mapping.model.BeanWrapper.<init>(BeanWrapper.java:115)
      	at org.springframework.data.mapping.model.BeanWrapper.create(BeanWrapper.java:73)
      	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:217)
      	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:200)
      	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.getValueInternal(MappingMongoConverter.java:712)
      	at org.springframework.data.mongodb.core.convert.MappingMongoConverter$2.doWithAssociation(MappingMongoConverter.java:239)
      	at org.springframework.data.mapping.model.BasicPersistentEntity.doWithAssociations(BasicPersistentEntity.java:185)
      	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:236)
      	at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:200)
      	at org.springframework.data.mongodb.core.convert.MappingMongoConverter$DelegatingParameterValueProvider.getParameterValue(MappingMongoConverter.java:950)
      	at org.springframework.data.mapping.model.BeanWrapper.<init>(BeanWrapper.java:115)
      	at org.springframework.data.mapping.model.BeanWrapper.create(BeanWrapper.java:73)
      

      As a workaround I can break this cycle and only reference Site from User and add an isAdmin property to User class but I think it is less direct and clear this way. It requires one more query to retrieve the admin of a Site.

      I fell that it is because retrieving a document from DBRef is not lazy as asked in DATAMONGO-348, but I thought it was eager only for one level depth.

        Issue Links

          Activity

          Hide
          Matthew T. Adams added a comment -

          IMHO, bidi relationships in object models are common, especially for people coming from the JPA & JDO side of the fence.

          Your suggestion of pushing logic up into the repository layer isn't ideal for me. If DATAJPA-237 is fixed, I'm on my way again using SD JPA + DataNucleus + MongoDB. Is that a possibility so that I don't have to wait for the general solution that you mentioned?

          Show
          Matthew T. Adams added a comment - IMHO, bidi relationships in object models are common, especially for people coming from the JPA & JDO side of the fence. Your suggestion of pushing logic up into the repository layer isn't ideal for me. If DATAJPA-237 is fixed, I'm on my way again using SD JPA + DataNucleus + MongoDB. Is that a possibility so that I don't have to wait for the general solution that you mentioned?
          Hide
          Ludovic Praud added a comment -

          Cyclic dependency is allowed in java objects graph in memory, is handle in java serialization, and some others persistence technology. It is handle as well in spring IoC bean injection. Of course mongodb does not provide direct cyclic dependency when querying but it does not forbid the cyclic dependency using dbref. May be it is a difficult case to handle when resolving query with spring data but it would be a great feature to use with lazy fetching.

          Show
          Ludovic Praud added a comment - Cyclic dependency is allowed in java objects graph in memory, is handle in java serialization, and some others persistence technology. It is handle as well in spring IoC bean injection. Of course mongodb does not provide direct cyclic dependency when querying but it does not forbid the cyclic dependency using dbref. May be it is a difficult case to handle when resolving query with spring data but it would be a great feature to use with lazy fetching.
          Hide
          Oliver Gierke added a comment -

          Just because something is common it doesn't mean it's a good idea . I doubt you get SD JPA running on top of DataNucleus' MongoDB implementation. As with all libraries claiming they provide a JPA API for a NoSQL store, they essentially don't. They usually provide a profile of the JPA, as some features of it essentially can't work with MongoDB (try calling EntityManager.getTransaction() or even better EntityTransaction.rollBack()), a huge part of the mapping annotations simply doesn't make sense. To round this off you're not able to use store specific functionality through JPA neither (upserts, geo-spatial stuff, indexing). To get SD JPA running you at least need the meta-model API as well as a complete Criteria API in place. None of the self-entitled JPA-for-NoSQL approaches I've seen so far provided this.

          This issue will eventually resolve when we fix DATAMONGO-348. Still it's very unlikely that this ticket (as well as DATAJPA-237) will make it into the upcoming GA releases.

          Show
          Oliver Gierke added a comment - Just because something is common it doesn't mean it's a good idea . I doubt you get SD JPA running on top of DataNucleus' MongoDB implementation. As with all libraries claiming they provide a JPA API for a NoSQL store, they essentially don't. They usually provide a profile of the JPA, as some features of it essentially can't work with MongoDB (try calling EntityManager.getTransaction() or even better EntityTransaction.rollBack() ), a huge part of the mapping annotations simply doesn't make sense. To round this off you're not able to use store specific functionality through JPA neither (upserts, geo-spatial stuff, indexing). To get SD JPA running you at least need the meta-model API as well as a complete Criteria API in place. None of the self-entitled JPA-for-NoSQL approaches I've seen so far provided this. This issue will eventually resolve when we fix DATAMONGO-348 . Still it's very unlikely that this ticket (as well as DATAJPA-237 ) will make it into the upcoming GA releases.
          Hide
          Matthew T. Adams added a comment -

          @Oliver, I generally agree with your point about JPA. I think DataNucleus's JPA metamodel layer is logically above the database layer, so I still expect it to work. The reason for DATAJPA-237 is primarily due to the fact that the JPA TCK is not openly available, which is another discussion.

          As for transaction management, begin & commit seem like no-ops to me, and JPA basically punts on rollback anyway, so maybe it's ok.

          JDO support (DATACMNS-96) would be a great solution to this problem. I wish I had the time to contribute, but I don't (yet).

          Show
          Matthew T. Adams added a comment - @Oliver, I generally agree with your point about JPA. I think DataNucleus's JPA metamodel layer is logically above the database layer, so I still expect it to work. The reason for DATAJPA-237 is primarily due to the fact that the JPA TCK is not openly available, which is another discussion. As for transaction management, begin & commit seem like no-ops to me, and JPA basically punts on rollback anyway, so maybe it's ok. JDO support ( DATACMNS-96 ) would be a great solution to this problem. I wish I had the time to contribute, but I don't (yet).
          Hide
          Hasnain Javed added a comment -

          We also had the same issue and our workaround was the same (to break the cyclic relationship in the domain model) as Ludovic Praud.

          Show
          Hasnain Javed added a comment - We also had the same issue and our workaround was the same (to break the cyclic relationship in the domain model) as Ludovic Praud.

            People

            • Assignee:
              Oliver Gierke
              Reporter:
              Ludovic Praud
            • Votes:
              6 Vote for this issue
              Watchers:
              8 Start watching this issue

              Dates

              • Created:
                Updated: