spring variable injection from an autowired object - java

I have a class like this -
#Service
public class SomeClass {
#Autowired
Environment env;
private String property;
#Value("${pty}")
public void setPty(String pty) {
pty = environment.getProperty("pty");
}
}
I'm trying to inject the 'pty' variable from another class 'Environment' which is autowired and I get this exception when my server startups
Error creating bean with name 'someClass': Injection of autowired
dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire method: public void
service.facade.ActionFacade.setPty(java.lang.String);
nested exception is java.lang.IllegalArgumentException: Could not
resolve placeholder 'pty' in string value "${pty}"

The exception is because there is no property pty in your Spring context. #Value lookup the placeholder 'pty' in the resource files loaded.
In your case it is not required as you need to get it from Environment class which you have Autowired already, below code will give you the idea.
#Service
public class SomeClass {
#Autowired
Environment env;
private String property;
#PostConstruct
public void init(){
property=env.getProperty("pty");
}
}

Try #PostConstruct
The PostConstruct annotation is used on a method that needs to be executed after dependency injection is done to perform any initialization.
#PostConstruct
public void init() {
property = env.getProperty("pty");
}

You can do this with the help of Spring bean life cycles:
1. InitializingBean -> afterPropertiesSet
2. #PostConstruct
public class EmployeeService implements InitializingBean{
private Employee employee;
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
#PostConstruct
public void init() {
property = env.getProperty("pty");
}
#Override
public void afterPropertiesSet() throws Exception {
}
}

Related

Autowire a bean requiring another bean for its object creation

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

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

Accessing autowired beans in multiple classes

my question is how can I access bean in class X, that is autowired in class Y?
I'm using spring boot, I have 2 controllers:
#Controller
public class OwnerController {
#Autowired
StandardDaoAction<Owner> ownerDao;
and another one
#Controller
public class VisitController {
#Autowired
StandardDaoAction<Pet> petDao;
now I need to add StandardDaoAction ownerDao bean in VisitController class, but when I use simply autowired, I get exception, because multiple beans of the same class defined and spring does not know what to do. I tried somehow to distinguish them with #Qualifier, but it did not worked or I messed up with something.
It's pretty basic question but Im stuck with it and cant find the solution
ok So I ran into conclusion that the core problem is with my implementation of dao's and interface aka something is wrong with my usage of generics:
my interface :
public interface StandardDaoAction<T> {
public T get(int id);
public void remove(int id);
public void add(T Type);
public void update(T type);
public List<T> getAll();
}
implementation of the interface by both classes:
#Repository
public class PetDaoImpl implements StandardDaoAction<Pet> {
#PersistenceContext
EntityManager em;
#Transactional
public Pet get(int id) {
return em.find(Pet.class, id);
}
#Transactional
public void remove(int id) {
em.remove(id);
}
#Transactional
public void add(Pet pet) {
em.persist(pet);
}
#Transactional
public void update(Pet pet) {
em.merge(pet);
}
#SuppressWarnings("unchecked")
#Transactional
public List<Pet> getAll() {
return em.createQuery("from Pet").getResultList();
}
}
#Repository
public class OwnerDaoImpl implements StandardDaoAction<Owner> {
#PersistenceContext
EntityManager em;
#Transactional
public Owner get(int id) {
return em.find(Owner.class, id);
}
#Transactional
public void remove(int id) {
em.remove(get(id));
}
#Transactional
public void add(Owner owner) {
em.persist(owner);
}
#Transactional
public void update(Owner owner) {
em.merge(owner);
}
#SuppressWarnings("unchecked")
#Transactional
public List<Owner> getAll() {
return em.createQuery("From Owner").getResultList();
}
}
when I add:
#Controller
public class VisitController {
#Autowired
StandardDaoAction<Pet> petDao;
#Autowired
StandardDaoAction<Owner> ownerDao;
this is the error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'visitController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: pl.kaczynski.dao.StandardDaoAction pl.kaczynski.controller.VisitController.ownerDao; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [pl.kaczynski.dao.StandardDaoAction] is defined: expected single matching bean but found 3: ownerDaoImpl,petDaoImpl,vetDaoImpl
there is also vetDaoImpl because there is another controller:
#Controller
public class VetListController {
#Autowired
StandardDaoAction<Vet> vetDao;
which also implements the interface, as you can see above.
so As long as I have one bean that implements StandardDaoActions interface , it's working because it goes autowired by type, but when I add another autowired bean in different controller , the error occurs.
Because of type erasure you will have two beans of type StandardDaoAction.
inject either by the concrete type as #Autowired private PetDaoImpl petDao
or use #Autowired #Qualifier("petDaoImpl") private StandardDaoAction<Pet> petDao

#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