Spring annotation to initialize a bean during Autowire - spring

Do we have a spring annotation that provides an option to initialize a bean (not a component) if not available through default constructor while autowiring?
If yes, that will be awesome. I am tired of initializing beans in some configuration class using default constructor and it occupies space.
I am doing this currently
#Bean
public Test test() {
return new Test();
}
Expecting:
Sometime like:
#Autowire(initMethodType=constructor)
private Test test:
If no, was there no real need of such annotation or any technical limitation?

You have to use #Bean annotation inside an #Configuration class.
Check the following link
https://docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/ch02s02.html
#Configuration
public class AppConfig {
#Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}

You could annotate your class with #Component, like this:
#Component
public class Test {
...
}
Whereever you need that class, you could then simply autowire it:
#Autowired
private Test test;
You would just have to make sure, that you use #ComponentScan to pick up that bean. You can find more information on that here.

Related

Is there a way to overide automatically injected beans in Spring boot when writing tests?

I have a class annotated with a spring bean #Repository("clientDatasource") called ClientServiceDatasource which implements an interface called Datasource. I also have a mock implementation of this interface also annotated with a spring bean #Repository("mockDatasource") called MockClientServiceDatasource. I also have a class annotated with the spring bean #Service called ClientService and in in its constructor, I pass in a datasource. I do it like so:
#Service
class ClientService (#Qualifier("clientDatasource") private val dataSource: Datasource){}
As you can see that the service will default to the clientDatasource, because of the #Qualifier when the application is running.
However when I run my tests I annotate my test class with #SpringTest . In my understanding this means that it boots up the entire application as if it were normal. So I want to somehow overide that #Qualifier bean thats being used in the client service in my test so that the Client Service would then use the mockedDatasource class.
I'm fairly new to kotlin and spring. So I looked around and found ways to write a testConfig class to configure beans like so :
#TestConfiguration
class TestConfig {
#Bean
#Qualifier("clientDatasource")
fun mockDatasource(): Datasource {
return MockClientServiceDatasource()
}
}
and then using it in the test like so:
#SpringTest
#Import(TestConfig::class)
class ClientServiceTest {
...
}
I also asked chatGPT and it gave me this:
#SpringBootTest
class ClientServiceTest {
#Autowired
lateinit var context: ApplicationContext
#Test
fun testWithMockedDatasource() {
// Override the clientDatasource bean definition with the mockDatasource bean
val mockDatasource = context.getBean("mockDatasource", Datasource::class.java)
val mockClientDatasourceDefinition = BeanDefinitionBuilder.genericBeanDefinition(MockClientServiceDatasource::class.java)
.addConstructorArgValue(mockDatasource)
.beanDefinition
context.registerBeanDefinition("clientDatasource", mockClientDatasourceDefinition)
// Now the ClientService should use the mockDatasource when it's constructed
val clientService = context.getBean(ClientService::class.java)
// ... do assertions and other test logic here ...
}
}
But some of the methods don't work, I guess chatGPT knowledge is outdated.
I also looked through spring docs, but couldn't find anything useful.
Okay, So I took a look at the code previously with the TestConfig class. And I realised by adding the:
#Primary
annotation to the method inside my TestConfig class, it basically forces that to be the primary repository bean. Like so:
#TestConfiguration
class TestConfiguration {
#Bean
#Primary
#Qualifier("clientDatasource")
fun mockDatasource(): Datasource {
return MockClientDataSource()
}
}
and in the test I only imported the test and it just worked. I didn't have to autowire anything
This is my test class:
#SpringBootTest
#AutoConfigureMockMvc
#Import(TestConfiguration::class)
internal class ServiceControllerTest{
#Suppress("SpringJavaInjectionPointsAutowiringInspection")
#Autowired
lateinit var mockMvc: MockMvc
#Test
fun `should return all clients` () {
// when/then
mockMvc.get("/clients")
.andDo { print() }
.andExpect {
status { isOk() }
content { contentType(MediaType.APPLICATION_JSON) }
jsonPath("$[0].first_name") {value("John")}
}
}
}

Spring Java Config: configure already existing bean

I want to configure in my #Configuration class bean which is already created by other library's autoconfiguration. I just need to change some fields in that class after it's being initialized.
But I can't find a proper way how to provide code block in #Configuration class and not using #Bean annotation. Is there an ideomatic way to do so in spring?
One way to do this:
#Configuration
class TestConfig {
#Autowired
private SomeBean someBean;
#PostConstruct
private void initSomeBean() {
// someBean.setProperty("qwe");
}
}
#PostConstruct annotation defines init-method, which is getting called after SomeBean is autowired. In this method you can adjust your bean
Do you want to import one Config in AnotherConfig on? It can be done via annotation placed on AnotherConfig:
import org.springframework.context.annotation.Import;
...
#Import(value = {Config.class})
public class AnotherConfig ... {}

what is the difference between #Bean annotation and #Component annotation at Spring?

It might be a very simple question for you.But I read lots of documents and I am totally confused.We can use #Component instead of #Bean or #Bean instead of #Component(as well as #Repository #Service #Controller) ?
Cheers
Component
#Component also for #Service and #Repository are used to auto-detect and auto-configure beans using classpath scanning.
As long as these classes are in under our base package or Spring is aware of another package to scan, a new bean will be created for each of these classes
Bean and Component are mapped as one to one i.e one bean per Class.
These annotations (#Component, #Service, #Repository) are Class level annotations.
Example:
Lets Say we have a UserService Class which contains all methods for User Operation.
#Service
public class UserService {
#Autowired
private UserRepository userRepository;
#Override
public User findByUsername( String username ) throws UsernameNotFoundException {
User u = userRepository.findByUsername( username );
return u;
}
public List<User> findAll() throws AccessDeniedException {
List<User> result = userRepository.findAll();
return result;
}
}
Spring will create a Bean for UserService and we can use this at multiple location/classes.
#Bean
#Bean is used to declare a single bean, rather than letting Spring do it automatically as in case of Component.
It decouples the declaration of the bean from the class definition, and lets you create and configure beans exactly how you choose.
#Bean are used at method level and can be configured as required
eg:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public SpringTemplateEngine springTemplateEngine()
{
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(htmlTemplateResolver());
return templateEngine;
}
#Bean
public SpringResourceTemplateResolver htmlTemplateResolver()
{
SpringResourceTemplateResolver emailTemplateResolver = new SpringResourceTemplateResolver();
emailTemplateResolver.setPrefix("classpath:/static/template/");
emailTemplateResolver.setSuffix(".html");
emailTemplateResolver.setTemplateMode("HTML");
emailTemplateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name());
return emailTemplateResolver;
}
...
Read more about Stereotype Annotations here.
#Bean is used to define a method as a producer, which tells Spring to use that method to retrieve an object of the method return type and inject that object as a dependency whenever it's required.
#Component is used to define a class as a Spring component, which tells Spring to create an object (if it's Singleton) from and take care of it's lifecycle and dependencies and inject that object whenever it's required.
#Service and #Repository are basically just like #Component and AFAIK they are just for better grouping of your components.
#Service for Defining your service classes where you have your business logic, and #Repository for Defining your repository classes where you interact with an underlying system like database.
#Component
If we mark a class with #Component or one of the other Stereotype annotations these classes will be auto-detected using classpath scanning. As long as these classes are in under our base package or Spring is aware of another package to scan, a new bean will be created for each of these classes.
package com.beanvscomponent.controller;
import org.springframework.stereotype.Controller;
#Controller
public class HomeController {
public String home(){
return "Hello, World!";
}
}
There's an implicit one-to-one mapping between the annotated class and the bean (i.e. one bean per class). Control of wiring is quite limited with this approach since it's purely declarative. It is also important to note that the stereotype annotations are class level annotations.
#Bean
#Bean is used to explicitly declare a single bean, rather than letting Spring do it automatically like we did with #Controller. It decouples the declaration of the bean from the class definition and lets you create and configure beans exactly how you choose. With #Bean you aren't placing this annotation at the class level. If you tried to do that you would get an invalid type error. The #Bean documentation defines it as:
Indicates that a method produces a bean to be managed by the Spring container.
Typically, #Bean methods are declared within #Configuration classes.We have a user class that we needed to instantiate and then create a bean using that instance. This is where I said earlier that we have a little more control over how the bean is defined.
package com.beanvscomponent;
public class User {
private String first;
private String last;
public User(String first, String last) {
this.first = first;
this.last = last;
}
}
As i mentioned earlier #Bean methods should be declared within #Configuration classes.
package com.beanvscomponent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class ApplicationConfig {
#Bean
public User superUser() {
return new User("Partho","Bappy");
}
}
The name of the method is actually going to be the name of our bean. If we pull up the /beans endpoint in the actuator we can see the bean defined.
{
"beans": "superUser",
"aliases": [],
"scope": "singleton",
"type": "com.beanvscomponent.User",
"resource": "class path resource
[com/beanvscomponent/ApplicationConfig.class]",
"dependencies": []
}
#Component vs #Bean
I hope that cleared up some things on when to use #Component and when to use #Bean. It can be a little confusing but as you start to write more applications it will become pretty natural.

Make a third party class a service

I'm a beginner at Spring and beginning to understand how beans work. I want to declare a 3rd party class as a Service or a Bean. How do I do this? Should I just extend the class and annotate that?
example:
#Service
public class MyService { public MyService(ThirdPartyClass thirdPartyClass){..}....}
Here I cannot annotate ThirdPartyClass as a Service or otherwise
If your aren't the owner of the class that you would like to use as a bean, you can create the bean declaration in one of application's configuration classes:
#Configuration
public class YourConfig {
#Bean
public ThirdPartyClass thirdPartyClass() {
return new ThirdPartyClass();
}
}
Spring will instantiate an appropriate object based on that description and expose it via container to other beans.
You can add the class which is out of your control as #Bean
#Configuration
public class ApplicationConfig {
#Bean
public ClassName methodName() {
return new ClassName();
}
}
At the time of initializing the application, spring will call this method and register ClassName object to spring context and will be made available where you #Autowired this bean.

BeanNotOfRequiredTypeException in Spring boot test runner and #Rule

I am writing an integration test using spring runner, and have created a TestRule implementation and used it through #Rule. But I try to create a bean of that implementation, I get BeanNotOfRequiredTypeException.
Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'localDynamoDB' is expected to be of type 'com.wickes.dynamo.local.LocalDynamodb' but was actually of type 'com.sun.proxy.$Proxy114'
My test class is:
#ComponentScan(basePackages = "com.wickes.stock")
#Configuration
public class TestConfig {
#Bean
public LocalDynamodb localDynamoDB() {
return new LocalDynamodb();
}
}
#RunWith(SpringRunner.class)
#SpringBootTest(classes = TestConfig.class)
public class StockListenerTest {
#Rule
#Autowired
public LocalDynamodb localDynamodb;
#Test
public void test() {
}
}
and my config is:
My LocalDynamodb is
public class LocalDynamodb extends ExternalResource {
}
M. Deinum is correct: LocalDynamodb is being proxied by interfaces, which you do not want.
Thus, you have two options:
Convert LocalDynamodb to an interface, implement the interface, and register the implementation as the bean.
Switch from dynamic interface-based proxies (the default) to class-based proxies. How you perform the switch depends on how the proxies are being created, but since we can't see the rest of your Spring configuration we don't know how to advise you there.
Regards,
Sam (author of the Spring TestContext Framework)
I had a similar problem when trying to inject an AspectJ proxied object, then I found that you can add the #Scope annotation to LocalDynamodb:
#Component
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ...
More details here

Resources