I'm working through the book Learning Spring Boot 2.0, Second Edition
but using Spring Boot 2.5.6
so I suspect my issue might be related to me having to do things slightly with the different version.
I have this class:
@Component
public class InitDatabase {
@Bean
CommandLineRunner init(MongoOperations operations) {
return args -> {
operations.dropCollection(Image.class);
operations.insert(new Image("1", "learning-spring-boot-cover.jpg"));
operations.insert(new Image("2", "learning-spring-boot-2nd-edition-cover.jpg"));
operations.insert(new Image("3", "bazinga.png"));
operations.findAll(Image.class).forEach(image -> System.out.println(image.toString()));
};
}
}
When I run my application I get this error:
2021-11-25 12:26:42.870 DEBUG 71010 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter : Application failed to start due to an exception
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.data.mongodb.core.MongoOperations' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1790) ~[spring-beans-5.3.12.jar:5.3.12] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1346) ~[spring-beans-5.3.12.jar:5.3.12] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300) ~[spring-beans-5.3.12.jar:5.3.12] at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887) ~[spring-beans-5.3.12.jar:5.3.12] at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) ~[spring-beans-5.3.12.jar:5.3.12] at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:541) ~[spring-beans-5.3.12.jar:5.3.12] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352) ~[spring-beans-5.3.12.jar:5.3.12] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195) ~[spring-beans-5.3.12.jar:5.3.12] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.12.jar:5.3.12] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.12.jar:5.3.12] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.12.jar:5.3.12] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.12.jar:5.3.12] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.12.jar:5.3.12] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.12.jar:5.3.12] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.12.jar:5.3.12] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.12.jar:5.3.12] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.12.jar:5.3.12] at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:64) ~[spring-boot-2.5.6.jar:2.5.6] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-2.5.6.jar:2.5.6] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434) ~[spring-boot-2.5.6.jar:2.5.6] at org.springframework.boot.SpringApplication.run(SpringApplication.java:338) ~[spring-boot-2.5.6.jar:2.5.6] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-2.5.6.jar:2.5.6] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332) ~[spring-boot-2.5.6.jar:2.5.6] at com.paulcarron.learningspringboot.learningspringboot.LearningSpringBootApplication.main(LearningSpringBootApplication.java:12) ~[classes/:na]
2021-11-25 12:26:42.870 ERROR 71010 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
APPLICATION FAILED TO START
Description:
Parameter 0 of method init in com.paulcarron.learningspringboot.learningspringboot.InitDatabase required a bean of type 'org.springframework.data.mongodb.core.MongoOperations' that could not be found.
Action:
Consider defining a bean of type 'org.springframework.data.mongodb.core.MongoOperations' in your configuration.
This is my build.gradle
:
plugins {
id 'org.springframework.boot' version '2.5.6'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.paulcarron.learningspringboot'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-webflux'
implementation 'org.synchronoss.cloud:nio-multipart-parser:1.1.0'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'de.flapdoodle.embed:de.flapdoodle.embed.mongo'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.projectreactor:reactor-test'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'javax.persistence:javax.persistence-api:2.2'
}
test {
useJUnitPlatform()
}
My understanding is that I don't need to activate the with @EnableReactiveMongoRepositories
as this is done automatically if Reactive MongoDB or Spring DataMongoDB 2.0 are on the classpath.
Is there any obvious reason why this is not working?
CodePudding user response:
I guess you're trying to init your database on the startup.
You can leverage the spring internal event mechanism.
When your application is ready, spring triggers the event ApplicationReadyEvent
You can listen to this event and init your collection:
@Component
public class DataInit implements ApplicationListener<ApplicationReadyEvent> {
private final MongoOperations operations;
public DataInit(MongoOperations operations) {
this.operations = operations;
}
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
// init data
}
}
If you want to know more about spring events --> https://www.baeldung.com/spring-events
CodePudding user response:
MongoOperations
is the interface for interacting with Mongo in a blocking manner. ReactiveMongoOperations
is the interface for interacting with Mongo in a reactive manner.
As you're using WebFlux (spring-boot-starter-webflux
), it would appear that you want to build a reactive application. If so, you should replace your use of MongoOperations
with ReactiveMongoOperations
. The, if you want to build a blocking, Servlet-based web application would be to switch to spring-boot-starter-data-mongodb
and spring-boot-starter-web
.
CodePudding user response:
I want to preload data and read that it was best to do this using a blocking API because when launching an application there is a risk of a thread lock issue when both the web container and my loader are starting up. The book I'm using is for an older veriosn of both Spring Boot and MongoDB.
It seems that the version of spring-boot-starter-data-mongodb-reactive
that the book used contained MongoOperations
but this was then split out. See this.
To use this I added implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
to my class path.
If there wasn't the issue of thread lock I could have used ReactiveMongoOperations
instead.