This question already has answers here:
Spring overloaded constructor injection
(3 answers)
Closed 6 years ago.
I would like to ask about the Spring Constructor Injection.
So in the class, I have two constructors with different number of arguments.
public class MyClassHello() {
public MyClassHello(String A) {
// do sth
}
public MyClassHello(String A, int B){
// do sth
}
}
If I try to inject like this to access the 1st constructor, Spring can not work since there is ambiguity.
<bean id="injectQuestion" class="MyClassHello">
<constructor-arg index="0" value="A String"/>
</bean>
The debug code is like this:
Unsatisfied dependency expressed through constructor argument with index 1 of type [java.lang.String]: Ambiguous constructor argument types.
I think it means, Spring needs to know if the index 1 argument exists?
It is not like the usual case where we have two constructors with same number of arguments. Like that, I could set the type in order to distinguish when injecting.
In my case, is there anyway to force Spring to choose the first constructor?
Thanks a lot!!
You can use the name:
<bean id= "InjectQuestion" class = "MyClassHello">
<constructor-arg name = "A" value="A String"/>
</bean>
<bean id= "InjectQuestion" class = "MyClassHello">
<constructor-arg name = "A" value="A String"/>
<constructor-arg name = "B" value="42"/>
</bean>
Note that your syntax in declaring the class is not valid; and also when defining the bean, in class="..." you should use the fully qualified name of the class (for example packageName.subPackage.MyClassHello not just MyClassHello)
Related
I'm working with a special CacheConfig object that holds a field (with standard getter/setter methods), accessExpirationValue, which is of type java.time.Duration. (EDIT: actually, the field is of type Long (the number of seconds), but the getter and setter are of type Duration.)
I'm trying to wire this in Spring by setting this value as a number of seconds and using a ConversionServiceFactoryBean, like so:
Relevant beans in ApplicationContext.xml:
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean" >
<property name="converters">
<set>
<bean
class="com.tjamesboone.example.config.SecondsToDurationConverter"/>
</set>
</property>
</bean>
<bean id="cacheConfig" class="com.tjamesboone.example.cache.CacheConfig" >
<property name="accessExpirationValue" value="0" />
</bean>
SecondsToDurationConverter:
package com.tjamesboone.example.cache;
import java.time.Duration;
import org.springframework.core.convert.converter.Converter;
public class SecondsToDurationConverter implements Converter<String, Duration> {
#Override
public Duration convert(String seconds) {
return Duration.ofSeconds(Long.parseLong(seconds));
}
}
Now, as I understand it, this is supposed to just work. When I pass in "0" for the value of accessExpirationValue, the fact that I've declared a conversionService bean that handles converting Strings to Durations means that is should set the value as a Duration of zero length.
But this would be to easy. And it is. Because when I test my application (using SpringJUnit4ClassRunner), I get this error, as if I'd never registered a Converter:
Bean property 'accessExpirationValue' is not writable or has an
invalid setter method. Does the parameter type of the setter match
the return type of the getter?
So my question is, What am I doing wrong? How do I get this to work they way I want?
For reference, this is the primary documentation I've been using:
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/validation.html#core-convert-Spring-config
It specifically says,
In a Spring application, you typically configure a ConversionService instance per Spring container (or ApplicationContext). That ConversionService will be picked up by Spring and then used whenever a type conversion needs to be performed by the framework.
EDIT:
I should probably also post the relevant part of CacheConfig!
package com.tjamesboone.example.config;
import java.time.Duration;
public class CacheConfig {
private Long accessExpirationValue;
public Duration getAccessExpiration() {
return Duration.ofSeconds(accessExpirationValue.intValue);
}
public void setAccessExpiration() {
this.accessExpirationValue = expirationDuration.getSeconds();
}
}
Spring is going to try to match the properties in your bean with the getters and setters specified in your class.
Your getters/setters are currently getAccessExpiration() but should be getAccessExpirationValue() to match your bean property name="accessExpirationValue". Change one or the other and you should have it.
I am trying to reproduce an assignment in Java code with an equivalent bean definition in Spring. As far as I can tell, though, Spring only lets you assign values to the fields within an object (provided that the class defines the appropriate setter methods). Is there a way to simply capture a reference to an object using Spring beans?
Here's an example of how I would expect this to work:
<!-- Non-working example. -->
<bean id="string" class="java.lang.String">
<value>"I am a string."</value>
</bean>
I realize that in this particular case I could just use a <constructor-arg>, but I'm looking for more general solution, one that also works for classes that don't provide parameterized constructors.
String class is immutable. No property setter method is available in java.lang.String class. If you want to inject the property value you can use below:
<bean id="emp" class="com.org.emp">
<property name="name" value="Alex" />
</bean>
in above for the obj emp, its name property will be set as Alex.
The thing to use here is a factory-method, possibly in conjunction with a factory-bean. (Non-static functions must be instantiated by a bean of the appropriate type.) In my example problem, I wanted to capture the output of a function that returns a String. Let's say the function looks like this:
class StringReturner {
public String gimmeUhString(String inStr) {
return "Your string is: " + instr;
}
}
First I need to create a bean of type StringReturner.
<bean name="stringReturner" class="how.do.i.java.StringReturner" />
Then I instantiate my String bean by calling the desired function as a factory-method. You can even provide parameters to the factory method using <constructor-arg> elements:
<bean id="string" factory-bean="stringReturner" factory-method="gimmeUhString">
<constructor-arg>
<value>I am a string.</value>
</constructor-arg>
</bean>
This is (for my purposes) equivalent to saying:
StringReturner stringReturner = new StringReturner();
String string = stringReturner.gimmeUhString("I am a string.");
String is not a Bean, Bean is a Objet that his Class that have a Constructor with empty arguments and the properties are accessible by Getters Methods and are modifiable by Setters Methods
I have two classes A and B. A holds B as a class field b.
A has two arguments in its constructor : public A(C c, D d){}.
B has two arguments in its constructor : public B(C c, D d){}.
A has a setter for B.
in the spring xml, I defined the Bean B nested inside A :
<bean id="B" class="java.util.B"/>
<bean id="A" class="java.util.A>
<property name="b" ref="B"/>
</bean>
if I load A as follows:
(A)SpringManager.getInstance().loadBean("A",new Object[] {c,d})
(assume that c and d are defined in the class that calles the loadBean function)
How do I pass the args that A got to B's constructor?
You can't. Either you are in charge or Spring is. What you are doing is wiring objects manually instead of using Spring to manage them. You can't expect Spring to provide magic to enable you to do that.
So you'll have to instantiate B first and then pass it to A:
B b = (B)SpringManager.getInstance().loadBean("B",new Object[] {c,d});
A a = (A)SpringManager.getInstance().loadBean("A",new Object[] {c,d});
a.setB(b);
And quite frankly: if you do it like that, I don't see why you are using Spring in the first place.
When calling Spring's "Validate" from Eclipse, I get a lot of errors when I want to get back an enum using Enum's implicit "valueOf" method.
For example:
<bean id="docFamily" class="...DocFamily" factory-method="valueOf">
<constructor-arg>
<value>LOGY</value>
</constructor-arg>
</bean>
has Eclipse telling me:
Non-static factory method 'valueOf'
with 1 arguments not found in factory
bean class ...
However as I understand it from the documentation:
BeanWrapperImpl supports JDK 1.5 enums
and old-style enum classes: String
values will be treated as enum value
names
So the above should work right? (btw is 'constructor-arg' the correct tag in that case, shouldn't it be some 'method-arg'?).
Why is Eclipse/Spring's "Validate" giving me that error message?
Enum.valueOf() has two arguments:
public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name)
Therefore the desired definition may look like this:
<bean id="docFamily" class="java.lang.Enum" factory-method="valueOf">
<constructor-arg index = "0"><value>...DocFamily</value></constructor-arg>
<constructor-arg index = "1"><value>LOGY</value></constructor-arg>
</bean>
However, something like this can be a more elegant solution:
<util:constant id = "docFamily" static-field = "...DocFamily.LOGY" />
I just tried using it like this:
<bean id="docFamily" class="...DocFamily" factory-method="valueOf">
<constructor-arg type="java.lang.String" value="LOGY"/>
</bean>
and it worked like charm. Does it works for you?
I am New to Spring.I have this question which has been bothering me for a while now. Any help would be appreciated.
There is an Interface which calls a getter method.
interface MessageHandler{
public List GetMessageCheckerList();
}
There is another Interface called MessageChecker which has multiple Implementations.
Say MessageChecker1, TestChecker, etc. (lets assume 2 for now )
Now how do i define this in the configuration xml file.
I actually have the bean created ,
here is the rest of the code
<bean id="checkerList" class="java.util.ArrayList">
<constructor-arg>
<list>
<ref bean="HL7Checker"/>
</list>
</constructor-arg>
</bean>
<bean id="HL7Checker" class="com.kahootz.messagereceiver.HL7CheckerImpl">
<property name="messageExecutor" ref="Executor"/>
</bean>
Please Advice
When I actually run the program using a main method, I get the handle of one of the beans, The HL7Checker should be passed in a list to the Bean with ID=messageHandler. But when i print out the list. It is empty.
Without using spring and only using getter and setter methods , i am able "set" a list and retrieve it using Get.
Almost all of your names do not conform to the Java Naming Conventions. That makes it hard for others to understand your code.
The <ref> tag expects the name of an object, not the name of a class. So you need to define a <bean id="testChecker" class="com.test.TestChecker" /> before you can reference it.
Don't use the package name com.Test. First, it should contain only lowercase letters. Second, you should be the owner of that name.