[JAVA-3825] Bson Filter behavior differs from BasicDBObject Filter Created: 28/Aug/20  Updated: 01/Sep/20  Resolved: 31/Aug/20

Status: Closed
Project: Java Driver
Component/s: Codecs, Query Operations
Affects Version/s: 3.12.5
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Barron Anderson Assignee: Brian DeLeonardis (Inactive)
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

MacOS Mojave 10.14.6, Java 1.8, Driver 3.12.5, Mongo 3.6.17-ent single node replicaset



 Description   

Working with customer to upgrade a data access layer Java class.  Trying to implement consistency across the board.  I have elected to use the Bson query helpers defined in "org.bson.conversions.Bson.Filters".  I am converting use of BasicDBObject and encountered a difference.  For this reason I am creating this ticket.  This might be a known behavior or might be a discovered bug - I will let you decide!  Here are the details...

 

Consider the following unit test...

 

@Test
public void mytest()
{
 com.mongodb.MongoClientSettings mongoClientSettings = com.mongodb.MongoClientSettings.builder()
 .applyConnectionString(new com.mongodb.ConnectionString("mongodb://testuser:mysecret@localhost:27017/?replicaSet=replSet&w=majority&readConcernLevel=majority&readPreference=primary&authSource=admin&retryWrites=true&maxPoolSize=10&waitQueueTimeoutMS=1000"))
 .build();
 
 com.mongodb.client.MongoClient client = com.mongodb.client.MongoClients.create(mongoClientSettings);
 com.mongodb.client.MongoDatabase db = client.getDatabase("javatest");
 com.mongodb.client.MongoCollection<org.bson.Document> collection = db.getCollection("troubleshooting");
 collection.deleteMany(new org.bson.BsonDocument());
 org.bson.Document insertedDocument = new org.bson.Document();
 insertedDocument.append("field1", 1);
 collection.insertOne(insertedDocument);
 Object value = new Object();
 value = new Integer[] {4, 5, 6};
 
 BasicDBObject filter = new BasicDBObject("field1", new BasicDBObject("$nin", value));
 
 com.mongodb.client.FindIterable<org.bson.Document> iterable1 = collection.find(filter);
 try(com.mongodb.client.MongoCursor<org.bson.Document> cursor1 = iterable1.iterator())
 {
 while (cursor1.hasNext())
 {
 org.bson.Document queriedDocument1 = cursor1.next();
 System.out.println(String.format("queriedDocument1: %s", queriedDocument1));
 }
 }
}

 

If I change the filter predicate to use the Filters helper Bson object..

 

@Test
public void mytest()
{
 com.mongodb.MongoClientSettings mongoClientSettings = com.mongodb.MongoClientSettings.builder()
 .applyConnectionString(new com.mongodb.ConnectionString("mongodb://testuser:mysecret@localhost:27017/?replicaSet=replSet&w=majority&readConcernLevel=majority&readPreference=primary&authSource=admin&retryWrites=true&maxPoolSize=10&waitQueueTimeoutMS=1000"))
 .build();
 
 com.mongodb.client.MongoClient client = com.mongodb.client.MongoClients.create(mongoClientSettings);
 com.mongodb.client.MongoDatabase db = client.getDatabase("javatest");
 com.mongodb.client.MongoCollection<org.bson.Document> collection = db.getCollection("troubleshooting");
 collection.deleteMany(new org.bson.BsonDocument());
 org.bson.Document insertedDocument = new org.bson.Document();
 insertedDocument.append("field1", 1);
 collection.insertOne(insertedDocument);
 Object value = new Object();
 value = new Integer[] {4, 5, 6};
 
 org.bson.conversions.Bson filter = com.mongodb.client.model.Filters.nin("field1", value);
 
 com.mongodb.client.FindIterable<org.bson.Document> iterable1 = collection.find(filter);
 try(com.mongodb.client.MongoCursor<org.bson.Document> cursor1 = iterable1.iterator())
 {
 while (cursor1.hasNext())
 {
 org.bson.Document queriedDocument1 = cursor1.next();
 System.out.println(String.format("queriedDocument1: %s", queriedDocument1));
 }
 }
}

{{ I get a codec error org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class [Ljava.lang.Integer;.}}

 

Please advise...



 Comments   
Comment by Barron Anderson [ 01/Sep/20 ]

Thanks for the clarification Brian.  Regarding the overloads... Are you saying because this example uses a variable of type Object it uses the method signature ...

 

public static <TItem> Bson nin(final String fieldName, final TItem... values) 

 

... whereas if it were Integer[] it would use ....

 

public static <TItem> Bson nin(final String fieldName, final Iterable<TItem> values)

 

?

Comment by Brian DeLeonardis (Inactive) [ 31/Aug/20 ]

Hi @ BarronAnderson,
This is actually the expected behavior. The method signature is public static <TItem> Bson nin(final String fieldName, final TItem... values), so it takes a String and a variable number of the same type. You can either pass the values in individually: nin("fieldname", 4, 5, 6) or in an array of objects: nin("fieldname", new Integer[]{4, 5, 6}). You can’t, however, pass in an array of primitives, because primitives cannot be generics.

You can also pass in a list: nin("fieldname", Arrays.asList(4, 5, 6)) because the nin method is overloaded so it will go to the method with the: public static <TItem> Bson nin(final String fieldName, final Iterable<TItem> values) signature.

In your second example’s case, the problem is that the second parameter has a static type of Object (not an array), so the compiler is putting the entire array into one parameter in the nin function. If you change the static type of your variable value to  Integer[] it should work. 

Generated at Thu Feb 08 09:00:31 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.