[JAVA-1763] CodecConfigurationException when using Filters class with aggregation Created: 15/Apr/15  Updated: 03/Jun/22  Resolved: 15/Feb/19

Status: Closed
Project: Java Driver
Component/s: BSON
Affects Version/s: 3.0.0
Fix Version/s: 3.11.0

Type: New Feature Priority: Major - P3
Reporter: Jochen Kemnade Assignee: Ross Lawley
Resolution: Done Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Attachments: File 0001-JAVA-1763-support-for-encoding-Bson-objects-embedded.patch     File aggregatebug.groovy     File issue1763.groovy    
Issue Links:
Related
is related to JAVA-1540 Create generic builders for aggregate... Closed

 Description   

I use com.mongodb.client.MongoCollection.aggregate(List<? extends Bson>) with an aggregation pipeline that contains $match directives. I build some of them with the com.mongodb.client.model.Filters class. When executing the aggregation I get an exception:

org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class com.mongodb.client.model.Filters$AndFilter.
	at org.bson.codecs.configuration.CodecCache.getOrThrow(CodecCache.java:46) ~[mongo-java-driver-3.0.0.jar:na]
	at org.bson.codecs.configuration.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:63) ~[mongo-java-driver-3.0.0.jar:na]
	at org.bson.codecs.configuration.ChildCodecRegistry.get(ChildCodecRegistry.java:51) ~[mongo-java-driver-3.0.0.jar:na]
	at org.bson.codecs.DocumentCodec.writeValue(DocumentCodec.java:174) ~[mongo-java-driver-3.0.0.jar:na]
	at org.bson.codecs.DocumentCodec.writeMap(DocumentCodec.java:189) ~[mongo-java-driver-3.0.0.jar:na]
	at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:131) ~[mongo-java-driver-3.0.0.jar:na]
	at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:45) ~[mongo-java-driver-3.0.0.jar:na]
	at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:63) ~[mongo-java-driver-3.0.0.jar:na]
	at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:29) ~[mongo-java-driver-3.0.0.jar:na]
	at org.bson.codecs.EncoderContext.encodeWithChildContext(EncoderContext.java:91) ~[mongo-java-driver-3.0.0.jar:na]
	at org.bson.codecs.BsonArrayCodec.encode(BsonArrayCodec.java:69) ~[mongo-java-driver-3.0.0.jar:na]
	at org.bson.codecs.BsonArrayCodec.encode(BsonArrayCodec.java:36) ~[mongo-java-driver-3.0.0.jar:na]
	at org.bson.codecs.EncoderContext.encodeWithChildContext(EncoderContext.java:91) ~[mongo-java-driver-3.0.0.jar:na]
	at org.bson.codecs.BsonDocumentCodec.writeValue(BsonDocumentCodec.java:133) ~[mongo-java-driver-3.0.0.jar:na]
	at org.bson.codecs.BsonDocumentCodec.encode(BsonDocumentCodec.java:112) ~[mongo-java-driver-3.0.0.jar:na]
	at org.bson.codecs.BsonDocumentCodec.encode(BsonDocumentCodec.java:40) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.connection.RequestMessage.addDocument(RequestMessage.java:216) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.connection.RequestMessage.addDocument(RequestMessage.java:168) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.connection.CommandMessage.encodeMessageBody(CommandMessage.java:69) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.connection.RequestMessage.encode(RequestMessage.java:132) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.connection.CommandProtocol.sendMessage(CommandProtocol.java:119) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.connection.CommandProtocol.execute(CommandProtocol.java:84) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:155) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:219) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.connection.DefaultServerConnection.command(DefaultServerConnection.java:146) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:182) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:166) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.operation.AggregateOperation$1.call(AggregateOperation.java:199) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.operation.AggregateOperation$1.call(AggregateOperation.java:196) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.operation.OperationHelper.withConnectionSource(OperationHelper.java:195) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.java:168) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.operation.AggregateOperation.execute(AggregateOperation.java:196) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.operation.AggregateOperation.execute(AggregateOperation.java:62) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.Mongo.execute(Mongo.java:736) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.Mongo$2.execute(Mongo.java:723) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.OperationIterable.iterator(OperationIterable.java:47) ~[mongo-java-driver-3.0.0.jar:na]
	at com.mongodb.AggregateIterableImpl.iterator(AggregateIterableImpl.java:92) ~[mongo-java-driver-3.0.0.jar:na]



 Comments   
Comment by Ross Lawley [ 08/Feb/19 ]

