I'm just implements quartz scheduler with kotlin and spring boot.
kotlin.UninitializedPropertyAccessException: lateinit property userController has not been initialized
I know userController Object is not created with #autowired basically in kotlin lateinit create object lazy so i d'not have idea to fix this issue. any possible way to create object in kotlin with eagerly to fix this issue
I'm Getting the following error:
Full Error Log : For reference
21:02:00.037 [DatabaseScheduler_Worker-1] ERROR org.quartz.core.JobRunShell - Job commentJobGroup.commentJob threw an unhandled Exception:
kotlin.UninitializedPropertyAccessException: lateinit property userController has not been initialized
at com.lovevirus.kotlinQuartzScheduler.scheduler.Jobs.CommentJob.getUserController(CommentJob.kt:17)
at com.lovevirus.kotlinQuartzScheduler.scheduler.Jobs.CommentJob.execute(CommentJob.kt:21)
at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
21:02:00.038 [DatabaseScheduler_Worker-1] ERROR org.quartz.core.ErrorLogger - Job (commentJobGroup.commentJob threw an exception.
org.quartz.SchedulerException: Job threw an unhandled exception.
at org.quartz.core.JobRunShell.run(JobRunShell.java:213)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property userController has not been initialized
at com.lovevirus.kotlinQuartzScheduler.scheduler.Jobs.CommentJob.getUserController(CommentJob.kt:17)
at com.lovevirus.kotlinQuartzScheduler.scheduler.Jobs.CommentJob.execute(CommentJob.kt:21)
at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
... 1 common frames omitted
Code:
import org.quartz.Job
import org.quartz.JobExecutionContext
import org.springframework.stereotype.Component
import com.lovevirus.kotlinQuartzScheduler.controller.UserController;
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
#Component
class CommentJob : Job {
private val logger: Logger = LoggerFactory.getLogger(CommentJob::class.java)
#Autowired
lateinit var userController : UserController;
override fun execute(p0: JobExecutionContext?) {
logger.debug("Inside Comment Job");
userController.getUser();
logger.debug("End Comment Job");
}
}
Thanks in advance
Have you implemented a custom SpringBeanJobFactory that would allow dependency autowiring?
class AutowiringSpringBeanJobFactory : SpringBeanJobFactory(), ApplicationContextAware {
#Transient
private var beanFactory: AutowireCapableBeanFactory? = null
override fun setApplicationContext(applicationContext: ApplicationContext) {
beanFactory = applicationContext.autowireCapableBeanFactory
}
override fun createJobInstance(bundle: TriggerFiredBundle): Any {
val job = super.createJobInstance(bundle)
beanFactory!!.autowireBean(job)
return job
}
}
The controller can also be passed on via the constructor:
#Component
class CommentJob(#Autowired userController: UserController): Job {
private val logger: Logger = LoggerFactory.getLogger(CommentJob::class.java)
override fun execute(p0: JobExecutionContext?) {
logger.debug("Inside Comment Job");
userController.getUser();
logger.debug("End Comment Job");
}
}
#Autowired can also be omitted. For more information about Kotlin and Spring Boot:
https://www.baeldung.com/spring-boot-kotlin
Related
i'am wrapping a service in a spy , that i put in springBoot application class annotated with #SpringBootApplication,
when i'am injecting the service in a test class it does not work, it injects the real service and not the spy , the test fails and i have the following exception : java.lang.IllegalStateException: Failed to unwrap proxied object.
here is my code :
#SpringBootApplication
public class ApiApplication {
#Bean
#Primary
public ApiService myservice(ApiService actual) {
return Mockito.spy(actual);
}
and i inject it in test :
public class ApiStepDefs {
private final MockMvc mockMvc;
private final ApiService apiServiceCustom;
public ApiStepDefs(MockMvc mockMvc, ApiService apiServiceCustom) {
this.mockMvc = mockMvc;
this.apiServiceCustom = apiServiceCustom;
}
thanks
I have this bean defined in a Batch application:
#Service("updating-processor")
class UpdatingProcessor(val searchService: searchService, val objectMapper: ObjectMapper) : ItemProcessor<SomeItem, List<OtherObject>>
I know that the above bean gets created in the app, I put a breakpoint in the init method and it stops when I debug the app.
I have this class:
#SpringBootApplication
#EnableBatchProcessing
#EnableJpaRepositories
#EnableRetry(proxyTargetClass=true)
class EtlApplication() : CommandLineRunner {
companion object {
val LOG = LoggerFactory.getLogger(EtlApplication::class.java.name)
}
#Autowired
#Qualifier("updating-processor")
lateinit var updatingProcessor: ItemProcessor<SomeItem, List<OtherObject>>
}
APPLICATION FAILED TO START
Description:
Field updatingProcessor in ... required a bean of type >> 'org.springframework.batch.item.ItemProcessor' that could not be found.
Action:
Consider defining a bean of type 'org.springframework.batch.item.ItemProcessor' in your configuration.
I get an error saying that the "updating-processor" cannot be autowired, and it's due to the List<OtherObject> as the second type. If I change List<OtherObject> to just OtherObject for the second generic parameter, the autowiring works.
How do I make it work with the list?
This is related to this post -> spring-inject-list-of-generic-interface-implementations-in-kotlin
You should be able to take the Action suggested by Spring:
Consider defining a bean of type 'org.springframework.batch.item.ItemProcessor' in your configuration.
For example:
#Configuration
class UpdatingProcessorConfig {
#Autowired
lateinit var searchService: SearchService
#Autowired
lateinit var objectMapper: ObjectMapper
#Bean
fun updatingProcessor(): ItemProcessor<SomeItem, List<OtherObject>> = UpdatingProcessor(searchService, objectMapper)
}
class UpdatingProcessor(val searchService: SearchService, val objectMapper: ObjectMapper) :
ItemProcessor<SomeItem, List<OtherObject>> {
override fun process(p0: SomeItem): List<OtherObject>? {
TODO("not implemented")
}
}
Spring Boot allows to inject a list of all implementations of an interface (SomeComponent) as List into another component (SomeOtherComponent), e.g.
#Component
interface SomeComponent
#Component
class SomeComponentImpl0 : SomeComponent
#Component
class SomeComponentImpl1 : SomeComponent
class SomeOtherComponent {
#Autowired
lateinit var impls: List<SomeComponent>
}
How can I inject mocks for the implementations using MockK annotations? In
import io.mockk.MockKAnnotations
import io.mockk.impl.annotations.InjectMockKs
import io.mockk.impl.annotations.MockK
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
class SomeOtherComponentTest {
#MockK
lateinit var someComponentImpl0: SomeComponentImpl0
#MockK
lateinit var someComponentImpl1: SomeComponentImpl1
#InjectMockKs
lateinit var instance: SomeOtherComponent
#BeforeEach
fun setup() {
MockKAnnotations.init(this)
}
#Test
fun testSomething() {
println(instance.impls.toString())
}
}
I'm getting either
io.mockk.MockKException:
No matching constructors found:
constructor(impls : kotlin.collections.List<de.richtercloud.inject.mocks.foor.list.of.impl.SomeComponent> = <not able to lookup>)
at de.richtercloud.inject.mocks.foor.list.of.impl.SomeOtherComponentTest.setup(SomeOtherComponentTest.kt:40)
if I'm using constructor injecction and
kotlin.UninitializedPropertyAccessException: lateinit property impls has not been initialized
at de.richtercloud.inject.mocks.foor.list.of.impl.SomeOtherComponentTest.testSomething(SomeOtherComponentTest.kt:26)
if I'm using an #Autowired var property in the class.
I'm using 1.3.50 through Maven 3.6 and MockK 1.9.3.
Add #ExtendWith(MockKExtension::class) above your Test class to make #InjectMokKs work.
I had the same problem here. It worked when I removed lateinit from the component being tested, and instantiated it on declaration.
For example, changed:
#InjectMockKs
lateinit var instance: SomeOtherComponent
to:
#InjectMockKs
var instance = SomeOtherComponent()
This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 4 years ago.
I'm new to SpringBoot. The problem I am facing with #Autowired annotation. When I'm trying to get the autowired bean, the compiler throw NullPointerException.
This is the service I'm using:
package com.oss.mail.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.integration.handler.LoggingHandler;
import org.springframework.stereotype.Service;
import com.oss.mail.dao.EmailReadingDao;
#Service
public class EmailReadingService {
Logger logger = LoggerFactory.getLogger(LoggingHandler.class);
EmailReadingDao emailReadingDao=new EmailReadingDao();
public void readEmails(){
logger.info("Called readEmail method from EmailReadingService");
logger.info("Calling readEmailDao() from EmailReadingDao");
emailReadingDao.readEmailDao();
}
}
This is how I defined my DAO:
#Configuration
public class EmailReadingDao {
Logger logger = LoggerFactory.getLogger(LoggingHandler.class);
#Autowired
private Environment env;
#Autowired
private GetEmails getEmailsUtil;
String emailHost;
String emailPort;
String emailUserName;
String emailPassword;
int NoOfEmails;
public void readEmailDao(){
logger.info("Called readEmailDao() from EmailReadingDao");
Map<String, String> emailsString=new HashMap<String, String>();
emailHost=env.getProperty("mail.pop3s.host");//Error at thir line.
emailPort=env.getProperty("mail.pop3s.port");
emailUserName=env.getProperty("mail.pop3s.username");
emailPassword=env.getProperty("mail.pop3s.password");
NoOfEmails=Integer.parseInt(env.getProperty("mail.NoOfEmails"));
And this is what I'm seeing in my logs:
2018-07-30 03:49:38 INFO o.s.i.handler.LoggingHandler - Called readEmailDao() from EmailReadingDao
Exception in thread "main" java.lang.NullPointerException
at com.oss.mail.dao.EmailReadingDao.readEmailDao(EmailReadingDao.java:36)
at com.oss.mail.service.EmailReadingService.readEmails(EmailReadingService.java:20)
at com.oss.ProductionIncidentAutomation.ProductionIncidentAutomationApplication.main(ProductionIncidentAutomationApplication.java:32)
I'm not sure why the spring is not wiring this class. Please help me in getting the resolution of this.
Autowiring doesn't work if you create an object using the new keyword. It only works in container managed beans. So you have to autowire EmailReadingDao too.
Change:
EmailReadingDao emailReadingDao=new EmailReadingDao();
to:
#Autowired
EmailReadingDao emailReadingDao;
Also EmailReadingDao is not a configuration. You should annotate it with #Repository:
#Repository
public class EmailReadingDao {
Change EmailReadingDao emailReadingDao=new EmailReadingDao(); to
#Autowired
private EmailReadingDao emailReadingDao;
or even better use constructor injection.
Then also change in your EmailReadingDao from #Configuration to #Component
#Component
public class EmailReadingDao {
...
}
Is it possible to do something like following in Kotlin?
#Autowired
internal var mongoTemplate: MongoTemplate
#Autowired
internal var solrClient: SolrClient
Recommended approach to do Dependency Injection in Spring is constructor injection:
#Component
class YourBean(
private val mongoTemplate: MongoTemplate,
private val solrClient: SolrClient
) {
// code
}
Prior to Spring 4.3 constructor should be explicitly annotated with Autowired:
#Component
class YourBean #Autowired constructor(
private val mongoTemplate: MongoTemplate,
private val solrClient: SolrClient
) {
// code
}
In rare cases, you might like to use field injection, and you can do it with the help of lateinit:
#Component
class YourBean {
#Autowired
private lateinit var mongoTemplate: MongoTemplate
#Autowired
private lateinit var solrClient: SolrClient
}
Constructor injection checks all dependencies at bean creation time and all injected fields is val, at other hand lateinit injected fields can be only var, and have little runtime overhead. And to test class with constructor, you don't need reflection.
Links:
Documentation on lateinit
Documentation on constructors
Developing Spring Boot applications with Kotlin
Yes, java annotations are supported in Kotlin mostly as in Java.
One gotcha is annotations on the primary constructor requires the explicit 'constructor' keyword:
From https://kotlinlang.org/docs/reference/annotations.html
If you need to annotate the primary constructor of a class, you need to add the constructor keyword to the constructor declaration, and add the annotations before it:
class Foo #Inject constructor(dependency: MyDependency) {
// ...
}
You can also autowire dependencies through the constructor. Remember to annotate your dependencies with #Configuration, #Component, #Service etc
import org.springframework.stereotype.Component
#Component
class Foo (private val dependency: MyDependency) {
//...
}
like that
#Component class Girl( #Autowired var outfit: Outfit)
If you want property injection but don't like lateinit var, here is my solution using property delegate:
private lateinit var ctx: ApplicationContext
#Component
private class CtxVarConfigurer : ApplicationContextAware {
override fun setApplicationContext(context: ApplicationContext) {
ctx = context
}
}
inline fun <reified T : Any> autowired(name: String? = null) = Autowired(T::class.java, name)
class Autowired<T : Any>(private val javaType: Class<T>, private val name: String?) {
private val value by lazy {
if (name == null) {
ctx.getBean(javaType)
} else {
ctx.getBean(name, javaType)
}
}
operator fun getValue(thisRef: Any?, property: KProperty<*>): T = value
}
Then you can use the much better by delegate syntax:
#Service
class MyService {
private val serviceToBeInjected: ServiceA by autowired()
private val ambiguousBean: AmbiguousService by autowired("qualifier")
}