I'm a complete novice regarding Spring applications, and I'm trying to integrate a project using Kotlin + Spring + GORM (Which requires usage of Groovy). When I try to run it I get:
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'messageController': Unsatisfied dependency expressed through method 'setTargetDatastore' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException
I have just 5 files in the project, including the build.gradle.
Message.groovy
import grails.gorm.annotation.Entity
import groovy.transform.ToString
import org.grails.datastore.gorm.GormEntity
#ToString
#Entity
class Message implements GormEntity<Message> {
String user;
String date;
String message;
}
Message.service
import domain.Message
import groovy.transform.CompileStatic
import org.springframework.stereotype.Service
#CompileStatic
#grails.gorm.services.Service(Message)
#Service
interface MessageService {
List<Message> findAll()
}
MessageController.groovy
#RestController
#Transactional
class MessageController {
#Autowired
MessageService messageService
#RequestMapping("/")
List<String> index() {
return messageService.findAll().collect { "[" + it.user + "#" + it.date + ": " + it.message + "]" }
}
#RequestMapping(value = "/save/", method = RequestMethod.POST)
String save(#RequestBody Message message) {
message.save()
return "Saved"
}
}
App.kt
#SpringBootApplication
class SimManagerApplication
fun main(args: Array<String>) {
SpringApplication.run(SimManagerApplication::class.java, *args)
}
build.gradle dependencies
dependencies {
compile('org.springframework.boot:spring-boot-starter-quartz')
compile('org.springframework.boot:spring-boot-starter-web')
compile('com.fasterxml.jackson.module:jackson-module-kotlin')
compile('com.vaadin:vaadin-spring-boot-starter')
compile('org.flywaydb:flyway-core')
compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
compile("org.jetbrains.kotlin:kotlin-reflect")
compile("com.h2database:h2")
compile("eu.vaadinonkotlin:vok-rest:0.6.2")
compile('org.codehaus.groovy:groovy-all:2.5.4')
compile("org.flywaydb:flyway-core:5.2.0")
compile "org.grails:gorm-hibernate5-spring-boot:6.1.6.RELEASE"
compile "org.hibernate:hibernate-core:5.1.0.Final"
compile "org.hibernate:hibernate-ehcache:5.1.0.Final"
runtime "org.apache.tomcat:tomcat-jdbc:8.5.0"
runtime "org.apache.tomcat.embed:tomcat-embed-logging-log4j:8.5.0"
runtime "org.slf4j:slf4j-api:1.7.10"
}
and as simple as that, the project fails to start. What, exactly, causes the UnsatisfiedDependencyException? Is there a simple straightforward way to solve it?.
Thank you very much in advance.
Related
I'm developing a Spring Boot application following TDD methodology. I've created the main classes (controller, service and repository) this way:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class CrimeServiceImpl implements CrimeService{
#Autowired
private CrimeRepository repository;
...
Controller:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class CrimeController {
#Autowired
private CrimeServiceImpl service = new CrimeServiceImpl();
Repository:
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface CrimeRepository extends JpaRepository<Crime, Long>{
}
This is the project structure:
If I run the application normally, no error. The classes' methods are empty. Then I've created a test class like this:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = CrimeServiceImpl.class)
#ComponentScan("com.springmiddleware")
#AutoConfigureMockMvc
#SpringBootTest
public class TestCrimeService {
//Calling method getAllCrimes works
#Test
public void returnAllCrimesExists() throws NoSuchMethodException, SecurityException {
List<Crime> list = new ArrayList<>();
assertTrue(this.service.getAllCrimes() == list);
}
And if I run this, the following error is shown and the test fails:
NoSuchBeanDefinitionException: No qualifying bean of type 'com.springmiddleware.repository.CrimeRepository' available: expected at least 1 bean which qualifies as autowire candidate.
I've checked all annotations and it seems to me that all is ok, and I thought if I missed something, even in the normal run the application would fail. What did I got wrong?
I wanted also to make a test class for a JPARepository, and I also encountered the same error message:
NoSuchBeanDefinitionException: No qualifying bean of type
'SomethingRepository' available:
expected at least 1 bean which qualifies as autowire candidate.
I could make it work by adding the 2 following annotations on top of the test class:
#EnableJpaRepositories(basePackageClasses = SomethingRepository.class) // repository
#EntityScan(basePackageClasses = Something.class) // entity of the repository
Now it looks like:
#RunWith(SpringRunner.class)
#EnableJpaRepositories(basePackageClasses = SomethingRepository.class) // repository
#EntityScan(basePackageClasses = Something.class) // entity of the repository
#SpringBootTest(classes = MyDbUnitTestApp.class) // does some #ComponentScan and #EntityScan on the repositories/entities package, and #EnableAutoConfiguration
#ActiveProfiles(Profiles.myTestProfile)
#DatabaseSetup(value = {
"/datasets/dataset1.xml" }, type = DatabaseOperation.CLEAN_INSERT)
public class SomethingRepositoryTest {
#Autowired
private SomethingRepository sut;
#Test
public void findById() {
Something something= sut.findById(1L);
Assert.assertEquals("foobar", something.getName());
}
}
I'm getting this exception on my test excution:
UnsatisfiedDependencyException: Error creating bean with name 'net.gencat.transversal.espaidoc.mongo.GridFSTest': Unsatisfied dependency expressed through field 'resourceProperties'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'net.gencat.transversal.espaidoc.ResourcesConfigProperties' available: expected at least 1 bean which qualifies as autowire candidate.
So, I think message is so clear enough: ResourcesConfigProperties is not satisfied.
My test:
RunWith(SpringRunner.class)
#SpringBootTest()
public class GridFSTest {
#Autowired
private GridFsTemplate gridFsTemplate;
#Autowired
private ResourcesConfigProperties resourceProperties;
public URL getHugeResource() {
try {
return Paths
.get(this.resourceProperties.getHuge())
.toUri()
.toURL();
} catch (MalformedURLException e) {
return null;
}
}
#Test
public void storeHugeFile() throws IOException {
URL resource = this.getHugeResource();
this.gridFsTemplate.store(
resource.openStream(),
resource.getPath(),
"mime"
);
}
}
and ResourcesConfigProperties is:
#ConfigurationProperties(prefix = "files")
public class ResourcesConfigProperties {
private String huge;
/**
* #return the huge
*/
public String getHuge() {
return huge;
}
/**
* #param huge the huge to set
*/
public void setHuge(String huge) {
this.huge = huge;
}
}
into my src/test/resources I have my application.properties file:
files.huge: /home/jcabre/Downloads/1GB.zip
Any ideas?
EDIT
Main Spring boot application:
#SpringBootApplication(
//scanBasePackages = { "cat.gencat.ctti.canigo.arch.web.rs" },
exclude = JmxAutoConfiguration.class
)
#EnableConfigurationProperties({
ApiProperties.class,
FileStoreProperties.class
})
#Import(RedisConfiguration.class)
public class ApiApplication {
public static void main(String[] args) {
SpringApplication.run(ApiApplication.class, args);
}
}
TL;DR:
It is happening, because the #ConfigurationProperties are not managed by the application context you build in tests, although they will be load when the application launches, because you have #EnableConfigurationProperties on your app main class.
#EnableConfigurationProperties on main class only affect the application context you have when you bootRun, but not that in a #SpringBootTest. The application context you build in tests could be, under many circumstances, distinct with that of bootRun, just like in your case.
You can add #Component to make the context be aware of it, both in gradle bootRun and in gradle test. It's the easiest way, but not 100% the suggested way.
More proper way with details if you have time
Instead, you can add #EnableConfigurationProperties({Config1.class, Config2.class}) in a #SpringBootTest, to inject only some of the configuration properties class into the context, to avoid injection overhead.
It would be like:
//#RunWith(SpringRunner.class) // for JUnit4 in Spring
#ExtendWith(SpringExtension.class) // for JUnit5 in Spring.
#SpringBootTest
#EnableConfigurationProperties({
ResourcesConfigProperties.class,
})
#Data
public class ConfigsTest {
#Autowired
private ResourcesConfigProperties resourceConfigProperties;
...
}
Better yet, you can use #SpringBootTest(classes={}): classes within {} are those you want the application context of #SpringBootTest to manage(creation, initialization, loading properties from yaml files, and so on). Then you don't have to load all the context, but only part of it.
You can group all classes of #ConfigurationProperties in one class of #Configuration, and put it in the classes={} of #SpringBootTest, instead of repeating this list of #ConfigurationProperties everywhere. Something like:
//#RunWith(SpringRunner.class) // for JUnit4 in Spring
#ExtendWith(SpringExtension.class) // for JUnit5 in Spring.
#SpringBootTest(classes = {
TestConfiguration.class
})
#Data
public class ConfigsTest {
#Autowired
private ResourcesConfigProperties resourceConfigProperties;
...
}
TestConfiguration.java:
#EnableConfigurationProperties({
ResourcesConfigProperties.class,
})
#Configuration
public class TestConfiguration {
}
You need to add ResourcesConfigProperties to your EnableConfigurationProperties annotation in the main spring boot class, this will load and create a bean out of the ResourceConfigProperties for you
You could also add #Component to your ResourceConfigProperties if you do not want to add it to the EnableConfigurationProperties annotation.
When using the SpringBootTest or any slice test it will use whatever is annotated on, or beans defined within the main SpringBootApplication within the test context.
You also need to annotate ResourcesConfigProperties class with #Configuration as below, otherwise it will not create a bean of this class in the spring container.
#Configuration
#ConfigurationProperties(prefix = "files")
public class ResourcesConfigProperties {
private String huge;
/**
* #return the huge
*/
public String getHuge() {
return huge;
}
/**
* #param huge the huge to set
*/
public void setHuge(String huge) {
this.huge = huge;
}
}
While running my launcher class i am getting the below error
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'roles' available
My RoleLauncher Class
// reads spring config java class
package come.rahul.spring.launcher;
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(RolesConfig.class);
Roles roles = context.getBean("roles", Roles.class);
My RolesConfig.class is just annotated with #Configuration and #ComponentScan("com.rahul.spring"). Its in the
package come.rahul.spring.configuartion;
My Roles Class is
package come.rahul.spring.entity;
#Component
public class Roles {
private Long roleId;
private String roleName;
//getter and setter omitted for brevity
I have one Dao and it's implementaion too
package come.rahul.spring.dao;
public interface RolesDao
{
//List<Roles> getRoles(); omitted for brevity
void print() ;
}
Its implementation is below :
package come.rahul.spring.dao;
#Repository
public class RolesDaoImpl implements RolesDao
public void print() {
System.out.println( " Inside Print method of RolesDaoImpl");
}
}
You use #ComponentScan("com.rahul.spring") but everywhere, you use package come.rahul.spring;. You need to use com everywhere instead of come
Given some application configuration with an unresolvable placeholder, like the following application.yml
my:
thing: ${missing-placeholder}/whatever
When I use #Value annotations, the placeholders in the configuration file are validated, so in this case:
package com.test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class PropValues {
#Value("${my.thing}") String thing;
public String getThing() { return thing; }
}
I get an IllegalArgumentException: Could not resolve placeholder 'missing-placeholder' in value "${missing-placeholder}/whatever". This is because the value is being set directly by AbstractBeanFactory.resolveEmbeddedValue and there is nothing to catch the exception thrown by PropertyPlaceholderHelper.parseStringValue
However, looking to move to #ConfigurationProperties style I noticed that this validation is missing, for example in this case:
package com.test;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
#ConfigurationProperties(prefix = "my")
public class Props {
private String thing;
public String getThing() { return thing; }
public void setThing(String thing) { this.thing = thing; }
}
there is no exception. I can see PropertySourcesPropertyValues.getEnumerableProperty catches the exception with the comment // Probably could not resolve placeholders, ignore it here and gathers the invalid value into its internal map. Subsequent data binding does not check for unresolved placeholders.
I checked that simply applying the #Validated and #Valid annotations to the class and field do not help.
Is there any way to preserve the behaviour of throwing an exception on unresolved placeholders with ConfigurationProperties binding?
Apparently there are no better solutions. At least this is kind of nicer than afterPropertiesSet().
#Data
#Validated // enables javax.validation JSR-303
#ConfigurationProperties("my.config")
public static class ConfigProperties {
// with #ConfigurationProperties (differently than #Value) there is no exception if a placeholder is NOT RESOLVED. So manual validation is required!
#Pattern(regexp = ".*\$\{.*", message = "unresolved placeholder")
private String uri;
// ...
}
UPDATE: I got the regex wrong the first time. It as to match the entire input (not just java.util.regex.Matcher#find()).
The correct regex to pass in #Pattern annotation is ^(?!\\$\\{).+
#Validated
#ConfigurationProperties("my.config")
public class ConfigProperties {
#Pattern(regexp = "^(?!\\$\\{).+", message = "unresolved placeholder")
private String uri;
// ...
}
I had the same issue exactly 10 minutes ago!
Try to add this bean in your configuration:
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
propertySourcesPlaceholderConfigurer.setIgnoreUnresolvablePlaceholders(true);
return propertySourcesPlaceholderConfigurer;
}
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!