PR: https://github.com/rozza/mongo-java-driver/pull/317

Comment by Jochen Kemnade [ 02/Oct/15 ]

Thanks. What you mention as 1. and 3. are exactly my points.
If I am not ready to use Document everywhere, that quickly leads to issues where different implementations mix, especially when third-party libraries come into play. Bson arguments in the method signatures suggest (at least to me) that I can pass arbitrarily mixed instances to those methods. And the classes don't throw when I construct objects like that, only when the driver tries to encode them (as you can see, my suggested patch only changes the codec class).
And 3. mostly caused issues for me, for example if a method takes a query (as Bson), extends it with more filter criteria using an $and filter, and delegates to a MongoCollection.

Comment by Jeffrey Yemin [ 01/Oct/15 ]

I have a somewhat different view of the Bson interface. The reason it was added was to give users the flexibility to pass instances of different Bson-implementing classes to the various methods in MongoCollection and MongoDatabase. The use cases we had in mind were:

  1. I'm porting from the DB/DBCollection API to MongoDatabase/MongoCollection, but need to continue using DBObject/QueryBuilder and am not ready to use Document everywhere.
  2. I really want strong typing for my documents, so I want to use BsonDocument
  3. I want to use some sort of abstract builder to generate query filters/etc and not have to know the concrete type that is being used

But we did not mean to require that different implementation of Bson must interoperate. For example, the BsonDocument class can only contain values of type BsonValue, but not other Bson types.

That said, we still could decide to allow arbitrary Bson values inside Document. So I'm going to re-open this issue so we can consider it further.

Comment by Jochen Kemnade [ 01/Oct/15 ]

What about something like this?

Comment by Jochen Kemnade [ 01/Oct/15 ]

To be honest, I find this quite hard to accept. I think this goes against the whole point of the Bson interface. I think it is there to give the users the freedom to use different implementations (like Filters, BasicDBObject, and Document). If those implementations cannot be used together, it is nearly impossible to base any code on the Bson interface, because code written by different people could use different incompatible implementations.

Comment by Jeffrey Yemin [ 01/Oct/15 ]

Hi Jochen,

This ticket was closed as Works As Designed, so I wouldn't expect either of those scripts to work with 3.1. The 3.1 release only offers an alternative: use the new Aggregates static factory methods to construct the pipeline, e.g.

        collection.aggregate(Arrays.asList(
                Aggregates.match(Filters.and(Filters.eq("author", "Dave"),
                                              Filters.eq("someOtherField", "value"))),
                Aggregates.sort(Sorts.descending("age"))))

Please see the reference documentation for more examples.

Comment by Jochen Kemnade [ 01/Oct/15 ]

flozano, 3.1 changes things for you? I just tried both scripts with 3.1.0-rc0 and they still break.

Comment by Jochen Kemnade [ 15/Sep/15 ]

We've almost completely stopped using the Filters class because it causes those errors.

Comment by Francisco Alejandro Lozano López [ 15/Sep/15 ]

It is - here we're using 3.1-SNAPSHOT because of it...

Comment by Jochen Kemnade [ 15/Sep/15 ]

3.0.4 is still affected.

Comment by Jochen Kemnade [ 09/Jul/15 ]

This groovy script reproduces the issue.

Comment by Jeffrey Yemin [ 09/Jul/15 ]

jkemnade can you post your application code that is calling the count method where this exception is thrown?

Comment by Jochen Kemnade [ 09/Jul/15 ]

A similar thing also happens when combining Document and Filters with com.mongodb.client.MongoCollection.count(Bson).

