Skip to content

Forced Sort Passing via sorts() Method When Building with MongoCursorItemReaderBuilder and Query #4860

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
apptie opened this issue Jun 4, 2025 · 0 comments · May be fixed by #4861
Open
Labels
status: waiting-for-triage Issues that we did not analyse yet type: bug

Comments

@apptie
Copy link

apptie commented Jun 4, 2025

Bug description
When building a MongoCursorItemReader using MongoCursorItemReaderBuilder with a Query object, the jsonQuery is null in MongoCursorItemReader.doOpen(), so it uses the passed Query.

In this case, MongoCursorItemReader.createQuery() is not called, which means the values specified in MongoCursorItemReaderBuilder.sorts() are ignored.

I confirmed that the Sort passed to the Builder is ignored through the following simple example code.

@Bean
public Job reportJob() {
    return new JobBuilder("reportJob", jobRepository)
            .start(reportStep())
            .build();
}

@Bean
public Step reportStep() {
    return new StepBuilder("reportStep", jobRepository)
            .<ReportData, ReportData>chunk(10, transactionManager)
            .reader(reportReader())
            .writer(reportWriter())
            .build();
}

@Bean
public MongoCursorItemReader<ReportData> reportReader() {
    Query query = new Query()
            .with(Sort.by(Sort.Direction.ASC, "timestamp"))
            .cursorBatchSize(10);

    return new MongoCursorItemReaderBuilder<ReportData>()
            .name("reportReader")
            .template(mongoTemplate)
            .collection("reportData")
            .query(query)
            .sorts(Map.of("timestamp", Sort.Direction.DESC)) // ignored 
            .targetType(ReportData.class)
            .build();
}

@Bean
public ItemWriter<ReportData> reportWriter() {
    return items -> items.forEach(data -> log.info("[result] : {}", data));
}

If sorts are not passed in MongoCursorItemReaderBuilder.sorts():

@Bean
public MongoCursorItemReader<ReportData> reportReader() {
    Query query = new Query()
            .with(Sort.by(Sort.Direction.ASC, "timestamp"))
            .cursorBatchSize(10);

    return new MongoCursorItemReaderBuilder<ReportData>()
            .name("reportReader")
            .template(mongoTemplate)
            .collection("reportData")
            .query(query)
            .targetType(ReportData.class)
            .build();
}

