How to create dynamic beans which have only a constructor with args - spring

I have a bean with final field.
public class Foo {
Service service;
final String bar;
public Foo(String bar){};
}
service is not final and has a setter. bar is final and can have many values. I cannot remove the final keyword. I try to create a spring factory that allows to create Foo's instances with injected service and dynamic bar value. factory.create(bar). Foo beans are instanciated at runtime because bar value is not known and unbounded
I have try:
#Configuration, but configuration does not allow parameters not managed by spring or dynamic parameter.
Lookup method needs a no-arg constructor.
Any idea ?
Thanks!

Take a look at ApplicationContext.getBean(String name, Object... args) method. You can pass arguments to bean creation with args parameter.

You can use constructor injection in the Application Context XML as one way to do this:
<bean name="foo" class="com.example.Foo">
<constructor-arg index="0">Bar</constructor-arg>
</bean>
EDIT: Missed that, check out this question: How to use #Autowired in spring
The second answer (not by me)
It looks like you might be able to use #Configurable annotation here.

Related

Spring: Using #Qualifier with Property Placeholder

I am trying to use a property placeholder as the attribute for #Qualifier, as follows:
#Autowired
#Qualifier("${beanName}")
private MyBean myBean;
However, this does not work, even though the property placeholder is available as a String value:
#Value("${beanName}")
private String beanName;
What would be a good workaround here, thanks very much.
I encountered exactly same issue. Just use Resource
#Resource(name="${beanName}")
private MyBean myBean;
I can't leave a comment so this is my answer:
As Adam B said maybe you can use spring profiles to achieve the result you are aiming to (wich result are you aiming?).
Another thing you can do is:
configure a map (using the spring util namespace) in your xml context configuration like this:
<util:map id="mapId" key-type="java.lang.String" value-type="com.xxx.interface-or-superclass">
<beans:entry key="${property.bean.name.1}" value-ref="bean1-defined-elsewehere"/>
<beans:entry key="${property.bean.name.2}" value-ref="bean2-defined-elsewehere"/>
<beans:entry key="${property.bean.name.3}" value-ref="bean3-defined-elsewehere"/>
</util:map>
then you can load this map in a bean called eg. "com.xxx.BeanSelector"
#Value("#{mapId}")
private Map<String, com.xxx.interface-or-superclass> myMap;
and add to this bean a methos like this:
public interface-or-superclass getBean(String beanName){
return myMap.get(beanName);
}
ok now you can have your final class similar to this:
#Autowired
private BeanSelector beanSelector;
#Value("${property.name.the.bean.you.want.to.use}")
private String beanName;
private interface-or-superclass myBean;
then you can istantiate myBean (maybe inside the method afterPropertiesSet() if you are implementing the interface InitializingBean)
in this way:
myBean = beanSelector.getBean(beanName);
// then check ifthe bean is not null or something like that
Ok it's a little messy and maybe you can act in a different way based on what you want achieve, but it's a workaround.
Just a try (don't really known the problem to solve) . You can use fixed bean name as usual (autowire with placeholder is not supported) but you can load different bean implementation from different xml based on property value.
.
Else think about a solution based on bean alias.
My 2 cents

Spring configuration calling more than one method

I have code which looks like the following:
MyContext context = new MyContext();
context.start();
MyEntity entity = context.getEntity();
I want to inject the MyEntity instance into various classes.
But I don't know how to setup my Spring configuration, where I first create an object, then call a method on it and then finally call another method which returns the entity I want to inject.
EDIT 2 - removed the Strings altogether
The most common type of dependencies injected using Spring don't depend on the user input for their construction. This includes data access objects, services etc.,
You are talking about injecting domain objects whose construction depends on the user input either directly or indirectly.
Spring provides #Configurable annotation to inject such domain objects that are created using new operator. You can search for "#Configurable Domain Driven Design" on the internet to get examples of how this can be implemented. I myself used it in one my applications and wrote a simple post here that might help you get started.
Edit:
To create a bean of type MyEntity as per the specification in your updated question, you would need to
define a bean of type MyContext
Create a MyEntityFactory class that would depend on the MyContext bean.
The factory method would take the MyContext bean as argument, calls context.start() on it and returns an instance of MyEntity.
You would define the MyEntity bean using this factory class.
The MyEntityFactory class would be as follows:
public class MyEntityFactory
{
public static MyEntity getMyEntity(MyContext context)
{
context.start();
return context.getEntity();
}
}
The spring bean configuration will be as follows:
<bean id="myContext" class="FQCN.Of.MyContext" />
<bean id="myEntity" class="FQCN.Of.MyEntityFactory" factory-method="getMyEntity">
<constructor-arg ref="myContext" />
</bean>
Since MyEntity is a singleton bean, the factory method will be called only once, btw.
More on creating beans using factory methods here.

How do I get a property value from an ApplicationContext object? (not using an annotation)

If I have:
#Autowired private ApplicationContext ctx;
I can get beans and resources by using one of the the getBean methods. However, I can't figure out how to get property values.
Obviously, I can create a new bean which has an #Value property like:
private #Value("${someProp}") String somePropValue;
What method do I call on the ApplicationContext object to get that value without autowiring a bean?
I usually use the #Value, but there is a situation where the SPeL expression needs to be dynamic, so I can't just use an annotation.
In the case where SPeL expression needs to be dynamic, get the property value manually:
somePropValue = ctx.getEnvironment().getProperty("someProp");
If you are stuck on Spring pre 3.1, you can use
somePropValue = ctx.getBeanFactory().resolveEmbeddedValue("${someProp}");
Assuming that the ${someProp} property comes from a PropertyPlaceHolderConfigurer, that makes things difficult. The PropertyPlaceholderConfigurer is a BeanFactoryPostProcessor and as such only available at container startup time. So the properties are not available to a bean at runtime.
A solution would be to create some sort of a value holder bean that you initialize with the property / properties you need.
#Component
public class PropertyHolder{
#Value("${props.foo}") private String foo;
#Value("${props.bar}") private String bar;
// + getter methods
}
Now inject this PropertyHolder wherever you need the properties and access the properties through the getter methods

Inject Dynamic Values for the property in Spring

I am very new to Spring and while going through the DI topic through various sources (Book & Internet) I have seen the following pattern of defining bean configuration:
For example we have a class "SampleApp"
public class SampleApp
{
private int intValue;
private float floatValue;
public SampleApp(int value)
{
intValue = value;
}
public void setIntValue(int value)
{
intValue = value;
}
public void setFloatValue(float floatValue)
{
this.floatValue = floatValue;
}
}
Corresponding bean configuration is as follows:
<bean class="somepackage.SampleApp" id="samplebeanapp">
<constructor-arg value="15" />
<property value="0.5" name="floatValue"></property>
</bean>
We have been hard-coding the value here to 15 & 0.5.
Here are my questions :
Is it possible to pass those values as run time parameter with scope as prototype?
If yes, how can we do it? and please elaborate with some example.
Spring configuration files are processed at startup, and Spring singleton beans are instantiated too in that moment. They are not processed again during the application lifecycle, in normal conditions.
You can use such type of property injection to pass configuration values, while you can use injection of object references to determine the structure of your application.
To avoid hardcoding the values inside the XML files, you can extract them in property files using a PropertyPlaceholderConfigurer.
The principle is to program to interfaces as much as possible, so you don't tie yourself to any specific implementation. However, for the case you're thinking, you'll just pass the values at runtime.
Example: BeanA needs the services of DaoBean, but the DaoBean won't be instantiated by BeanA. It will be passed to BeanA through dependency injection and BeanA will only talk to a DaoInterface.
At this point if BeanA want to save 15 and 0.5, will call the methods with the actual values (or more commonly variables).
daoInterface.saveInt(15);
daoInterface.saveFloat(0.5);
I don't use dependency injection to pass the values in this case. Dependency injection is a great tool, but doesn't meant that it has to be used everywhere.

How to inject a value to bean constructor using annotations

My spring bean have a constructor with an unique mandatory argument, and I managed to initialize it with the xml configuration :
<bean name="interfaceParameters#ota" class="com.company.core.DefaultInterfaceParameters">
<constructor-arg>
<value>OTA</value>
</constructor-arg>
</bean>
Then I use this bean like this and it works well.
#Resource(name = "interfaceParameters#ota")
private InterfaceParameters interfaceParameters;
But I would like to specify the contructor arg value with the annocations, something like
#Resource(name = "interfaceParameters#ota")
#contructorArg("ota") // I know it doesn't exists!
private InterfaceParameters interfaceParameters;
Is this possible ?
Thanks in advance
First, you have to specify the constructor arg in your bean definition, and not in your injection points. Then, you can utilize spring's #Value annotation (spring 3.0)
#Component
public class DefaultInterfaceParameters {
#Inject
public DefaultInterfaceParameters(#Value("${some.property}") String value) {
// assign to a field.
}
}
This is also encouraged as Spring advises constructor injection over field injection.
As far as I see the problem, this might not suit you, since you appear to define multiple beans of the same class, named differently. For that you cannot use annotations, you have to define these in XML.
However I do not think it is such a good idea to have these different beans. You'd better use only the string values. But I cannot give more information, because I dont know your exact classes.
As Bozho said, instead of constructor arg you could set the property...#PostConstruct will only get called after all the properties are set...so, you will still have your string available ...

Resources