Autowire a bean requiring another bean for its object creation - java

I have a class which has following autowiring
public class XYZ {
#Autowired
private Principal principal;
public void main() {
AlexandriaDownloadSignatureUtilityV1 downloadSignatureUtilV1 =
new AlexandriaDownloadSignatureUtilityV1(
getMaterialsetNameProvider(principal),
);
}
}
I want to autowire AlexandriaDownloadSignatureUtilityV1 dependency, but since it is dependent on pricipal bean, can you please tell me how to do so?

#Component
public class XYZ {
#Autowired
private Principal principal;
public void main() {
AlexandriaDownloadSignatureUtilityV1 downloadSignatureUtilV1 =
new AlexandriaDownloadSignatureUtilityV1(
getMaterialsetNameProvider(principal),
);
}
}
Add #Component at the Top of the class this will create a bean of this object and inject their dependency also

Related

Getting NoSuchBeanDefinitionException while injecting bean dependency through constructor

I am trying to inject a configuration bean into my Service. For this i created a separate class EncryptionProps
public class EncryptionProps {
#Getter
#Setter
#Value("${kafka.properties.security.keyreuseinterval}")
private long keyReuseInterval;
}
Then, i am creating another config class to register this as a bean
#Configuration
public class EncryptionConfig {
#Bean
public EncryptionProps encryptionProps() {
return new EncryptionProps();
}}
And this is how, i am calling this in my service class:
#Service
public class EncryptionService {
private final long keyReuseInterval;
//some more declarations
#Autowired
public EncryptionService(SchemaProcessor schemaProcessor, CryptoLib crypto, EncryptionProps encryptionProps) {
this.schemaProcessor = Preconditions.checkNotNull(schemaProcessor, "schemaProcessor cannot be null.");
this.crypto = Preconditions.checkNotNull(crypto, "CryptoLib must be provided");
this.keyReuseInterval = encryptionProps.getKeyReuseInterval();
}
However, when i run this, i am getting the following error - org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.sinkad.kafka.util.EncryptionProps' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I am stuck on this since last day. I have tried tons of stackoverflow questions on this, but none helped so far. Can anybody please help me in why Spring is not finding this bean. I even tried adding #ComponentScan over the EncryptionConfig class. But that also didn't worked. Or if you can just point me to some resource related to it.
Thanks!
UPDATE:
Here is my main class:
package com.example.sinkad;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}}
Try like below:
#Component
class EncryptionProps {
final String keyreuseinterval;
// Use #Autowired to get #Value to work.
#Autowired
EncryptionProps(
#Value("${kafka.properties.security.keyreuseinterval}") final String keyreuseinterval) {
this.keyreuseinterval = keyreuseinterval;
}
}
I was finally able to solve this issue with a team member's help. I am still not sure what was the issue, But here's what we did:
1) Moved the keyReuseInterval value to another config class, which will create the object for EncryptionProps object
public class EncryptionProps {
#Getter
#Setter
private long keyReuseInterval;
}
Here 's the config class
#Configuration
public class CryptoConfig {
#Value("${kafka.properties.security.keyreuseinterval}")
private long keyReuseInterval;
#Bean
public EncryptionProps encryptionProps() {
EncryptionProps encryptionProps = new EncryptionProps();
encryptionProps.setKeyReuseInterval(keyReuseInterval);
return encryptionProps;
}
}
2) And we are calling encryptionProps in the service class similar to before:
#Autowired
public EncryptionService(SchemaProcessor schemaProcessor, CryptoLib crypto, EncryptionProps encryptionProps) {
this.schemaProcessor = Preconditions.checkNotNull(schemaProcessor, "schemaProcessor cannot be null.");
this.crypto = Preconditions.checkNotNull(crypto, "CryptoLib must be provided");
this.keyReuseInterval = encryptionProps.getKeyReuseInterval();
}
I am not sure how this fixed the issue. But thought will share it with you guys. Thanks again guys for your suggestions.

SpringBoot application doesn't autowire field