the following exception occurs:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'reportJob' defined in class path resource [com/example/batch/demo/ReportJobConfig.class]: Failed to instantiate [org.springframework.batch.core.Job]: Factory method 'reportJob' threw exception with message: Error creating bean with name 'reportStep' defined in class path resource [com/example/batch/demo/ReportJobConfig.class]: Failed to instantiate [org.springframework.batch.core.Step]: Factory method 'reportStep' threw exception with message: Error creating bean with name 'reportReader' defined in class path resource [com/example/batch/demo/ReportJobConfig.class]: Failed to instantiate [org.springframework.batch.item.data.MongoCursorItemReader]: Factory method 'reportReader' threw exception with message: sorts map is required.
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:657) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:489) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1375) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1205) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:569) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:529) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:339) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:373) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.instantiateSingleton(DefaultListableBeanFactory.java:1222) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingleton(DefaultListableBeanFactory.java:1188) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:1123) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:987) ~[spring-context-6.2.7.jar:6.2.7]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:627) ~[spring-context-6.2.7.jar:6.2.7]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:753) ~[spring-boot-3.5.0.jar:3.5.0]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439) ~[spring-boot-3.5.0.jar:3.5.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:318) ~[spring-boot-3.5.0.jar:3.5.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1362) ~[spring-boot-3.5.0.jar:3.5.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1351) ~[spring-boot-3.5.0.jar:3.5.0]
at com.example.batch.demo.DemoApplication.main(DemoApplication.java:10) ~[main/:na]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.batch.core.Job]: Factory method 'reportJob' threw exception with message: Error creating bean with name 'reportStep' defined in class path resource [com/example/batch/demo/ReportJobConfig.class]: Failed to instantiate [org.springframework.batch.core.Step]: Factory method 'reportStep' threw exception with message: Error creating bean with name 'reportReader' defined in class path resource [com/example/batch/demo/ReportJobConfig.class]: Failed to instantiate [org.springframework.batch.item.data.MongoCursorItemReader]: Factory method 'reportReader' threw exception with message: sorts map is required.
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:199) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiateWithFactoryMethod(SimpleInstantiationStrategy.java:88) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:168) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-6.2.7.jar:6.2.7]
... 20 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'reportStep' defined in class path resource [com/example/batch/demo/ReportJobConfig.class]: Failed to instantiate [org.springframework.batch.core.Step]: Factory method 'reportStep' threw exception with message: Error creating bean with name 'reportReader' defined in class path resource [com/example/batch/demo/ReportJobConfig.class]: Failed to instantiate [org.springframework.batch.item.data.MongoCursorItemReader]: Factory method 'reportReader' threw exception with message: sorts map is required.
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:657) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:489) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1375) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1205) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:569) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:529) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:339) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:373) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.resolveBeanReference(ConfigurationClassEnhancer.java:425) ~[spring-context-6.2.7.jar:6.2.7]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:396) ~[spring-context-6.2.7.jar:6.2.7]
at com.example.batch.demo.ReportJobConfig$$SpringCGLIB$$0.reportStep() ~[main/:na]
at com.example.batch.demo.ReportJobConfig.reportJob(ReportJobConfig.java:33) ~[main/:na]
at com.example.batch.demo.ReportJobConfig$$SpringCGLIB$$0.CGLIB$reportJob$0() ~[main/:na]
at com.example.batch.demo.ReportJobConfig$$SpringCGLIB$$FastClass$$1.invoke() ~[main/:na]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) ~[spring-core-6.2.7.jar:6.2.7]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:393) ~[spring-context-6.2.7.jar:6.2.7]
at com.example.batch.demo.ReportJobConfig$$SpringCGLIB$$0.reportJob() ~[main/:na]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:171) ~[spring-beans-6.2.7.jar:6.2.7]
... 23 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.batch.core.Step]: Factory method 'reportStep' threw exception with message: Error creating bean with name 'reportReader' defined in class path resource [com/example/batch/demo/ReportJobConfig.class]: Failed to instantiate [org.springframework.batch.item.data.MongoCursorItemReader]: Factory method 'reportReader' threw exception with message: sorts map is required.
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:199) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiateWithFactoryMethod(SimpleInstantiationStrategy.java:88) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:168) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-6.2.7.jar:6.2.7]
... 44 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'reportReader' defined in class path resource [com/example/batch/demo/ReportJobConfig.class]: Failed to instantiate [org.springframework.batch.item.data.MongoCursorItemReader]: Factory method 'reportReader' threw exception with message: sorts map is required.
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:657) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:489) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1375) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1205) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:569) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:529) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:339) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:373) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.resolveBeanReference(ConfigurationClassEnhancer.java:425) ~[spring-context-6.2.7.jar:6.2.7]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:396) ~[spring-context-6.2.7.jar:6.2.7]
at com.example.batch.demo.ReportJobConfig$$SpringCGLIB$$0.reportReader() ~[main/:na]
at com.example.batch.demo.ReportJobConfig.reportStep(ReportJobConfig.java:41) ~[main/:na]
at com.example.batch.demo.ReportJobConfig$$SpringCGLIB$$0.CGLIB$reportStep$1() ~[main/:na]
at com.example.batch.demo.ReportJobConfig$$SpringCGLIB$$FastClass$$1.invoke() ~[main/:na]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) ~[spring-core-6.2.7.jar:6.2.7]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:393) ~[spring-context-6.2.7.jar:6.2.7]
at com.example.batch.demo.ReportJobConfig$$SpringCGLIB$$0.reportStep() ~[main/:na]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:171) ~[spring-beans-6.2.7.jar:6.2.7]
... 47 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.batch.item.data.MongoCursorItemReader]: Factory method 'reportReader' threw exception with message: sorts map is required.
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:199) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiateWithFactoryMethod(SimpleInstantiationStrategy.java:88) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:168) ~[spring-beans-6.2.7.jar:6.2.7]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:653) ~[spring-beans-6.2.7.jar:6.2.7]
... 68 common frames omitted
Caused by: java.lang.IllegalArgumentException: sorts map is required.
at org.springframework.util.Assert.notNull(Assert.java:181) ~[spring-core-6.2.7.jar:6.2.7]
at org.springframework.batch.item.data.builder.MongoCursorItemReaderBuilder.build(MongoCursorItemReaderBuilder.java:284) ~[spring-batch-infrastructure-5.2.2.jar:5.2.2]
at com.example.batch.demo.ReportJobConfig.reportReader(ReportJobConfig.java:60) ~[main/:na]
at com.example.batch.demo.ReportJobConfig$$SpringCGLIB$$0.CGLIB$reportReader$2() ~[main/:na]
at com.example.batch.demo.ReportJobConfig$$SpringCGLIB$$FastClass$$1.invoke() ~[main/:na]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258) ~[spring-core-6.2.7.jar:6.2.7]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:393) ~[spring-context-6.2.7.jar:6.2.7]
at com.example.batch.demo.ReportJobConfig$$SpringCGLIB$$0.reportReader() ~[main/:na]
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.lambda$instantiate$0(SimpleInstantiationStrategy.java:171) ~[spring-beans-6.2.7.jar:6.2.7]
... 71 common frames omitted

As I understand it, since jsonQuery cannot specify sorting conditions, I think the sorts value only needs to be validated when building through jsonQuery.

Environment
Spring Batch 5.2.2
Spring Boot 3.5.0
Amazon Correto 21.0.3

@apptie apptie added status: waiting-for-triage Issues that we did not analyse yet type: bug labels Jun 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: waiting-for-triage Issues that we did not analyse yet type: bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant