pass "HardCoded" Constructor Arg Class<T> to bean via Spring Config - java

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"/>

Related

Spring XML configuration - how to define Instant, BigDecimal, ... parameters?

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>

Auto-wiring Spring constructor arguments from properties file in XML

I'm using Spring to auto-wire beans for configuration. Some parameters come from a properties file:
<bean id="mydb" class="myproject.mydb" autowire="constructor">
<constructor-arg name="host" value="${mydb.host}" />
<constructor-arg name="db" value="${mydb.db}" />
<constructor-arg name="user" value="${mydb.user}" />
<constructor-arg name="password" value="${mydb.password}" />
</bean>
Is there a way to auto-wire these properties based on the bean id so that I would just have to write the following?
<bean id="mydb" class="myproject.mydb" autowire="constructor" />
Edit: The point of this is to not have to explicity specify the non-bean constructor arguments. I want Spring to automatically check the properties for beanId.constructorArgName
To achieve exactly what you want, I think you'd need to implement a BeanPostProcessor and provide your custom wiring logic (where you read the .properties file) in postProcessBeforeInitialization. The bean name is available to that method, but there are multiple problems with this. The first is that argument names are not necessarily available at runtime, so indexes might be a better option. The second is that you already have an instantiated bean (so a default constructor would need to exists), and you'd instantiate another, throwing the first one away which is wasteful. To use the instance that already exists, you'd need to wire it by properties, not constructor, which violates encapsulation and is not what you asked. The third is that it's not at all obvious what is going on. So, all in all, you are probably better off avoiding this completely.
In your class myproject.mydb
#Autowired
public mydb(#Value("mydb.host") String host, ...){...}
As per your question, the only way Property values can be injected to the constructor is through the XMLfile as done above or using the #Value("${some.property}") annotation.
Refer this for more info
Use #Value("property key") annotation. look at eg.: http://java.dzone.com/articles/autowiring-property-values

Spring Di via setter dynamic constructor parameters

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.

How to autowire a class with non-empty constructor?

I'd like to #Autowired a class that has a non-empty constructor.
Just the the following as an example, it does not necessairly have to be a view/service. Could be whatever component you like, having non-default constructor:
#Component
class MyViewService {
//the "datasource" to show in the view
private List<String> companies companies;
private MyObject obj;
public MyViewService(List<String> companies, MyObject obj) {
this.companies = companies;
this.obj = obj;
}
}
Of course I cannot just write
#Autowired
private MyViewService viewService;
as I'd like to use the constructor with the list. But how?
Are there better approaches than refactoring these sort of constructors to setters? I wouldn't like this approach as ideally the constructor forces other classes to provide all objects that are needed within the service. If I use setters, one could easily forget to set certain objects.
If you want Spring to manage MyViewService you have to tell Spring how to create an instance of it. If you're using XML configuration:
<bean id="myViewService" class="org.membersound.MyViewService">
<constructor-arg index="0" ref="ref_to_list" />
<constructor-arg index="1" ref="ref_to_object" />
</bean>
If you're using Java configuration then you'd call the constructor yourself in your #Beanannotated method.
Check out the Spring docs on this topic. To address a comment you made to another answer, you can create a List bean in XML as shown in the Spring docs. If the list data isn't fixed (which it's probably not) then you want to use an instance factory method to instantiate the bean.
In short, the answers you seek are all in the Spring docs :)
If a component has a non-default constructor then you need to configure the constructor in the bean configuration.
If you are using XML,
it might look like this (example from the spring reference document):
<beans>
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
</bean>
<bean id="bar" class="x.y.Bar"/>
<bean id="baz" class="x.y.Baz"/>
</beans>
The key here is constructor wiring of the bean that will be used for the #AutoWire.
The way you use the bean has no impact.

Nesting abstract beans in Spring and init-method does not seem to work

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.

Categories

Resources