org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class com.mongodb.client.model.Filters$SimpleEncodingFilter.
	at org.bson.codecs.configuration.CodecCache.getOrThrow(CodecCache.java:46)
	at org.bson.codecs.configuration.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:63)
	at org.bson.codecs.configuration.ChildCodecRegistry.get(ChildCodecRegistry.java:51)
	at org.bson.codecs.DocumentCodec.writeValue(DocumentCodec.java:174)
	at org.bson.codecs.DocumentCodec.writeIterable(DocumentCodec.java:197)
	at org.bson.codecs.DocumentCodec.writeValue(DocumentCodec.java:170)
	at org.bson.codecs.DocumentCodec.writeMap(DocumentCodec.java:189)
	at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:131)
	at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:45)
	at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:63)
	at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:29)
	at org.bson.codecs.EncoderContext.encodeWithChildContext(EncoderContext.java:91)
	at org.bson.codecs.BsonDocumentCodec.writeValue(BsonDocumentCodec.java:133)
	at org.bson.codecs.BsonDocumentCodec.encode(BsonDocumentCodec.java:112)
	at org.bson.codecs.BsonDocumentCodec.encode(BsonDocumentCodec.java:40)
	at com.mongodb.connection.RequestMessage.addDocument(RequestMessage.java:216)
	at com.mongodb.connection.RequestMessage.addDocument(RequestMessage.java:168)
	at com.mongodb.connection.CommandMessage.encodeMessageBody(CommandMessage.java:69)
	at com.mongodb.connection.RequestMessage.encode(RequestMessage.java:132)
	at com.mongodb.connection.CommandProtocol.sendMessage(CommandProtocol.java:119)
	at com.mongodb.connection.CommandProtocol.execute(CommandProtocol.java:84)
	at com.mongodb.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:155)
	at com.mongodb.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:219)
	at com.mongodb.connection.DefaultServerConnection.command(DefaultServerConnection.java:146)
	at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:182)
	at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:173)
	at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:128)
	at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:118)
	at com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol(CommandOperationHelper.java:69)
	at com.mongodb.operation.CountOperation.execute(CountOperation.java:172)
	at com.mongodb.operation.CountOperation.execute(CountOperation.java:43)
	at com.mongodb.Mongo.execute(Mongo.java:738)
	at com.mongodb.Mongo$2.execute(Mongo.java:725)
	at com.mongodb.MongoCollectionImpl.count(MongoCollectionImpl.java:167)
	at com.mongodb.MongoCollectionImpl.count(MongoCollectionImpl.java:152)

Comment by Jeffrey Yemin [ 11/May/15 ]

There's no good place where a better error message could be inserted, so I think we're going to have to live with this. Note that the Aggregates class is available in 3.1-SNAPSHOT now.

Comment by Jochen Kemnade [ 15/Apr/15 ]

Thanks for your help. Could the error message be improved until then to help users understand that they should not (yet) combine Filters and Documents?

Comment by Jeffrey Yemin [ 15/Apr/15 ]

The current plan for aggregate pipeline builders would have it look something like this:

  collection.aggregate([Aggregates.match(Filters.eq('name', 'foo')))]).into([])

or with static imports in place, just:

  collection.aggregate([match(eq('name', 'foo')))]).into([])

We should have this available in a 3.1 SNAPSHOT in a couple of weeks. Until then, apologies for the inconvenience, and please follow ross@10gen.com's advice above.

Comment by Ross Lawley [ 15/Apr/15 ]

Currently mixing Filters inside Documents is not supported, without adding a custom codecs. We are writing static helpers for aggregation for 3.1 (JAVA-1540)

In the meantime it may be easier to use just documents or parse Json:

collection.aggregate([new Document('$match', new Document('name', 'foo'))]).into([])
 
// or
collection.aggregate([Document.parse("{$match: {name: 'foo'}}")]).into([])

Comment by Jochen Kemnade [ 15/Apr/15 ]

I attached a Groovy script to reproduce the problem.

Comment by Jochen Kemnade [ 15/Apr/15 ]

I guess the problem is caused by combining org.bson.Document and com.mongodb.client.model.Filters.

collection.aggregate([new Document('$match', Filters.eq('name', 'foo'))]).into([])

leads to

org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class com.mongodb.client.model.Filters$SimpleEncodingFilter.
	at org.bson.codecs.configuration.CodecCache.getOrThrow(CodecCache.java:46)
	at org.bson.codecs.configuration.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:63)
	at org.bson.codecs.configuration.ChildCodecRegistry.get(ChildCodecRegistry.java:51)
	at org.bson.codecs.DocumentCodec.writeValue(DocumentCodec.java:174)
	at org.bson.codecs.DocumentCodec.writeMap(DocumentCodec.java:189)
	at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:131)
	at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:45)
	at org.bson.BsonDocumentWrapper.getUnwrapped(BsonDocumentWrapper.java:189)
	at org.bson.BsonDocumentWrapper.get(BsonDocumentWrapper.java:129)
	at com.mongodb.AggregateIterableImpl.execute(AggregateIterableImpl.java:118)
	at com.mongodb.AggregateIterableImpl.into(AggregateIterableImpl.java:112)
	at com.mongodb.client.MongoIterable$into.call(Unknown Source)

Comment by Ross Lawley [ 15/Apr/15 ]

Can you post an example of your aggregation pipeline code?

Generated at Thu Feb 08 08:55:26 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.