Results 1 to 10 of 11

Thread: Sprint Data Mongo RC1 issue querying UUID

Hybrid View

  1. #1
    Join Date
    Dec 2011
    Posts
    6

    Question Sprint Data Mongo RC1 issue querying UUID

    I have been sucesfully querying a Mongo collection where the key is of UUID type. Here is an example:

    MongoTemplate().findOne(new Query(Criteria.where("_id").is(userId)),SocialUser .class);

    With M5 this was working fine but after switching to RC1 I am always getting a null result from this query. To understand what was going on I enabled MongoDb profiling I can see why the query returns nothing. The query parameter for _id produced by Spring has changed:

    WITH M5:

    { "ts" : ISODate("2011-12-16T20:35:44.523Z"), "op" : "query", "ns" : "MyList.SocialUser", "query" : { "_id" : BinData(3,"4tF9oXFLI0OudRiiBU9BWQ==") }, "ntoretur
    n" : 1, "nscanned" : 1, "nreturned" : 1, "responseLength" : 305, "millis" : 0, "client" : "10.10.4.99", "user" : "" }

    WITH RC1:

    { "ts" : ISODate("2011-12-16T20:37:26.854Z"), "op" : "query", "ns" : "MyList.SocialUser", "query" : { "_id" : { "mostSigBits" : NumberLong("4837793376138809826"
    ), "leastSigBits" : NumberLong("6431508628474721710") } }, "ntoreturn" : 1, "idhack" : true, "responseLength" : 20, "millis" : 0, "client" : "10.10.4.99", "user
    " : "" }

    Obviously M5 and RC1 have a significant difference here. I am not sure whether it is a bug or by design but I can't find any documentation or notes about this change.

    Why is RC1 passing the UUID parameter like this: { "mostSigBits" : NumberLong("4837793376138809826"
    ), "leastSigBits" : NumberLong("6431508628474721710") } instead of { "_id" : BinData(3,"4tF9oXFLI0OudRiiBU9BWQ==") } ? How can I adjust my configuration so that RC1 does what M5 was doing?

    Thanks,

    David

  2. #2
    Join Date
    Dec 2007
    Posts
    27

    Default

    Also facing this problem,

    looking in source code I have found that MongoSimpleTypes has a SUPPORTED_ID_CLASSES collection containing only: ObjectId.class, String.class, BigInteger.class

    may be related to the problem ?

  3. #3
    Join Date
    Dec 2011
    Posts
    6

    Default Hack / work around

    I was able to work around the problem by registering a custom UUID to DBObject converter that returns the UUID object (without converting it). I do not fully understand how the hack works but it does it.

    Here is my converter:

    public class GenericConverterImplementation implements GenericConverter {

    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
    Set<ConvertiblePair> pairs = new HashSet<ConvertiblePair>();
    pairs.add(new ConvertiblePair(UUID.class, DBObject.class));
    pairs.add(new ConvertiblePair(DBObject.class, UUID.class));
    return pairs;
    }

    @Override
    public Object convert(Object source, TypeDescriptor sourceType,
    TypeDescriptor targetType) {


    if (sourceType.getObjectType() == UUID.class && targetType.getObjectType() == DBObject.class)
    {
    return UUIDHelper.fromJavaToDotNet((UUID)source);
    }
    if (targetType.getObjectType() == UUID.class)
    {
    return UUIDHelper.fromDotNetToJava((UUID)source);
    }
    throw new IllegalArgumentException("Could not find a converter from " + sourceType.getName() + " to " + targetType.getName());
    }


    }

    And here is how I am registering it:

    socialMongoTemplate = new MongoTemplate(new SimpleMongoDbFactory("myserver","mydbname"));
    GenericConversionService serv = (GenericConversionService)socialMongoTemplate.getC onverter().getConversionService();
    ArrayList<GenericConverter> converters = new ArrayList<GenericConverter> ();
    converters.add(new GenericConverterImplementation());
    CustomConversions conversions = new CustomConversions(converters);((MappingMongoConver ter)socialMongoTemplate.getConverter()).setCustomC onversions(conversions);
    serv.addConverter(new GenericConverterImplementation());

    (Not the most elegant way of registering it. I am new to Spring and still not familiar with Ioc.)

    David

  4. #4
    Join Date
    Dec 2007
    Posts
    27

    Default

    Registering Converter and not respecting the "contract" to return the correct type is definitively not a solution for me.

    We can register converter to/from String like this:
    Code:
    public class UUIDToStringConverter implements Converter<UUID, String> {
    
    	@Override
    	public String convert(UUID inUUID) {
    		return inUUID.toString();
    	}
    
    }
    
    public class UUIDToStringConverter implements Converter<UUID, String> {
    
    	@Override
    	public String convert(UUID inUUID) {
    		return inUUID.toString().toLowerCase();
    	}
    
    }
    and register them in the context.xml

    Code:
    <mongo:mapping-converter id="mongoDbConverter">
    	<mongo:custom-converters>
    		<mongo:converter>
    			<bean class="your.package.path.UUIDToStringConverter"/>
    		</mongo:converter>
    		<mongo:converter>
    			<bean class="your.package.path.StringToUUIDConverter"/>
    		</mongo:converter>
     	</mongo:custom-converters>
    </mongo:mapping-converter>
    
    <bean id="mongoTemplate"  class="org.springframework.data.mongodb.core.MongoTemplate">
    	<constructor-arg ref="mongoDbFactory" />
    	<constructor-arg ref="mongoDbConverter" />
    </bean>

    but the field will then be a String not a Binary, subtype UUID…

  5. #5
    Join Date
    Apr 2006
    Location
    Dresden, Germany
    Posts
    483

    Default

    @neutrino: Serializing UUIDs is not supported out of the box, so you have to write your own Converter implementations. If you think it's a feature worth being added feel free to raise a JIRA. Generally the approach JeitEmegie showed should be working.

    @JeitEmegie: You could come up with converters of:

    Code:
    public enum UUIDToBinaryConverter implements Converter<UUID, org.bson.types.Binary> {
    
      INSTANCE;
    
      @Override
      public String convert(UUID inUUID) {
        return new Binary(inUUID.toString().getBytes());
      }
    }
    as well as the appropriate invert one if you insist on storing them as binary data. The SUPPORTED_ID_CLASSES is gone in recent versions. It essentially captured the types we ware able to auto-generate. Shouldn't have to do anything with the issue.

  6. #6
    Join Date
    Dec 2007
    Posts
    27

    Default

    I kept my first option to use UUID stored as String, the need of Binary was just for evaluation purpose, not a requirement…

Posting Permissions

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