Kotlin application.yml data class looking for beans - spring

I have a Kotlin data class that I want to read properties from application.yml file. Here is my data class:
#ConstructorBinding
#ConfigurationProperties("meanwhile.in.hell.myapp")
data class MyAppProperties(val serverId: String, val locationId: String)
I then added it to my configuration class:
#Configuration
#EnableConfigurationProperties(MyAppProperties::class)
open class MyAppConfiguration(private val properties: MyAppProperties) {
where I access the values using just properties.serverId and pass the object into the constructor of other beans being created, such as this one:
open class MyAppClient(
private val webClient: WebClient,
private val properties: MyAppProperties
) : IMyAppClient {
However, when I start up my application I get an error that instead of trying to load the properties from application.yml, it is trying to find beans for the constructor params:
Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'meanwhile.in.hell.myapp-meanwhile.in.hell.myapp.MyAppProperties': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Parameter 0 of constructor in meanwhile.in.hell.myapp.MyAppProperties required a bean of type 'java.lang.String' that could not be found.
How do I stop my app thinking that these params are Autowired? I know that in Kotlin, this is how a constructor Autowired bean looks like (ie, not requiring the annotation), but all example I have seen online on how to read application.yml properties looks the same as my data class.
Spring-Boot v2.3.0.RELEASE
Kotlin v1.3.72

Turns out I was missing the dependency
org.jetbrains.kotlin:kotlin-reflect
Docs:
https://docs.spring.io/spring-boot/docs/2.2.1.RELEASE/reference/htmlsingle/#boot-features-kotlin-requirements
Issue:
https://github.com/spring-projects/spring-boot/issues/19582

Related

kotlin, spring boot and data classes for configuration

I've implemented several projects with spring boot and java. Now I'm evaluating, if I could do it with kotlin.
I am struggling with #ConfigurationProperties and data classes.
Simple example:
api:
clientId: client123
url: https://api.url.com
key: api-access-key
Data class:
#ConfigurationProperties("api")
#ConstructorBinding
data class ApiConfiguration(
val clientId: String,
val url: String,
val key: String
)
Starter class:
#EnableConfigurationProperties(ApiConfiguration::class)
#SpringBootApplication
class SpringdemoApplication
fun main(args: Array<String>) {
runApplication<SpringdemoApplication>(*args)
}
If I'm running a test, I get the following message:
s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'apiConfiguration': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
...
Description:
ApiConfiguration is annotated with #ConstructorBinding but it is defined as a regular bean which caused dependency injection to fail.
Action:
Update your configuration so that ApiConfiguration is defined via #ConfigurationPropertiesScan or #EnableConfigurationProperties.
The following post doesn't help me: Kotlin & Spring Boot #ConfigurationProperties
Environment:
spring boot 2.7.8
kotlin 1.6.21
Can someone help me to understand and solve the problem?

No qualifying bean of type [com.atlassian.jira.issue.TemporaryAttachmentsMonitorLocator]

I started to develop a Jira External System Importer Plugin and I should upload a JSON File using its Setup Page but when I add "TemporaryAttachmentsMonitorLocator" to my SetupPage class constructor and I click on my importer's button, it fails with the error: "No qualifying bean of type [com.atlassian.jira.issue.TemporaryAttachmentsMonitorLocator]"
[INFO] [talledLocalContainer] org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dev.addax.jira.plugins.trello2jira.web.TrelloSetupPage': Unsatisfied dependency expressed through constructor argument with index 4 of type [com.atlassian.jira.issue.TemporaryAttachmentsMonitorLocator]: No qualifying bean of type [com.atlassian.jira.issue.TemporaryAttachmentsMonitorLocator] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport(value=)}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: **No qualifying bean of type [com.atlassian.jira.issue.TemporaryAttachmentsMonitorLocator] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency**. Dependency annotations: {#com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport(value=)}
[INFO] [talledLocalContainer] at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749)
public class TrelloSetupPage extends AbstractSetupPage {
private final TemporaryAttachmentsMonitorLocator locator;
public TrelloSetupPage(#ComponentImport UsageTrackingService usageTrackingService, #ComponentImport WebInterfaceManager webInterfaceManager,
#ComponentImport PluginAccessor pluginAccessor, #ComponentImport EventPublisher eventPublisher,
#ComponentImport TemporaryAttachmentsMonitorLocator locator) {
super(usageTrackingService, webInterfaceManager, pluginAccessor, eventPublisher);
this.locator = locator;
}
// ... other content omitted.
}
The other params in my constructor are resolved right. Only this one is what it fails. If I remove that class I can navigate to my SetupPage as is expected.
Finally, the class is exported by the OSGi system bundle and I checked it is even still used as a service by the Jira native JIM Plugin.
Any idea what might be the reason why it is not finding this class?
I removed #ComponentImport TemporaryAttachmentsMonitorLocator locator and I included
ComponentAccessor.getOSGiComponentInstanceOfType(TemporaryAttachmentsMonitorLocator.class) in the constructor body.
I don't know why #ComponentImport does not work for this case but the workaround works like a charm.

Spring Data JDBC UnsatisfiedDependencyException

I wanted to move from JdbcTemplate to Spring Data JDBC. However I seem to have some misconfiguration but I cannot figure out where. The errors are "expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}" and "Parameter 0 of constructor ... required a bean ... that could not be found."
I put #Repository on the public repository interfaces extending PagingAndSortingRepository (as I did with the DAO classes extending from JdbcDaoSupport) without success. Then I added #EnableJdbcRepositories with and without package name to the database config class, also no success. I also tried the database config to inherit from AbstractJdbcConfiguration, still the same errors ...
Unfortunately I couldn't find a working example and I now gave up after some trial and error. I still would love to get this working, the version I used is spring-boot-starter-data-jdbc:2.4.0
Code fragments:
DatabaseConfiguration.java
#Configuration
#EnableJdbcRepositories("<basepackage>.repository.jdbc")
#EnableJdbcAuditing(auditorAwareRef = "springSecurityAuditorAware")
#EnableJpaRepositories("<basepackage>.repository")
#EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
#EnableTransactionManagement
#EnableElasticsearchRepositories("<basepackage>.repository.search")
public class DatabaseConfiguration extends AbstractJdbcConfiguration {
}
UserRepository.java
#Repository
public interface UserRepository extends PagingAndSortingRepository<User, String> {
}
QualityResource.java (REST Controller)
public QualityResource(UserRepository userRepository) {
this.userRepository = userRepository;
}
Error messages:
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'qualityResource' defined in file [.../backend/build/classes/java/main/.../web/rest/QualityResource.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type '....repository.jdbc.UserRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Application failed to start: Description: Parameter 0 of constructor in <basepackage>.web.rest.QualityResource required a bean of type '<basepackage>.repository.jdbc.UserRepository' that could not be found.

Spring beans GeoModule bean injection to RepositoryRestMvcConfiguration

I'm currently testing spring data rest, and I want to expose the primary keys (ids) of my entities through the REST interface.
I have found that the proper (?) way to do this is:
public class IdExporterConfiguration extends RepositoryRestMvcConfiguration {
#Override
protected void configureRepositoryRestConfiguration(
RepositoryRestConfiguration config) {
super.configureRepositoryRestConfiguration(config);
config.exposeIdsFor(User.class);
}
}
The problem is, that if I change my bean definition to this:
<bean class="test.project.util.IdExporterConfiguration"/>
From this:
<bean class="org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration"/>
my application fails to start...
The error is:
Could not autowire field: org.springframework.data.geo.GeoModule org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration.geoModule;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.data.geo.GeoModule] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Basically it says that it does not find a GeoModule bean, so it can't autowire it for the RepositoryRestMvcConfiguration base...
Now the fun part is, that is I define the bean:
<bean class="org.springframework.data.geo.GeoModule"/>
The error changes to:
Could not autowire field: org.springframework.data.geo.GeoModule org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration.geoModule;
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.data.geo.GeoModule] is defined:
expected single matching bean but found 2: jacksonGeoModule,org.springframework.data.geo.GeoModule#0
So if I don't define a bean, there is 0, but if I define one, there is 2?
I still don't know why, but if I use the #Configuration annotation, then it works...
No GeoModule bean needed, but how can it be, that with the original config as XML bean definition it works, but with the subclass, it does not?

Spring: how to ignore #Autowired property if bean is not defined

Situation: I have I class with property annotated with #Autowired:
public class MyClass {
#Autowired
protected MyAutoWiredBean myAutowiredBean;
}
Is there any possibility to made wiring this bean optional, i.e. if such bean is defined in some configuration file - to wire it, but if such bean is not defined - just continue working without throwing:
org.springframework.beans.factory.BeanCreationException:
Could not autowire field: protected MyAutoWiredBean...;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No matching bean of type [com.mypackage.MyAutoWiredBean] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.
Have you tried:
#Autowired(required=false)
Javadoc:
Declares whether the annotated dependency is required. Defaults to true
you can set required attribute like :
#Autowired(required=false)
http://static.springsource.org/spring/docs/2.5.5/api/org/springframework/beans/factory/annotation/Autowired.html

Resources