Dynamic injection of bean properties spring - java

So my problem is, I have a bean which I would like to inject dynamically based on runtime values. Lets say I have class A which has private variable B. I would like to inject my variable B (upon creation of the bean) via spring with value I got from user (for example). How can I do that ? Should I just use getBean() and then use setter method for my variable or is there any better way ?
EDIT:
#Bean
class A {
private int B;
...
}
main {
context = someContext("myConfigFileWhereBeansAreDefined");
int value = getIntFromUser();
// I want to have myNewBean injected with "value" i got from user
A myNewBean = context.getBean("A");
}

Related

How to manage Spring #Value parameters' constuctor injection when explicitly instantiating a new bean?

I have my JWT utils class:
#Component
public class JwtUtils {
private final String jwtSecret;
private final int jwtExpirationMs;
public JwtUtils(#Value("${app.jwtSecret}") String jwtSecret, #Value("${app.jwtExpirationMs}") String jwtExpirationMs)){
this.jwtSecret = jwtSecret;
this.jwtExpirationMs = jwtExpirationMs;
}
...
}
and inside my WebTokenConfig I need to initialize it for my AuthTokenFilter:
#Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter(new JwtUtils(..., ...), ...);
}
So basically, JwtUtils needs 2 parameters, but those parameters should be set from properties' context. How to handle the constructor's injection?
Plus, I'm trying to test JwtUtils class with a junit test with mockito.
Using #Autowired on fields (and not on constructor) and then instantiating the bean with new JwtUtils(), those parameters are not being init'd, staying null and 0 (even with #TestPropertySource, System.setProperties, ...). That's why I'm trying with constructor injection (which as I read is always the best option). This way I just have to pass the parameters through the new JwtUtils() and that's it.
But when done inside other beans (no test), it just makes no sense to me to pass them since they should be retrieved from context and not be passed.
I'm probably missing something.

How to handle #Autowire object in its parent classes?

I know similar questions have been asked so many times here before, but I am still confused by the mechanisms.
Here is my problem. There is a null pointer exception coming from the CategoryDAO object in the CategoryService.
#Service
public class CategoryService {
#Autowired
private CategoryDAO categoryDAO;
public List<Category> list(){
List<Category> categories = categoryDAO.list();
for (Category category : categories){
List<Record> rs = recordDAO.list(category.getID());
category.setRecordNumber(rs.size());
}
return categories;
}
public void add(String name){
Category newCategory = new Category();
newCategory.setName(name);
categoryDAO.add(newCategory);
}
}
#Repository
public class CategoryDAO {
#Autowired
private SqlSessionFactory sqlSessionFactory;
public int getTotal(){
SqlSession sqlSession = sqlSessionFactory.openSession();
List<Category> categories = sqlSession.selectList("category.selectAll");
return categories.size();
}
}
In this top rated post and this one, both of the top answers mentioned that The most preferable option is to let Spring autowire all of your beans.
Does it mean I have to also autowire the CategoryService in other classes once I need it? Which means I cannot use new operator to initialise a class if it contains autowired object?
If yes, could you please explain the reason behind it?
Thanks
UPDATE
Here is an example about using the autowired class CategoryService:
public class RecordListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
RecordPanel panel = RecordPanel.getInstance();
if (new CategoryService().list().size() == 0){
JOptionPane.showMessageDialog(panel, "NO category is recorded, set category first");
MainPanel.getInstance().getPanel().display(CategoryPanel.getInstance());
return;
}
}
The CategoryService is used in new CategoryService().list().size() == 0. If I autowire it as a property of this class here then this class will also need to be injected once I need it. I would like to avoid that so things could be easier. How can I achieve that?
Does it mean I have to also autowire the CategoryService in other classes once I need it?
Yes.
Which means I cannot use new operator to initialise a class if it contains autowired object?
Yes.
The #Autowire annotation enables you to use Dependency Injection. A technique (or good practice, actually) that makes it easy to change the implementations you use for your interfaces in your application. You define beans/component/services that will get injected whenever you use the #Autowire annotation over an attribute or a constructor parameter.
Instead of using new all over your code you just declare which concrete class should be used for an interface (or maybe the class itself) annotated with #Autowire.
Imagine you create an interface RemoteAccess and an implementation FtpRemoteAccess and then every time you need it you write RemoteAccess remoteAccess = new FtpRemoteAccess();
After a while you might end up with that line over several places. Now, if you need to change this to HttpRemoteAccess because you have this new, better alternative, you have to review all your code base. Instead, if you used dependency injection you would just change the bean (there is more than one way to do that using Spring).
For all this to work, Spring must be able to inject all the dependencies of a bean. If you create a bean, all its attributes must be injected too because Spring will create that object for you.
Clarification:
Inside your bean (namely, you classes that will be injected) you can create objects using new provided that makes sense and those object are not injected types. You are already doing that in CategoryService::add() and it is ok. Dependency injection doesn't mean you will not ever write new again. You will just avoid it for objects that will be managed by Spring dependency injection.
Then, there are other good practices that disencourage using new like the static factory method that recommend putting a static method in your class to build complete objects and letting the constructor to be private. But you don't need to apply all the patterns all the time.
UPDATE:
For your RecordListener class you have to add a CategoryService attribute and then be sure it is initialized. There are two options: you can convert RecordListener in a bean itself and have it autowired where you need that. This way Spring will construct a RecordListener object for injecting it and will also add any other bean that is needed (like CategoryService)
#Component
public class RecordListener implements ActionListener {
#Autowire
private CategoryService categoryService;
#Override
public void actionPerformed(ActionEvent e) {
RecordPanel panel = RecordPanel.getInstance();
if (categoryService.list().size() == 0) {
JOptionPane.showMessageDialog(panel, "NO category is recorded, set category first");
MainPanel.getInstance().getPanel().display(CategoryPanel.getInstance());
return;
}
}
}
The other option is you inject CategoryService in the class that is currently creating the RecordListener and then pass it as constructor argument. In that case RecordListener will not be a bean.

How to pass a value from a #ApplicationScoped to a #ViewScoped?

When trying to pass the value I receive this error:
javax.servlet.ServletException: javax.servlet.ServletException: Unable to >create managed bean createController. The following problems were found:
Property configMB for managed bean createController does not exist. Check that appropriate getter and/or setter methods exist.
The scope of the object referenced by expression #{configMB}, request, is shorter than the referring managed beans (createController) scope of view at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:138)
Is it possible to pass a value from #ApplicationScoped to #ViewScoped?
You can inject long-life beans into short-life beans. (Not vice versa)
#ApplicationScoped
public class AppBean {
private Object someValue;
//getters
}
#ViewScoped
public class ViewBean {
#Inject
private AppBean appBean;
public void sendForm() {
Object value = appBean.getSomeValue();
// do things...
}
}

Autowire Spring Bean based on boolean variable

I want to configure the spring beans in such a way that depending on the value of a boolean variable, one of the two available connection bean gets autowired in the code.
Below is the initialization of the boolean variable:
//This is overridden as false from the properties file on the server.
#Value(value = "${my.property.connectionOne:true}")
private boolean connectionOne;
I have defined the Bean in such a way:
#Bean(name = "specificConnection")
public Destination getSpecificConnection() throws Exception {
if (connectionOne) { //boolean variable
return new ConnectionOne("DB");
}
else {
return new ConnectionTwo("XML");
}
}
where ConnectionOne and ConnectionTwo both implement Destination
And I am using the bean in the desired class as:
#Autowired
#Qualifier(value = "specificConnection")
private Destination specificConnection;
However, it doesn't seem to work. It keeps returning ConnectionOne only even if I change the value of the boolean variable to false.
I am using Spring version 4.2.0 and Wildfly Server.
Please let me know if any further clarification is required.
I want to configure the spring beans in such a way that depending on
the value of a boolean variable
The boolean variable has to be valued before the initialization of the specificConnection bean by Spring.
So what you should probably do is using a value expression.
#Value("${isConnectionOne}") // looks the value in the available placeholder
private boolean isConnectionOne;
#Bean(name = "specificConnection")
public Destination getSpecificConnection() throws Exception {
if (connectionOne) { //boolean variable
return new ConnectionOne("DB");
}
else {
return new ConnectionTwo("XML");
}
}
This is a perfect example for spring profiles! Have a look on this link:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html
In Spring, you can define different profiles your program will run in. Based on settings you define in your application.properties your program will use different beans of these profiles. :)
I hope that could help you!
Greethings
Noixes

Spring #Configuration #Bean - How can I get more context information for bean creation?

I'd like to create a bean based on "which instance of which class the field belongs to (or even, just to which class this field belongs to). Something like:
#Configuration
#ComponentScan
public class MyConfiguration {
#Bean
SomeClass getTheRightInstance(SomeContext someContext) {
if(someContext.getinjectedFieldHostInstance.getId() == 7) {
return new SpecificSomeClassImplForId7();
} else {
return new SomeClass();
}
}
Bean is to be injected into following field:
public class A {
private int final id;
#Inject private SomeClass field;
int getId();
public A() {
id = SerialIdGenerator.getNextID();
}
}
Select bean injected into A's field based on A instance's id
public staitc void main(String[] args) {
A a1 = new A(); // has id '1', gets field injected with SimpleClass
A a2 = new A(); // has id '2', gets field injected with SimpleClass
...
A a7 = new A(); // gets field injected with SpecificSomeClassImplForId7
...
A last= new A(); // has id!=7, gets field injected with SimpleClass
}
The general idea is to have the decision as to which implementation to inject to which field in which class be defined in code.
Can I inject different bean instances to the same field of different instances of the same class? How can you configure it through code?
The bean you define is a Singleton, so its created at Context-Initialization before the app know that anyone might autowire the value. You must create the Bean as Prototype to request the instance on autowire only.
This is still not possible to get infos about the autowire-target. You can use *Aware-interfaces to get
very own unique Beanname
Beanfactory
ApplicationContext
But neither the target of the autowire nor the class of the target.
Notice that: if the autowire-field has been marked as #Lazy and the Bean's scope is Prototype you can elaborate the exact time the bean autowires using the bean's #PostConstruct.
I'm not sure why you want to do that but it seems like a bad idea.
Classes should never configure their behaviour around their caller, it leads to code that is tightly coupled and not very portable.
Instead, you should find out what makes those 2 fields different and refactor them to use 2 different interfaces (which may even have a common super interface in case of shared functionality). Then you can easily provide 2 different implementations for those interfaces. In your case you could also write a class that handles the specific case for id == 7 and the other cases (maybe via delegation) and use another way of configuring the instance either after or while injecting it into A.
I'm not aware of any possibility to do what you want directly.
Edit: After discussing a bit further in the comments and understanding more what you want to accomplish I think having one factory to create A instances would be best:
#Service
class AFactory {
#Autowired
private SpecificSomeClassImplForId7 specificSomeClassImplForId7;
#Autowired
private SomeClass someClass;
public A makeA() {
if(isSpecialA()) {
return new A(specificSomeClassImplForId7);
} else {
return new A(someClass);
}
}
Then you can use this factory in other Spring Beans in your Application to make As.

Categories