I do have ServiceImpl which looks like this:
#Service
#RequiredArgsConstructor
public class ServiceAImpl implements ServiceA {
private final String fieldA;
#Override
public boolean isFieldA(String text){
return fieldA.equals(text);
}
And I would like to inject a field value to fieldA in an Application.java from application.yml like this:
#EnableSwagger2
#SpringBootApplication
public class Application {
#Value("${fieldA}")
private String fieldA;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public ServiceA serviceA() {
return new ServiceAImpl(fieldA);
}
But I receive the following error when running SpringBoot app:
Error creating bean with name 'serviceAImpl' defined in URLNo qualifying bean of type 'java.lang.String' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Do you have any solution for that?
You annotated your class with #Service and defined it manually as a bean with the #Bean annotation. I do think the second is the way you planned to use it.
The #Service annotation will make this class get picked up by Spring's component scan and additionally create an instance of it.
Of course it tries to resolve the parameters and fails when it tries to find a matching "bean" for the String field because there is no simple String bean (and should not :) ).
Remove the #Service annotation and everything should work as expected.
Try this
#Service
public class ServiceAImpl implements ServiceA {
private final String fieldA;
#Autowire
public ServiceAImpl(#Value("${fieldA}") String fieldA){
this.fieldA = fieldA;
}
#Override
public boolean isFieldA(String text){
return fieldA.equals(text);
}
}
and this
#EnableSwagger2
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
You should not use #Service and #Bean for the same class!
Spring is not so smart :)
You should annotate your bean like:
#RequiredArgsConstructor
public class ServiceAImpl {
#Value("${fieldA}")
private final String something;
...
But I'm not sure it will work with the #RequiredFieldsConstructor, it would be simpler for you write down the constructor annotated with #Autowired and using the #Value annotation for the String parameter:
#Autowired
public ServiceAImpl(#Value("${aProp}") String string) {
You're using two bean declaration mechanisms:
You're registering your bean using #Service
You're registering a bean using #Bean
This means that your service will be created twice. The one defined using #Bean works properly, since it uses the #Value annotation to inject the proper value in your service.
However, the service created due to #Service doesn't know about the #Value annotation and will try to find any bean of type String, which it can't find, and thus it will throw the exception you're seeing.
Now, the solution is to pick either one of these. If you want to keep the #Bean configuration, you should remove the #Service annotation from ServiceAImpl and that will do the trick.
Alternatively, if you want to keep the #Service annotation, you should remove the #Bean declaration, and you should write your own constructor rather than relying on Lombok because this allows you to use the #Value annotation within the constructor:
#Service
public class ServiceAImpl implements ServiceA {
private final String fieldA;
/**
* This constructor works as well
*/
public ServiceAImpl(#Value("${fieldA}") String fieldA) {
this.fieldA = fieldA;
}
#Override
public boolean isFieldA(String text){
return fieldA.equals(text);
}
}
If you want to declare ServiceAImpl as a Spring bean in your Java Configuration file, you should remove the #Service annotation from the class declaration. These annotations doesn't work well together.
ServiceAImpl.java
import org.springframework.beans.factory.annotation.Autowired;
public class ServiceAImpl implements ServiceA {
private final String fieldA;
#Autowired
public ServiceAImpl(String fieldA) {
this.fieldA = fieldA;
}
#Override
public boolean isFieldA(String text) {
return fieldA.equals(text);
}
}
Application.java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
#SpringBootApplication
public class Application {
#Value("${fieldA}")
private String fieldA;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public ServiceA serviceA() {
return new ServiceAImpl(fieldA);
}
}
Your application.properties
fieldA=value
The below implementation works well for me. You have two issues, first you have to choose between #Service and #Bean and the other issue I've seen in your code was the #Value annotation, you have to use only to inject a value from the properties.
#SpringBootApplication
public class TestedValueApplication {
#Autowired
void printServiceInstance(ServiceA service) {
System.out.println("Service instance: " + service);
System.out.println("value==value? " + service.isFieldA("value"));
}
public static void main(String[] args) {
SpringApplication.run(TestedValueApplication.class, args);
}
#Bean
public ServiceA serviceA(#Value("${fieldA}") String fieldA) {
return new ServiceAImpl(fieldA);
}
}
Service:
public class ServiceAImpl implements ServiceA {
private String fieldA;
ServiceAImpl(String fieldA) {
this.fieldA = fieldA;
}
public boolean isFieldA(String text) {
return fieldA.equals(text);
}
}
application.properties:
fieldA=value

How to implement DI in Spring MVC.?

I have a confusion in Dependency Injection in Spring MVC.
First Code:-
#Service
#Transactional
public class UserServiceImpl implements UserService {
#Autowired
private Userdao udo;
#Override
#Transactional
public List<Positions> plist() {
return udo.plist();
}
}
It is working Fine.
I would like to implement Dependency Injection in this class.Am doing right or wrong?
second code:-
`#Service
#Transactional
public class UserServiceImpl implements UserService {
#Autowired
private Userdao udo;
public UserServiceImpl(Userdao udo) {
this.udo = udo;
}
#Override
#Transactional
public List<Positions> plist() {
return udo.plist();
}
}
Its not working.ERROR: org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'homeController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.xxx.Services.UserService com.xxx.java.HomeController.uservice; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userServiceImpl' defined in file [D:\xxxWorkspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\abcd\WEB-INF\classes\com\xxx\ServiceImp\UserServiceImpl.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.xxx.ServiceImp.UserServiceImpl]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.xxx.ServiceImp.UserServiceImpl.<init>()
I am a beginner .please help me to solve this.How to implement DI in Spring MVC.
You can do this two ways.
You can use field based autowiring. But in this case you will need a default constructor.
#Service
#Transactional
public class UserServiceImpl implements UserService {
#Autowired // field based DI
private Userdao udo;
// default constructor
public UserServiceImpl() {}
#Override
#Transactional
public List<Positions> plist() {
return udo.plist();
}
}
You can use constructor based dependency injection. To do this simply move your #Autowire annotation to your constructor. And remove it from the field.
#Service
#Transactional
public class UserServiceImpl implements UserService {
private Userdao udo;
#Autowired // constructor based DI
public UserServiceImpl(Userdao udo) {
this.udo = udo;
}
#Override
#Transactional
public List<Positions> plist() {
return udo.plist();
}
}
First setup is alright, and should work.
In the second setup you're getting following exception
class [com.xxx.ServiceImp.UserServiceImpl]: No default constructor found;
Which means what it says, since you've defined a constructor public UserServiceImpl(Userdao udo) Spring can't find an no-argument constructor.
You can either remove this constructor and use the first one or you can define the no argument constructor yourself.
You shouldn't actually need to define a constructor in a bean as you're not going to create bean object yourself. You would only need it if you're autorwiring constructor arguments.
If you're trying to autowire constructor then you can do it like below.
#Service
#Transactional
public class UserServiceImpl implements UserService {
private Userdao udo;
#Autowired //autowired constructor, instead of the field
public UserServiceImpl(Userdao udo) {
this.udo = udo;
}
#Override
#Transactional
public List<Positions> plist() {
return udo.plist();
}
}
In simple words: If you define a constructor (overloaded) then you must use the #Autowired annotation on the constructor, if you do not define a constructor, then you must use the #Autowired annotation for each Object you need to add as dependency injection. For example:
With constructor overloaded:
#Service
#Transactional
public class UserServiceImpl implements UserService {
private final Userdao userDao;
private final RoleDao roleDao;
#Autowired
public UserServiceImpl(Userdao userDao, RoleDao roleDao) {
this.userDao = userDao;
this.roleDao = roleDao;
}
}
Without constructor overloaded
#Service
#Transactional
public class UserServiceImpl implements UserService {
#Autowired
private UserDao userDao;
#Autowired
private RoleDao roleDao;
// default constructor
public UserServiceImpl() {}
}
Defining a constructor with a single #Autowired is better than having many objects #Autowired

How to extend #Service?

Here is a sample class below:
#Service("testService")
public class TestService {
public String something() {
return "abc";
}
}
I want to extend the class and let the container know that it needs to pick up my extended class from now.
#Service("extendedTestService")
public class ExtendedTestServiceMock extends TestService {
#Override
public String something() {
return "xyz";
}
}
Test class:
public class TestClass extends SpringTest {
#Autowired
#Qualifier("extendedTestService")
private ExtendedTestService testService;
public void testMethod() {
......
}
}
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [TestService] is defined: expected single matching bean but found 2: ExtendedTestServiceMock,testService
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:865) ~[spring-beans-3.2.8.RELEASE.jar:3.2.8.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:770) ~[spring-beans-3.2.8.RELEASE.jar:3.2.8.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:489) ~[spring-beans-3.2.8.RELEASE.jar:3.2.8.RELEASE]
... 91 common frames omitted
How to resolve it?
Try using interfaces.
public interface TestService {
String something();
}
Implementations:
#Service
#Qualifier("testService")
public class TestServiceImpl implements TestService { ... }
#Service
#Qualifier("testServiceMock")
public class TestServiceMockImpl implements TestService { ... }
And the test class:
public class TestClass extends SpringTest {
#Autowired
#Qualifier("extendedTestService")
private TestService testService;
...
}
One solution that would work in your case is the #Primary annotation.
Your TestServiceMockImpl would look like:
#Service("extendedTestService ")
#Primary
public class ExtendedTestServiceMock extends TestService {
#override
public String something() {
return "xyz";
}
}
Check out this for more details on #Primary
I however suggest that you don't follow the above solution (since this will get out of hand very quick if you start using #Primary everywhere), that you instead take a look at Spring Profiles
There are a lot of way you could create your Spring configuration using profiles, but regardless of how you end up configuring the beans, the end result would be a more clean design.
If you have an identifier to help you decide which service to initialize, then you can use ConditionlOnProperty annotation
Ex:
#Service
#ConditionlOnProperty(value = "test.service.extension.enabled")
public class TestService {
}
#Service
#ConditionlOnProperty(value = "test.service.extension.enabled", havingValue = "false")
public class ExtendedTestServiceMock extends TestService {
}
If you want to use the extended test service, you can set the property test.service.extension.enabled=true in your application.properties
It depends on your definition order if your service define on the xml file.
Otherwise, you could use a BeanFactoryPostProcessor to do this, which is only registered in the test scenarios that you want this mocked.
public class SystemTestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
// put your custom code in here
}
}
Or you can use #DependsOn to make sure the parent bean should be deploy firstly then your extend bean
#Service("testService")
#DependsOn("testService")
public class ExtendedTestService extends TestService {
}
Hope this helps.

#Autowire not preperly injected with Spring #Bean configuration

I am practising on spring-social and it seems that the userConnectionRepository is not properly autowired in the following code when I do a "Run as Junit Test" in Eclipse. I get a Null pointer exception on the usersConnectionRepository when creating a new FacebookOffLine although breakpoints put in the #Bean java creation code shows that they seem to be properly created. Thanks in advance,
public class FacebookOffline {
private Facebook fb;
#Autowired
private UsersConnectionRepository usersConnectionRepository;
public FacebookOffline(User user) {
super();
ConnectionRepository cr = usersConnectionRepository.createConnectionRepository(user.getId());
fb = cr.getPrimaryConnection(Facebook.class).getApi();
}
}
Here is the test code :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {
org.springframework.social.quickstart.config.MainConfig.class,
org.springframework.social.quickstart.config.SocialConfig.class })
public class FacebookOfflineTest {
#Test
public void test1() {
FacebookOffline essai = new FacebookOffline(new User("yves"));
And the Spring configuration classes adapted from Keith Donald Quick Start Sample :
#Configuration
#ComponentScan(basePackages = "org.springframework.social.quickstart", excludeFilters = { #Filter(Configuration.class) })
#PropertySource("classpath:org/springframework/social/quickstart/config/application.properties")
public class MainConfig {
#Bean
public DataSource datasource() {
DriverManagerDataSource toReturn = new DriverManagerDataSource("jdbc:mysql://localhost:3306/spring_social");
toReturn.setDriverClassName("com.mysql.jdbc.Driver");
toReturn.setUsername("spring");
toReturn.setPassword("spring");
return toReturn;
}
}
#Configuration
public class SocialConfig {
#Inject
private Environment environment;
#Inject
private DataSource dataSource;
#Bean
public ConnectionFactoryLocator connectionFactoryLocator() {
ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();
registry.addConnectionFactory(new FacebookConnectionFactory(environment
.getProperty("facebook.clientId"), environment
.getProperty("facebook.clientSecret")));
return registry;
}
#Bean
public UsersConnectionRepository usersConnectionRepository() {
JdbcUsersConnectionRepository repository = new JdbcUsersConnectionRepository(
dataSource, connectionFactoryLocator(), Encryptors.noOpText());
return repository;
}
}
Actually there are 2 problems here.
Spring cannot autowire beans it doesn't control (i.e. created with new)
Dependencies aren't available in the constructor (an object instance is needed before it can be injected)
The first one can be mitigated by letting spring manage an instance of FacebookOffline (or if you need multiple instances make the bean request or session scoped).
The second is a bit harder but can probaly solved by using a method annotated with #PostConstruct (or by implementing InitializingBean from spring).
You did
FacebookOffline essai = new FacebookOffline(new User("yves"));
That means, Spring isn't managing this essai instance and thus spring can't autowire any variables in the essai.
You'll have to create bean of FacebookOffline in SocialConfig.
Then you can have
/* ... */
public class FacebookOfflineTest {
#Autowired
ApplicationContext context;
#Test
public void test1() {
FacebookOffline essai = context.getBean(FacebookOffline.class);
OR
/* ... */
public class FacebookOfflineTest {
#Autowired
FacebookOffline essai;
#Test
public void test1() {
// You can use essai now
Also, you'll need to update FacebookOffline as Dependencies ain't available in constructor.
public class FacebookOffline {
private Facebook fb;
#Autowired
private UsersConnectionRepository usersConnectionRepository;
public FacebookOffline(User user) {
super();
}
#PostConstruct
void loadFacebook() {
ConnectionRepository cr = usersConnectionRepository.createConnectionRepository(user.getId());
fb = cr.getPrimaryConnection(Facebook.class).getApi();
}
}
Spring can't autowire fields on an instance you create via new since it doesn't know about it. Declare a bean of type FacebookOffline instead.

Categories

Resources