#Autowired but got lateinit property testBean has not been initialized error - spring

I have following class (partial code):
#Component
class TestClass: InitializingBean, DisposableBean {
#Autowired
private lateinit var testBean: SomeObject
override fun afterPropertiesSet(){
log.info("testBean 1: $testBdean")
}
fun testFunction(testName: String): Boolean {
log.info("testBean 2: $testBdean")
}
#Throws(Exception::class)
override fun destroy() {
}
}
I saw testBean 1 was run successfully but testBean 2 gave error: lateinit property testBean has not been initialized. So the testBean bean was initialized in afterPropertiesSet() and not available in other functions? I know if we put testBean in the constructor TestClass(testBean) it will be initialized and available to all functions. But is there another way because TestClass will be called from other packages and not every package can pass the testBean to the constructor.

You could create an object that holds your TestClass and use that holder to refer to your create component
something like:
#SpringBootApplication
class DemoApplication
fun main(args: Array<String>) {
runApplication<DemoApplication>(*args)
}
#Component
class SomeObject(val name:String = "some object")
#Component
class TestClass(val someObject: SomeObject) {
init {
TestClassHolder.testClass = this
}
fun test() = someObject.name
}
object TestClassHolder {
lateinit var testClass: TestClass
}
class NotBeanClass {
fun call() = TestClassHolder.testClass.test()
}
#RestController
class TestController {
#GetMapping
fun test() = NotBeanClass().call()
}

Related

Verifying pointcuts being called in tests

I have a dummy project where I try figure out how to test pointcuts being triggered.
My project consists of 1 aspect bean which just prints after a foo method is called
#Component
#Aspect
public class SystemArchitecture {
#After("execution(* foo(..))")
public void after() {
System.out.println("#After");
}
}
And a FooServiceImpl with implemented foo method
#Service
public class FooServiceImpl implements FooService{
#Override
public FooDto foo(String msg) {
return new FooDto(msg);
}
}
The code works and and I can see "#After" being printed to console, but I can't check programatically if after pointcut was called using the test below.
#SpringBootTest
public class AspectTest {
#Autowired
private FooService fooService;
#Test
void shouldPass() {
fooService.foo("hello");
}
}
I've also tried using non-bean proxy as was adviced in https://stackoverflow.com/a/56312984/18224588, but this time I'm getting an obvious error cannot extend concrete aspect because my spy proxy is no longer viewed as an aspect:
public class AspectNoContextTest {
#Test
void shouldPass() {
FooService fooService = Mockito.mock(FooService.class);
SystemArchitecture systemArchitecture = Mockito.spy(new SystemArchitecture());
AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory(fooService);
aspectJProxyFactory.addAspect(systemArchitecture);
DefaultAopProxyFactory proxyFactory = new DefaultAopProxyFactory();
AopProxy aopProxy = proxyFactory.createAopProxy(aspectJProxyFactory);
FooService proxy = (FooService) aopProxy.getProxy();
proxy.foo("foo");
verify(systemArchitecture, times(1)).after();
}
}
Ok, after some digging, I found that it's possible to accomplish this by making an aspect a #SpyBean. Also AopUtils can be used for performing additional checks
#SpringBootTest
public class AspectTest {
#Autowired
private FooService fooService;
#SpyBean
private SystemArchitecture systemArchitecture;
#Test
void shouldPass() {
assertTrue(AopUtils.isAopProxy(fooService));
assertTrue(AopUtils.isCglibProxy(fooService));
fooService.foo("foo");
verify(systemArchitecture, times(1)).after();
}
}

java bootstrap mock with ConditionalOnProperty and Autowired member

I have an object that looks like this:
#Service
#ConditionalOnProperty(
name="name",
havingValue = "true"
)
public class MyClass{
#Autowired(required = false)
private SomeObject someObject;
}
And I have this in my test file:
#ExtendWith({SpringExtension.class})
#ContextConfiguration(classes = {MyClass.class}, loader = AnnotationConfigContextLoader.class)
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class MyTest {
MyClass myClass;
#Autowired
#ConditionalOnProperty(
name = "name",
havingValue = "true"
)
static MyClass getMyClass(){
return new MyClass();
}
}
#MockBean
static SomeObject someObject;
#BeforeAll
public void before() {
myClass = MyTest.getMyClass()
when(someObject.someFunc()).thenReturn(1);
}
}
I'm using this function because just using #Autowired and #MockBean on the SomeObject didn't work because of the #ConditionalOnProperty.
The problem is that inside MyClass, someObject is null.
No need to use static MyClass getMyClass()
use:
#ExtendWith({SpringExtension.class})
#ContextConfiguration(classes = {MyClass.class, SomeObject.class, loader = AnnotationConfigContextLoader.class)
#SpringBootTest(properties = "name=true")
public class MyTest{
#Autowired
MyClass
#Autowired myClass;
SomeObject someObject;
}

