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
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.
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)
Is there anyway so that I can provide parameter to API( not to the member of class) using Spring?
I know I can pass result of one API call to member of class
<bean id="registryService" class="foo.MyRegistry">
...properties set etc...
</bean>
<bean id="MyClient" class="foo.MyClient">
<property name="endPoint" value="#{registryService.getEndPoint('bar')}"/>
</bean>
But, I want to pass the value to API( Basically I am trying to add ActionListener on JButton from spring)
Not really a spring expert but...
In Spring 3.
#Value("#{properties.getAppropriateActionListener()}")
public void setActionListener(ActionListener listener) {
myJButton.setActionListener(listener);
}
Also, I think Spring expects a setEndpoint() and getEndPoint() methods to be able to resolve the property which is named "endPoint". Declaring a property like that effectively passes the value to the setEndPoint() method. So passing a value to API (which I assume is invoking a method call) is actually pretty straightforward.
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.
I have the following class structure
public class Outer{
private Mapper a;
....
private class MapperA implements Mapper {
}
private class MapperB implements Mapper {
}
}
In my Spring config file I would like to create a an Outer bean, and assign one of MapperA or MapperB as a property. Is this possible?
<bean id="outer" class="mypackage.Outer">
<property name="a" ?????='????' />
</bean>
Edit: Some more info, based on the feedback from answers:
I got lazy with my above example. I do have a public setter/getter for the Mapper instance variable.
The reason all of the Mapper classes are inner classes is because there could potentially be many of them, and they will only ever be used in this class. I just don't want a ton of cruft classes in my project. Maybe a factory method is a better idea.
Spring can instantiate private inner classes. The actual problem with your config is that they are also non-static, so you need a <constructor-arg .../>:
<bean id="outer" class="mypackage.Outer">
<property name = "a">
<bean class = "mypackage.Outer.MapperA">
<constructor-arg ref = "outer" />
</bean>
</property>
</bean>
Normally you'd need a setter for the Mapper within Outer, and an instance of the required Mapper. But as these are:
private
inner
classes, that becomes a bit tricky (as you've identified). If you make them public, I'm sure you could creae an instance using Outer$MapperA etc. But that seems a little nasty. So:
do they need to be inner and private ?
perhaps Outer can take a String, and determine from that whether to instantiate MapperA or MapperB. i.e. there's some factory capability here.
The simplest thing to do is to really determine if they need to be inner/private. If so, then they really shouldn't be referenced within the config, which should be talking about publicly accessible classes.
As far as I know, it's impossible until you make MapperA and MapperB usual public classes.
But if you do want to keep them as inner private classes then you can "inject" them manually.
You'll need to create method with #PostInit annotation and initialize your a field there (a = new MapperA () for example, or something more complex). With this approach you should also check that initialization callbacks are switched-on in your spring configuration.