Results 1 to 8 of 8

Thread: Spring Data Document M2: Bug with @DBRef

  1. #1
    Join Date
    Apr 2011
    Posts
    3

    Default Spring Data Document M2: Bug with @DBRef

    @DBRef works with Lists but not with properties.

    With:
    @DBRef
    private List<Address> addresses;
    Loading and saving works!

    With:
    @DBRef
    private Address address;
    Only saving works (correct data at mongoDB).
    Loading throws this exception:

    Exception in thread "main" org.springframework.core.convert.ConverterNotFound Exception: No converter found capable of converting from 'com.mongodb.DBRef' to 'persontest.Address'



    Code:
    @Document
    public class User {
        @Id
        private ObjectId id;
    
        @Indexed
        private Integer ssn;
    
        @DBRef
        private List<Address> addresses;
    
        @DBRef
        private Address address;
       ...
    }
    Code:
    @Document
    public class Address {
    
        @Id
        private ObjectId id;
    
        private String street;
        ...
    }
    Code:
    User user = new User();
    user.setSsn(111);
    
    Address address = new Address();
    address.setStreet("Mainstreet");
    mongoOps.insert(address);
    
    user.setAddress(address);
    
    mongoOps.insert(user);
    
    log.info(mongoOps.findOne(new Query(Criteria.where("ssn").is(111)), User.class));

  2. #2
    Join Date
    Jul 2006
    Location
    Lamar, Missouri USA
    Posts
    36

    Default

    Yikes!

    I pushed a fix for this and created a test case specifically for non-list, referenced properties.

    If you use a snapshot build (after the nightly runs and creates one, that is ), you should get a fix for that.

    Sorry for the bug. It was a two-line fix so should have been caught earlier.
    Jon Brisbin
    SpringSource
    http://www.springsource.com

  3. #3
    Join Date
    Jun 2011
    Posts
    3

    Default I have the same issue @DBRef annotation not working with properties

    org.springframework.core.convert.ConverterNotFound Exception: No converter found capable of converting from 'com.mongodb.DBRef' to 'com.test.Person'
    I am using spring-data-mongodb version 1.0.0.M2. Please advise.

  4. #4
    Join Date
    Jun 2011
    Posts
    3

    Default

    Hi a quick correction, I updated to 1.0.0.M3 and i still have the same issue. Can you please tell me on which version did your fix get in?

  5. #5
    Join Date
    Sep 2011
    Posts
    4

    Default Still an issue?

    I have a case where this is continuing to fail in 1.0.0M4 -- the option to use a List is also not working for me, however. Is it expected that this has been fixed? Is there bug to track it?

    M

  6. #6
    Join Date
    Sep 2011
    Posts
    4

    Default Found a work around

    This is a total hack, but it does seem to work until a real fix can make it into the Spring code base. The issue is most definitely the storage of the reference, not the loading -- the value on the '$id' field is stored as "3a7blahblahblah" instead of ObjectId("3a7blahblahblah"). So the solution is to use a Mongo event listener to make this happen before the save occurs:

    Code:
    @Component
    public class MyDocReferenceFixer extends AbstractMongoEventListener<MyDoc> {
    
        @Override
        public void onBeforeSave(MyDoc source, DBObject dbo) {
            super.onBeforeSave(source, dbo);
            
            Object o = dbo.get("myReferenceProperty");
            DBRef dbref = (DBRef)o;
            
            dbo.put("myReferenceProperty", new DBRef(dbref.getDB(), dbref.getRef(), new ObjectId((String)dbref.getId())));
        }
        
    }
    Pretty simple -- biggest downfall here (aside from it being a total hack) is that you have to do it for every Document type that has a DBRef, which will get irritating after a while. It does appear to work so far, though -- after putting this in place, my DBRef objects are eagerly loaded when using the MongoTemplate object, and when using a repository.

    M

  7. #7
    Join Date
    Dec 2008
    Location
    Aurora, CO, USA
    Posts
    24

    Default

    VGuna and I (johannz) discussed this on September 9 in http://forum.springsource.org/showth...9-returns-null

    I created a bug for it: https://jira.springsource.org/browse/DATADOC-275 - DBRef fields and collections are returning nulls. In that bug I researched the cause, and have a proposed fix.

    Copied from the bug:
    Analysis

    I think the problem is in the MappingMongoConverter, and how it is storing DBRefs. Looking at the code for the createDBRef method, it is not doing any type conversion of the ID that it retrieves from the target object, when it should be.

    From the createDBRef method, exception handling removed:

    Code:
    Object id = null;
    	BeanWrapper<MongoPersistentEntity<Object>, Object> wrapper = BeanWrapper.create(target, conversionService);
    	id = wrapper.getProperty(idProperty, Object.class, useFieldAccessOnly);
    
    	String collection = dbref.collection();
    	if ("".equals(collection)) {
    		collection = targetEntity.getCollection();
    	}
    
    	String dbname = dbref.db();
    	DB db = StringUtils.hasText(dbname) ? mongoDbFactory.getDb(dbname) : mongoDbFactory.getDb();
    	return new DBRef(db, collection, id);
    Suggested fix

    I suspect the line "id = wrapper.getProperty(idProperty, Object.class, useFieldAccessOnly);" should be replaced by this code, copied from writeInternal:
    Code:
    Object idObj = null;
    	Class<?>[] targetClasses = new Class<?>[] { ObjectId.class, String.class, Object.class };
    	for (Class<?> targetClass : targetClasses) {
    		try {
    			idObj = wrapper.getProperty(idProperty, targetClass, useFieldAccessOnly);
    			if (null != idObj) {
    				break;
    			}
    		} catch (ConversionException ignored) {
    		} catch (IllegalAccessException e) {
    			throw new MappingException(e.getMessage(), e);
    		} catch (InvocationTargetException e) {
    			throw new MappingException(e.getMessage(), e);
    		}
    	}
    
    	if (null != idObj) {
    		dbo.put("_id", idObj);
    	} else {
    		if (!VALID_ID_TYPES.contains(idProperty.getType())) {
    			throw new MappingException("Invalid data type " + idProperty.getType().getName()
    					+ " for Id property. Should be one of " + VALID_ID_TYPES);
    		}
    	}

  8. #8
    Join Date
    Sep 2011
    Posts
    4

    Default

    I did see that defect after my initial post, thanks -- it was one of the pieces of evidence I used to find the workaround. Unfortunately, it doesn't do me any good until the next version of spring-data rolls out with that code (I tried the latest snapshot, which didn't have any effect). I think I certainly was able to prove that the theory that the $id value is being stored incorrectly is true, at least in my instance, and my work around enables me to move forward for now.

    M

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •