No qualifying bean of type [java.lang.Class] found for dependency [java.lang.Class<org.springframework.data.repository.Repository<?, ?>>] - spring

I have started working with Spring framework. Here I am working with Spring Data - Cassandra Repository modular application. I could able to test a spring-data-cassandra application individually, whereas when I try to use as a moudle in a project and scan the packages of components from other module like...
<context:component-scan base-package="example.dao,example.domain" />
I am getting an error
No qualifying bean of type [example.domain.EventRepository] found for dependency [example.domain.EventRepository]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
I can share you the code, if required.
The way I have done for another modules works fine.
I am not getting where is the problem.
Please find the code below for DAO CLASS.
#Service
#Transactional
public class EventDao {
#Autowired
private EventRepository eventRepository;
/*public EventDao(EventRepository eventRepository) {
this.eventRepository = eventRepository;
}*/
private final static Logger logger = LoggerFactory.getLogger(EventDao.class);
public Event saveMember(Event member) {
eventRepository.save(member);
return member;
}
}
My Repository interface.
package example.domain;
import org.springframework.data.cassandra.repository.CassandraRepository;
import org.springframework.data.cassandra.repository.Query;
public interface EventRepository extends CassandraRepository<Event> {
#Query("select * from event where type = ?0 and bucket=?1")
Iterable<Event> findByTypeAndBucket(String type, String bucket);
}
My Cassandra configuration class.
package example;
#Configuration
#PropertySource(value = { "classpath:cassandra.properties" })
#EnableCassandraRepositories(basePackages = { "example" })
public class CassandraConfiguration extends AbstractCassandraConfiguration {
private static final Logger LOG = LoggerFactory.getLogger(CassandraConfiguration.class);
#Autowired
private Environment environment;
#Bean
public CassandraClusterFactoryBean cluster() {
CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
cluster.setContactPoints(environment.getProperty("cassandra.contactpoints"));
cluster.setPort(Integer.parseInt(environment.getProperty("cassandra.port")));
return cluster;
}
#Override
protected String getKeyspaceName() {
return environment.getProperty("cassandra.keyspace");
}
#Bean
public CassandraMappingContext cassandraMapping() throws ClassNotFoundException {
return new BasicCassandraMappingContext();
}
}
UPDATE
I could able to create individual spring-data-cassandra and spring-data-neo4j modules seperately with other service modules and its working fine in both the modules.
But I have another module with Neo4j spring-data-neo4j module in the same project, when I try to run both(neo4j+cassandra) the modules under the same project its creating the problem.
still waiting for the help! I have tried my best!
Thanks!

Related

Spring boot get #value within a class extending a dependency

Folks, am trying to access config properties from within a class that I've extended from a dependency. Apparently the config class is returning a null pointer in my implementation class (CustomUtil).
pom.xml
...
<dependency>
<groupId>com.utilapp</groupId> //3rd party library that I need to use
<artifactId>util-lib</artifactId>
</dependency>
...
The BaseUtil is from the dependency. CustomUtil is a bean in my SpringBoot App & am overriding the method as below to check the key from the config property ignoreKeyList .
package com.myapp
...
#Component
public class CustomUtil extends BaseUtil {
#Autowired
private ClientConfig clientConfig; // This returns null!
#Override
protected boolean shouldExcludeFromList(String key) {
return this.clientConfig.getIgnoreKeyList.contains(key); // their library/util excludes certain keywords from the content being formatted
}
}
Config class in my SpringBoot App.
package com.myapp
...
#Configuration
#Getter
#Setter
public class ClientConfig {
#Value("${myapp.ignorekeys}")
private List<String> ignoreKeyList;
...
...
}
Main class in my app.
package com.myapp
...
#SpringBootApplication
public class MyClientApplication {
public static void main(String[] args) {
SpringApplication.run(MyClientApplication.class, args);
}
}
Service implementation class in my SpringBoot App.
package com.myapp
import com.utilapp.formatters.FormatBuilder;
import com.utilapp.formatters.TextFormatter;
...
#Service
public class ServiceImpl implements MyService {
#Autowired
private ClientConfig clientConfig; // works here!
public String formatContent(String content) {
TextFormatter formatter = this.getTextFormatter();
return formatter.parseAndFormat(content);
}
private TextFormatter getTextFormatter() {
return FormatBuilder.custom() // FormatBuilder is from the dependency
.withApplication(this.clientConfig.getAppName()) // In their library, the BaseUtil gets instantiated which am extending in my CustomUtil bean
...
...
.withIndentSupport(Boolean.TRUE)
.build();
}
}
Controller in my app
package com.myapp
...
#RestController
#RequestMapping("/app/v1")
public class StyleController {
#Autowired
private MyService myService;
#GetMapping("/format")
public String formatContent(#RequestParam String content) {
return this.myService.formatContent(content);
}
}
When I debug ClientConfig, it loads the properties from the config file; application.properties in src\main\resources.
But for some reason the ClientConfig is returning null from within the CustomUtil bean. Not sure why!
I originally thought it was due to ordering of bean instantiation. I tried playing around with #Order, #DependsOn, #ComponentScan, #ScanBasePackages etc, but none yields.
Any pointers/guidance please.
Thanks.

Autoconfigure ReactiveCrudRepos in integration tests

I'm having some difficulty in writing some Integration tests. I have something like so
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Service.class)
public class ServiceTest {
#Rule
public PostgreSQLContainer postgres = new PostgreSQLContainer();
#Autowired
Service Service;
#Before
public void setUp() {
PostgresqlConnectionFactory connectionFactory = new PostgresqlConnectionFactory(PostgresqlConnectionConfiguration.builder()
.host(postgres.getHost())
.port(postgres.getFirstMappedPort()) // optional, defaults to 5432
.username(postgres.getUsername())
.password(postgres.getPassword())
.database(postgres.getDatabaseName()) // optional
.build());
Resource resource = new ClassPathResource("sql.sql");
Mono<PostgresqlConnection> mono = connectionFactory.create();
mono.map(connection -> connection
.createStatement(Helpers.asString(resource))
.execute()).block();
}
#Test
public void test() {
Request Request = new Request();
request.setName("name");
Mono<Item> itemMono = Service.createNewHub(hubRequest);
Item item = itemMono.block();
Assert.assertEquals(1L, 1L);
}
}
And my Service.class looks like the below
#Service
public class Service {
private Repository repository;
public Service(Repository repository) {
this.repository = repository;
}
public Flux<Item> getAllItems() {
return repository.findAll();
}
}
And my repo
#Repository
public interface Repository extends ReactiveCrudRepository<Item, Integer> {
}
My error is the following
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.Repository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
While all of the code I have written in the application is able to be injected fine, when it comes to the ReactiveCrudRepos, I am not having any luck on getting their instantiated object. What do I need to do to have the implementations created and injected?
As long as you use #SpringBootTest(classes = Service.class), the other beans are not loaded into the application context. The annotation element class of the annotation is described as:
The component classes to use for loading an ApplicationContext.
Remove the element and use the #SpringBootApplication as is:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Service.class)
public class ServiceTest { /* code */ }
Remember, using this way is testing an application context completely different from what will be run on the production environment. It should be a last resort.
Moreover, avoid naming the interface Repository when there exists the Spring annotation #Repository itself. I would personally prefer:
#Repository
public interface ItemRepository extends ReactiveCrudRepository<Item, Integer> {
}

SpringBoot: how to inject two classes having same name

