How do I specify a constructor argument that is not a primitive value (or a simple type like a String) but still a class part of the Java library in the XML configuration file ?
The XML works so far for me for simple values, e.g.
<bean id="foo" class="app.model.provider.IFoo">
<constructor-arg name="bar" value="baz"/>
</bean>
How do I define a dependency that requires e.g. a java.time.Instant instance in its constructor?
Spring allows you to use factory methods to get instances.
Say you wanted to do the equivalent of
Instant.now();
you would use
<bean id="anInstant" class="java.time.Instant" factory-method="now"/>
If you want to do
Instant.parse("2015-07-24T17:10:00Z")
you would use
<bean id="anInstant" class="java.time.Instant" factory-method="parse">
<constructor-arg value="2015-07-24T17:10:00Z" />
</bean>
However, I wouldn't create accessible Instant beans. If you need to pass them to some other bean's constructor, provide them directly, without names
<bean id="example" class="com.example.Example">
<constructor-arg name="startTime">
<bean class="java.time.Instant" factory-method="parse">
<constructor-arg value="2015-07-24T17:10:00Z" />
</bean>
</constructor-arg>
</bean>
Related
I'm beginner with spring framework, and I'm following this tutorial to applicate DI via setter. All works fine, but I'd like add to my class CsvOutputGenerator a constructor with one dynamic parameter, passed on the fly while I getting bean from Application context.
How can I do that?
I've already change my spring configuration in this way:
...
<bean id="CsvOutputGenerator" class="com.mkyong.output.impl.CsvOutputGenerator">
<constructor-arg type="java.lang.String" value="Test"/>
</bean>
...
but in this way is static value for my constructor.
You can pass it via system property for example
<constructor-arg lazy-init="true" type="java.lang.String" value="#{ systemProperties['some.key']}"/>
Try something else, even though Spring isn't made to be used like this (note the "prototype" scope):
<bean id="CsvOutputGenerator" class="com.mkyong.output.impl.CsvOutputGenerator" scope="prototype" />
And then in your code you can do something like this:
CsvOutputGenerator myBean = (CsvOutputGenerator) context.getBean("CsvOutputGenerator", "testing testing");
This is the method in the API that I used above.
The below content is based on the above question and comments.
Say u have a class URLRepo with attribute String url. url is initialized to value.
Then you can do something like this, to wire your CsvOutputGenerator
public class URLRepo {
private String url = "your value";
getters and setters
}
<bean id="urlRepo" class="com.*.*.MyURLRepo"/>
<bean id="CsvOutputGenerator" class="com.mkyong.output.impl.CsvOutputGenerator">
<constructor-arg type="java.lang.String" value="urlRepo.url"/>
</bean>
hope this is what you are looking for.
I have the following construct Spring XML (Spring 3.1):
<bean id="taskRunner" abstract="true" init-method="startThreads"
class="my.class.TaskRunner" />
...
<bean id="taskRunnerA" parent="taskRunner">
<constructor-arg name="foo">...</constructor-arg>
<property name="bar">...</property>
</bean>
And I am trying to separate out the init method into a higher level abstract bean:
<bean id="taskRunnerLauncher" abstract="true" init-method="startThreads" />
<bean id="taskRunner" abstract="true" depends-on="taskRunnerLauncher"
class="my.class.TaskRunner" />
...
<bean id="taskRunnerA" parent="taskRunner">
<constructor-arg name="foo">...</constructor-arg>
<property name="bar">...</property>
</bean>
Somehow this does not work, i.e. startThreads() is never invoked in the second case. Does anybody know why? Does Spring support nested abstract beans?
My idea for doing this is so I can override "taskRunnerLauncher" in unit tests and set it to "mock" or "java.lang.Object" and suppress startThreads() call (which starts new thread and making it a pain to test).
Does anybody know why?
The taskRunnerLauncher bean is set to be abstract. This means it will only act as a template for other beans. Spring will not actually create a bean for it. Therefore there won't be any invocation of startThreads because there is nothing to invoke it on.
Found the problem. I mistakenly used depends-on instead of parent attribute on taskRunner bean.
I have a generic type that I am injecting into a service. Because of the way generics are implemented in Java, I need to have a constructor arg (or property setter) that holds the Class information of the generic type parameter.
My question is -- Can I, via property injection or specifying a constructor arg, pass in an instance of Class with spring?
I DO know the type of T before run time so I know specifically what the Type parameter will be.
I was thinking it would look something like this:
<bean id="dataMartService" class="com.someclass">
<constructor-arg value="java.lang.class<com.someotherclass>" />
</bean>
Am I completely off in how this should happen?
Try:
<bean id="dataMartService" class="com.someClass">
<constructor-arg>
<value type="java.lang.Class">someotherclass</value>
</constructor-arg>
</bean>
Use spring el:
<constructor-arg value="#{ T(java.lang.Math) }" />
(you'll need spring 3.0 for this)
That being said, if you pass a string into an argument where a class is expected during a property set, spring should automatically convert it, though i'm not sure how this works when matching constructors. The above approach is much more concise.
You can use:
//for constructor
public CheckSpell(SpellCheker spellCheker){
this.spellCheker=spellCheker;
}
//Use object reference as bean
<bean id="textEditor" class="com.sring.spellCheck">
<constructor-arg ref="spellChecker"/>
</bean>
<bean id="spellCheker" class="com.spring.SpellCheker"/>
How do I inject a String into a class. I Have seen plenty of examples of how to inject a class but can't find any for a String.
An example: If your field is called "name" and your class is called "Person" you can use setter injection like this:
<bean id="personBean" class="example.Person">
<property name="name" value="Paul" />
</bean>
It should be as simple as that. You will obviously need setter methods in your Person class for name.
Let Spring know where to find your properties file (in this case myProperties.properties):
<!-- Spring will replace ${} keys with values from the file used by the propertyConfigurer -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="location" value="classpath:myProperties.properties"/>
</bean>
In your class, you can inject like this:
#Value("${web.theme}")
private String theme;
In this case, the property defined bye "web.theme" in myProperties.properties will be injected into the "theme" member variable. But you can also inject in the constructor or setter as well.
If you don't want to use annotations, you can use it in your xml file as well.
I am trying to write a ValidatorFactory which will give me a validator based on its type
public Validator getNewValidator(ValidatorType type){
switch:
case a : new Validator1();
break;
case b : new Validator2();
break;
}
I want to write using spring xml beans definition
I can use method injection but it will let me create only one object and the method does
not take any arguments.
I don't want to use FactoryBean.. I am just looking whether we can do this using spring xml
bean definition.
you can do conditional bean injection with plain xml. The "ref" attribute can be triggered by property values from a property file and thus create conditional beans depending on property values. This feature is not documented but it works perfect.
<bean id="validatorFactory" class="ValidatorFactory">
<property name="validator" ref="${validatorType}" />
</bean>
<bean id="validatorTypeOne" class="Validator1" lazy-init="true" />
<bean id="validatorTypeTwo" class="Validator2" lazy-init="true" />
And the content of the property file would be:
validatorType=validatorTypeOne
To use the property file in your xml just add this context to the top of your spring config
<context:property-placeholder location="classpath:app.properties" />
For complex cases (more complex than the one exposed), Spring JavaConfig could be your friend.
If you are using annotation (#Autowired, #Qualifier etc) instead of xml, you are not able to make conditional beans work (at least at current version 3). This is due to #Qualifier does not support expression
#Qualifier(value="${validatorType}")
More information is at https://stackoverflow.com/a/7813228/418439
I had an slightly different requirements. In my case I wanted to have encoded password in production but plain text in development. Also, I didn't have access to parent bean parentEncoder. This is how I managed to achieve that:
<bean id="plainTextPassword" class="org.springframework.security.authentication.encoding.PlaintextPasswordEncoder"/>
<bean id="shaPassword" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
<constructor-arg type="int" value="256"/>
</bean>
<bean id="parentEncoder" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource">
<bean class="org.springframework.aop.target.HotSwappableTargetSource">
<constructor-arg ref="${password.encoding}Password"/>
</bean>
</property>
</bean>
Of course, I defined password.encoding in a property file with possible values as sha or plainText.
You should be able to do this:
<bean id="myValidator" factory-bean="validatorFactory" factory-method="getNewValidator" scope="prototype">
<constructor-arg><ref bean="validatorType"/></constructor-arg>
</bean>
<bean id="validatorType" ... />
Of course, it uses an automatically configured FactoryBean underneath but you avoid any Spring dependency in your code.