I have a multi module project (gradle) with following structure:
Root project 'mp-search'
--- Project ':analyzer'
--- Project ':common'
| \--- Project ':common:es-model'
...
Description:
:analyzer
: contains a spring boot application- Contains @SpringBootApplication and all other needed dependencies (Web, Feign, etc.)
:common:es-model
: contains models repositories for Spring Data Elasticsearch- Contains only the "spring-boot-starter-data-elasticsearch" dependency (no @SpringBootApplication)
Say I have the following classes in :common:es-model
with package com.example.esmodel.document.model
:
package com.example.esmodel.document.model;
//imports
@org.springframework.data.elasticsearch.annotations.Document(indexName = "document")
public class Document {
@Id
private String documentId;
@Field
private String content;
// Getter Setter Constructor
}
package com.example.esmodel.document.repository;
// imports
@Repository
public interface DocumentRepository extends ElasticsearchRepository<Document, String> {
}
Furthermore I created a configuration class with @ComponentScan
to find them
package com.example.esmodel.document.configuration;
// Imports
@Configuration
@ComponentScan(basePackages = "com.example.esmodel.document")
public class DocumentConfiguration {
}
And an custom annotation for simple inclusion in the application which imports the configuration:
package com.example.esmodel.document;
//Imports
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(DocumentConfiguration.class)
public @interface EnableDocumentModel {
}
I want to use the DocumentRepository
in a controller in my application project (:analyzer
). So I want to include it via the EnableDocumentModel
annotation like this:
package com.example.analyzer;
import com.example.esmodel.document.EnableDocumentModel;
// Other imports
@SpringBootApplication
@EnableFeignClients
@EnableDocumentModel // [1]
//@Import(DocumentConfiguration.class) // [2]
//@ComponentScan(basePackages = "com.example.esmodel.document") // [3]
public class AnalyzerApplication {
public static void main(String[] args) {
SpringApplication.run(AnalyzerApplication.class, args);
}
}
Of these three tests [1] and [2] are not working. The classes (EnableDocumentModel
, DocumentConfiguration
) are found and application tries to start, but fails with a UnsatisfiedDependencyException
:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.example.analyzer.controller.DocumentController required a bean of type 'com.example.esmodel.document.repository.DocumentRepository' that could not be found.
But test [3], using the same @ComponentScan(basePackages = "com.example.esmodel.document")
from DocumentConfiguration
in the AnalyzerApplication
, works fine. But this is not what I desire.
Do I miss something? Any ideas?
Thanks in advance!
Edit:
Just to make sure the DocumentConfiguration
is considered by spring at all, I added @Import(DocumentRepository.class)
in DocumentConfiguration
, but it throws an BeanInstantiationException
because it's an interface (which is of course reasonable).
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.example.esmodel.document.repository.DocumentRepository]: Specified class is an interface
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:70) ~[spring-beans-5.3.19.jar:5.3.19]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1326) ~[spring-beans-5.3.19.jar:5.3.19]
... 31 common frames omitted
So Spring definitely considers DocumentConfiguration
otherwise the exception wouldn't be thrown. So somehow the configuration is considered, but @ComponentScan(basePackages = "de.sva.medpower.esmodel.document")
doesn't do its job...
I also found a tutorial on medium (https://medium.com/trendyol-tech/how-to-write-a-spring-boot-library-project-7064e831b63b) doing it that way, but somehow it doesn't work for me..
CodePudding user response:
@ComponentScan
does not trigger Spring Data repository initialization. You'd need an @EnableElasticsearchRepositories
somewhere in your configuration (ideally on a class in the package that you'd want to scan for ES repositories).
This is even activated automatically if Boot finds Spring Data Elasticsearch on the execution classpath, but in your case doesn't show any effect as the application's root package is com.example.analyzer
(the package that your @SprignBootApplication
class resides in).
Annotating DocumentConfiguration
with @EnableElasticsearchRepositories
and point that to the packages that the ES repositories reside in should fix the issue.