lateinit property has not been initialized when using #Autowired

I'm using #Bean and #Autowired
#Component
class ConfigurationServiceInvoker() {
fun getRules(request: RulesRequest): RulesResponse {
return runBlocking { stub.geRules(request) }
}
}
#Component
object InvokerConfiguration {
#Bean
fun getConfigurationServiceInvoker(): ConfigurationServiceInvoker {
return ConfigurationServiceInvoker()
}
}
When I calling getRules() function I got error "lateinit property configurationServiceInvoker has not been initialized", how to fix this issue?
#Autowired
private lateinit var configurationServiceInvoker: ConfigurationServiceInvoker
val response = configurationServiceInvoker.getRules()
configurationServiceInvoker.getRules() is being invoked during construction of the object. Runtime annotation processors like that which handles #Autowired occur after the object is constructed. Consider using #PostConstruct to initialize the response value, like so:
#Autowired
private lateinit var configurationServiceInvoker: ConfigurationServiceInvoker
lateinit var response;
#PostConstruct
fun postConstruct() {
response = configurationServiceInvoker.getRules()
}

Defining constructor in prototype bean

Using SpringBoot, I have a Component bean that is defined as #Scope("protoype"). It also injects another prototype bean
The class is defined as
#Component
#Scope("prototype")
public class MyClass{
#Autowired
public BeanFactory beanFactory
private InjectedBean injectedBean
public MyClass(DataObj data) {
this.injectedBean = beanFactory.getBean(InjectedBean.class, data)
}
}
However, IntelliJ complains about the data field on the constructor: Could not autowire. No beans of 'DataObj' type found.. But DataObj is a POJO. I pass it in at runtime in order to create the bean. Am I defining the constructor incorrectly?
Update
Had the same problem doing it this way. It still wants to treat DataObj as a bean on the factory constructor class. Doesn't matter if I annotate the class with #Component or #Configuration
#Component
public class MyClass{
#Autowired
public BeanFactory beanFactory
private InjectedBean injectedBean
public MyClass(InjectedBean injectedBean) {
this.injectedBean = injectedBean;
}
#Bean
#Scope("prototype")
public MyClass myClass(DataObj data) {
InjectedBean injectedBean = beanFactory.getBean(InjectedBean.class, data)
return new MyClass(injectedBean);
}
}
Also tried this example from that same link:
#Configuration
public class ServiceConfig {
#Bean
public Function<DataObj, MyClass> thingFactory() {
return data-> myClass(data); //
}
#Bean
#Scope(value = "prototype")
public MyClass myClass(DataObj data) {
return new MyClass(data);
}
}
Update
I think I resolved this with some information in Spring Java Config: how do you create a prototype-scoped #Bean with runtime arguments?. Part of my problem is that I tried to put the factory bean in the Component itself, which doesn't work
In other words
#Component
public class MyClass{
#Autowired
public BeanFactory beanFactory
private InjectedBean injectedBean
public MyClass(InjectedBean injectedBean) {
this.injectedBean = injectedBean;
}
#Bean
#Scope("prototype")
public MyClass myClass(DataObj data) {
InjectedBean injectedBean = beanFactory.getBean(InjectedBean.class, data)
return new MyClass(injectedBean);
}
}
In this cass, Spring tries to create a MyClass bean because of the #Component annotation, but another MyClass bean due to the #Bean annotation.
So I moved the #Bean to another class
#Configuration
public class ServiceConfig {
#Bean
public Function<DataObj, MyClass> thingFactory() {
return data-> myClass(data); //
}
#Bean
#Scope(value = "prototype")
public MyClass myClass(DataObj data) {
return new MyClass(data);
}
}
This appears to work, but IntelliJ still complains about DataObj. This might be an Intellij issue

Spring AOPed target class not injecting mocks

I have class A having structure:
#Service
Class A implements AInterface {
private final C c;
String test(String b) {
}
}
Structure of class C:
class C {
// some methods
}
then I wrote interceptor for this class :
#Aspect
#Component
class Interceptor {
#Around(
value =
"execution(* AInterface.test(..)) && args(c)")
public Object intercept(ProceedingJoinPoint joinPoint, String c) {
// some logic
}
}
I am trying to do integration test and wants to inject mock class c in A but its not happening.
Test class structure:
#SpringBootTest
class ATest {
// Tried #MockBean also
#Mock
private C c;
#Autowired #InjectMock private AInterface a;
#BeforeTest {
MockitoAnnotations.initMocks(this);
// tried using ReflectionUtils to inject mock
}
#Test
void testTest () {
// when then logic
}
}

Resources