[JAVA-4495] Cannot search with a custom codec registry Created: 15/Feb/22  Updated: 27/Oct/23  Resolved: 10/Oct/22

Status: Closed
Project: Java Driver
Component/s: Codecs
Affects Version/s: 4.5.0
Fix Version/s: None

Type: Bug Priority: Minor - P4
Reporter: Boris Petrov Assignee: Unassigned
Resolution: Works as Designed Votes: 0
Labels: external-user, regression
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Summary

Using a custom codec registry when searching leads to a stack-overflow exception.

Please provide the version of the driver. If applicable, please provide the MongoDB server version and topology (standalone, replica set, or sharded cluster).

This happens only with driver 4.5.0. Driver 4.4.2 works fine.

How to Reproduce

`build.gradle`:

plugins {
	id 'application'
}
repositories {
	mavenCentral()
}
dependencies {
	implementation 'org.mongodb:mongodb-driver-reactivestreams:4.5.0'
}
application {
	mainClass = 'company.Test'
}

`src/main/java/company/Test.java`:

package company;
 
import com.mongodb.client.model.Filters;
import com.mongodb.client.result.InsertOneResult;
import com.mongodb.reactivestreams.client.MongoClients;
 
import org.bson.Document;
import org.bson.codecs.Codec;
import org.bson.codecs.configuration.CodecRegistry;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
 
public class Test {
	public static class CustomCodecRegistry implements CodecRegistry {
		private final CodecRegistry codecRegistry;
 
		public CustomCodecRegistry(CodecRegistry codecRegistry) {
			this.codecRegistry = codecRegistry;
		}
 
		@Override
		public <T> Codec<T> get(Class<T> clazz) {
			return get(clazz, codecRegistry);
		}
 
		@Override
		public <T> Codec<T> get(Class<T> clazz, CodecRegistry registry) {
			return registry.get(clazz);
		}
	}
 
	public static void main(String[] args) throws InterruptedException {
		var client = MongoClients.create();
 
		var collection = client.getDatabase("test").getCollection("collection");
 
		collection.insertOne(new Document("bad", "42")).subscribe(new Subscriber<>() {
			@Override
			public void onSubscribe(Subscription s) {
				s.request(1);
			}
 
			@Override
			public void onNext(final InsertOneResult success) {
			}
 
			@Override
			public void onError(Throwable t) {
				t.printStackTrace();
			}
 
			@Override
			public void onComplete() {
				collection
					.withCodecRegistry(new CustomCodecRegistry(collection.getCodecRegistry()))
					.find(Filters.eq("bad", "42"))
					.subscribe(new Subscriber<>() {
						@Override
						public void onSubscribe(Subscription s) {
							s.request(1);
						}
 
						@Override
						public void onNext(Document t) {
							System.err.println(t);
						}
 
						@Override
						public void onError(Throwable t) {
							t.printStackTrace();
						}
 
						@Override
						public void onComplete() {
						}
				});
			}
		});
 
		Thread.sleep(5000);
	}
}

 Run `gradle run` on this and you'll see the error. Commenting-out the `.withCodecRegistry(new CustomCodecRegistry(collection.getCodecRegistry()))` line or changing the driver's version to `4.4.2` in `build.gradle` fixes the issue.



 Comments   
Comment by Jeffrey Yemin [ 10/Oct/22 ]

Took another look at this, and it just looks like the custom registry is not written correctly. If it's changed to:

    public static class CustomCodecRegistry implements CodecRegistry {
        private final CodecRegistry codecRegistry;
 
        public CustomCodecRegistry(CodecRegistry codecRegistry) {
            this.codecRegistry = codecRegistry;
        }
 
        @Override
        public <T> Codec<T> get(Class<T> clazz) {
            return codecRegistry.get(clazz);
        }
 
        @Override
        public <T> Codec<T> get(Class<T> clazz, CodecRegistry registry) {
            return codecRegistry.get(clazz, registry);
        }
    }

then it works as expected.

Closing as Works as Designed.

Comment by Boris Petrov [ 15/Feb/22 ]

Thanks, that indeed does solve the issue (and makes my code simpler)! Of course, the original problem still remains.

Comment by Jeffrey Yemin [ 15/Feb/22 ]

Ah, ok. No worries. Try something like this:

CodecRegistries.fromRegistries(
                        CodecRegistries.fromCodecs(new CustomCodec()),
                        collection.getCodecRegistry())

Comment by Boris Petrov [ 15/Feb/22 ]

@Jeffrey Yemin - well, for one, I didn't know about these builders. What I want is to get an instance of `MongoCollection` from the original `MongoCollection` (which already has a custom codec-provider) and add another codec to be checked for first. Is there a simpler way of doing that?

Comment by Jeffrey Yemin [ 15/Feb/22 ]

alien what is your use case for implementing a custom CodecRegistry interface, as opposed to using the builders in CodecRegistries? If we understood that, we might be able to offer a workaround while we continue our analysis.

Comment by Jeffrey Yemin [ 15/Feb/22 ]

Thanks for the report. Here's a slightly simpler repro, using the sync driver:

import com.mongodb.client.MongoClients;
import org.bson.Document;
import org.bson.codecs.Codec;
import org.bson.codecs.configuration.CodecRegistry;
 
public class JAVA4495 {
    public static class CustomCodecRegistry implements CodecRegistry {
        private final CodecRegistry codecRegistry;
 
        public CustomCodecRegistry(CodecRegistry codecRegistry) {
            this.codecRegistry = codecRegistry;
        }
 
        @Override
        public <T> Codec<T> get(Class<T> clazz) {
            return get(clazz, codecRegistry);
        }
 
        @Override
        public <T> Codec<T> get(Class<T> clazz, CodecRegistry registry) {
            return registry.get(clazz);
        }
    }
 
    public static void main(String[] args) throws InterruptedException {
        var client = MongoClients.create();
 
        var collection = client.getDatabase("test").getCollection("JAVA4495");
 
        collection.withCodecRegistry(new CustomCodecRegistry(collection.getCodecRegistry()))
                .insertOne(new Document());
    }
}

This is almost certainly a regression introduced by the fix to JAVA-4461. We will look into it.

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