In my application, I have two classes having the same name, but of course in different packages.
Both classes need to be injected in the application; Unfortunately, I get the following error message:
Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'myFeature' for bean class [org.pmesmeur.springboot.training.service.feature2.MyFeature] conflicts with existing, non-compatible bean definition of same name and class [org.pmesmeur.springboot.training.service.feature1.MyFeature]
My issue can be reproduced by the following sample:
#Component
#EnableConfigurationProperties(ServiceProperties.class)
public class MyService implements IService {
private final ServiceProperties serviceProperties;
private final IProvider provider;
private final org.pmesmeur.springboot.training.service.feature1.IMyFeature f1;
private final org.pmesmeur.springboot.training.service.feature2.IMyFeature f2;
#Autowired
public MyService(ServiceProperties serviceProperties,
IProvider provider,
org.pmesmeur.springboot.training.service.feature1.IMyFeature f1,
org.pmesmeur.springboot.training.service.feature2.IMyFeature f2) {
this.serviceProperties = serviceProperties;
this.provider = provider;
this.f1 = f1;
this.f2 = f2;
}
...
package org.pmesmeur.springboot.training.service.feature1;
public interface IMyFeature {
void print();
}
package org.pmesmeur.springboot.training.service.feature1;
import org.springframework.stereotype.Component;
#Component
public class MyFeature implements IMyFeature {
#Override
public void print() {
System.out.print("HelloWorld");
}
}
package org.pmesmeur.springboot.training.service.feature2;
public interface IMyFeature {
void print();
}
package org.pmesmeur.springboot.training.service.feature2;
import org.springframework.stereotype.Component;
#Component
public class MyFeature implements IMyFeature {
#Override
public void print() {
System.out.print("FooBar");
}
}
If I use different names for my classes MyFeature, my problem disappears!!!
I am used to work with Guice and this framework does not have this kind of problem/limitation
It seems that the spring dependencies injection framework uses only
the class-name instead of package-name + class-name in order to
select its classes.
In "real-life" I have this problem with a far-bigger project and I would strongly prefer not to have to rename my classes: can anyone help me?
One last point, I would prefer to avoid "tricks" such as using
#Qualifier(value = "ABC") when injecting my classes: in my sample,
there should be no ambiguity for finding the correct instance of
MyFeature as they do not implement the same interface
Simply re-implementing BeanNameGenerator adds a new problem for beans declared/instantiated by names
#Component("HelloWorld")
class MyComponent implements IComponent {
...
}
#Qualifier(value = "HelloWorld") IComponent component
I solved this issue by extending AnnotationBeanNameGenerator and redefining method buildDefaultBeanName()
static class BeanNameGeneratorIncludingPackageName extends AnnotationBeanNameGenerator {
public BeanNameGeneratorIncludingPackageName() {
}
#Override
public String buildDefaultBeanName(BeanDefinition beanDefinition, BeanDefinitionRegistry beanDefinitionRegistry) {
return beanDefinition.getBeanClassName();
}
}
You can assigna a value for each component e.g. #Component(value="someBean") and then inject it with #Qualifier e.g.
#Autowired
public SomeService(#Qualifier("someBean") Some s){
//....
}
Spring provides autowire by type and name. Your classname are same. By default spring considers only className not package. But you can override this behaviour by defining custom implementation of BeanNameGenerator interface in which you can generate name using both package and name. I am not providing code solution because i think you should explore more on this.
You can do something like this;
in package a
public class MyFeature implements IMyFeature {
#Override
public void print() {
System.out.print("FooBar");
}
}
in package b
public class MyFeature implements IMyFeature {
#Override
public void print() {
System.out.print("HelloWorld");
}
}
and in some config class;
#Configuration
public class Configuration {
#Bean
public a.MyFeature f1() {
return new a.MyFeature();
}
#Bean
public b.MyFeature f2() {
return new b.MyFeature();
}
}
Then you can autowire them with names f1 and f2, that are the names of their respective bean constructor methods.
You can do the similar thing with #Component("f1") &
#Component("f2")
Even though different interfaces are implemented and are in different packages, identical bean name causes this trouble, and you have to utilize some sort of custom naming to distinguish. Utilizing some custom Spring logic would be way too ugly compared to what you'd do with above solutions.

Transitive inclusion of #Configuration classes from a .xml-based spring config

Suppose we start with an xml-based config, say main.xml, that imports a java config FullConfig.java via:
<context:annotation-config/>
<bean class="test.FullConfig"/>
This java config has the form:
#Configuration
#Import(value = {IncludeConfig.class})
public class FullConfig {
#Autowired
#Qualifier(value = "tmpBean")
private DataClazz autowired;
#Bean
public DataClazz someOtherBean() {
System.out.println("Using autowired tmpBean:" + autowired);
return new DataClazz();
}
}
so it imports a further java config, which contains a definition of the tmpBean of DataClazz type,
#Configuration
public class IncludeConfig {
#Bean
public DataClazz tmpBean() {
return new DataClazz();
}
}
Now two questions:
Is this "transitive inclusion" guaranteed to work in spring (i.e. is someOtherBean() guaranteed not to thrown a NPE)?
IntelliJ up to version 2017.2 does mark #Qualifier(value = "tmpBean") red with a message "Cannot find bean with qualifier 'tmpBean'". Should that be considered a bug?
Note: I have checked that an application using ClassPathXmlApplicationContext("main.xml") does work correctly, i.e. no NPE is thrown (and all relevant beans are visible).
You need to return DataClazz:
#Bean
public DataClazz someOtherBean() {
System.out.println("Using autowired tmpBean:" + autowired);
return autowired;
}
Probably yes but try to test it.
IDEA-82844 (Bug)

Multiple Spring Configuration files (one per Profile)

I'm a Spring rookie and trying to benefit from the advantages of the easy 'profile' handling of Spring. I already worked through this tutorial: https://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-profile and now I'd like to adapt that concept to an easy example.
I've got two profiles: dev and prod. I imagine a #Configuration class for each profile where I can instantiate different beans (implementing a common interface respectively) depending on the set profile.
My currently used classes look like this:
StatusController.java
#RestController
#RequestMapping("/status")
public class StatusController {
private final EnvironmentAwareBean environmentBean;
#Autowired
public StatusController(EnvironmentAwareBean environmentBean) {
this.environmentBean = environmentBean;
}
#RequestMapping(method = RequestMethod.GET)
Status getStatus() {
Status status = new Status();
status.setExtra("environmentBean=" + environmentBean.getString());
return status;
}
}
EnvironmentAwareBean.java
public interface EnvironmentAwareBean {
String getString();
}
EnvironmentAwareBean.java
#Service
public class DevBean implements EnvironmentAwareBean {
#Override
public String getString() {
return "development";
}
}
EnvironmentAwareBean.java
#Service
public class ProdBean implements EnvironmentAwareBean {
#Override
public String getString() {
return "production";
}
}
DevConfig.java
#Configuration
#Profile("dev")
public class DevConfig {
#Bean
public EnvironmentAwareBean getDevBean() {
return new DevBean();
}
}
ProdConfig.java
#Configuration
#Profile("prod")
public class ProdConfig {
#Bean
public EnvironmentAwareBean getProdBean() {
return new ProdBean();
}
}
Running the example throws this exception during startup (SPRING_PROFILES_DEFAULT is set to dev):
(...) UnsatisfiedDependencyException: (...) nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [EnvironmentAwareBean] is defined: expected single matching bean but found 3: prodBean,devBean,getDevBean
Is my approach far from a recommended configuration? In my opinion it would make more sense to annotate each Configuration with the #Profile annotation instead of doing it for each and every bean and possibly forgetting some variants when new classes are added later on.
Your implementations of EnvironmentAwareBean are all annotated with #Service.
This means they will all be picked up by component scanning and hence you get more than one matching bean. Do they need to be annotated with #Service?
Annotating each #Configuration with the #Profile annotation is fine. Another way as an educational exercise would be to not use #Profile and instead annotate the #Bean or Config classes with your own implementation of #Conditional.

Resources