I have a static class ResourceFetcher with a static method fetchResource(String reference). I want to inject the resource returned by it into another class JobRunner. Can anyone specify the cleanest way of doing this?
I do not want to pass ResourceFetcher into JobRunner. In fact, I have an enum with set of keys, and I need to pass a map of key-value pairs into JobRunner with values obtained by invoking fetchResource.
Onething I want to clarify is that ResourceFetcher class' fetchResource returns an object of type String
Thanks in advance.
<bean id="resource" class="com.x.y.ResourceFetcher" factory-method="fetchResource">
<constructor-arg value="someReference"/>
</bean>
You can then inject resource into your JobRunner bean.
If the fetchResource method is static on ResourceFetcher, why can't JobRunner simply refer to it? I don't see the need to inject ResourceFetcher.
Related
Is it possible to chain methods in factory-method in spring to create beans. For example, I have the following API:
SomeObject.builder().build();
Is there some way I can create this bean in spring XML config directly without creating 2 beans? For example,
<bean id="fooBar" class="com.foo.bar.SomeObject" factory-method="builder().build"/>
Note: The SomeObject.builder() call returns a SomeObjectBuilder object(private static class within SomeObject).
You can't do that. You just specify a single method (even without the brackets). But in SomeObject class you can create a static method that does that for you. For example:
static SomeObject newFactoryMethod(){
return builder().build();
}
And add it to the XML:
<bean id="fooBar" class="com.foo.bar.SomeObject" factory-method="newFactoryMethod"/>
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've been searching but cannot find these steps. I hope I'm missing something obvious.
I have a properties file with the following contents:
machines=A,B
I have another file like that but having a different number of members in the machines element like this:
machines=B,C,D
My question is how do I load this variable-length machines variable into a bean in my spring config in a generic way?
something like this:
<property name="machines" value="${machines}"/>
where machines is an array or list in my java code. I can define it however I want if I can figure out how to do this.
Basically I'd rather have spring do the parsing and stick each value into a list element instead of me having to write something that reads in the full machines string and do the parsing myself (with the comma delimiter) to put each value into an array or list. Is there an easy way to do this that I'm missing?
You may want to take a look at Spring's StringUtils class. It has a number of useful methods to convert a comma separated list to a Set or a String array. You can use any of these utility methods, using Spring's factory-method framework, to inject a parsed value into your bean. Here is an example:
<property name="machines">
<bean class="org.springframework.util.StringUtils" factory-method="commaDelimitedListToSet">
<constructor-arg type="java.lang.String" value="${machines}"/>
</bean>
</property>
In this example, the value for 'machines' is loaded from the properties file.
If an existing utility method does not meet your needs, it is pretty straightforward to create your own. This technique allows you to execute any static utility method.
Spring EL makes easier.
Java:
List <String> machines;
Context:
<property name="machines" value="#{T(java.util.Arrays).asList('${machines}')}"/>
If you make the property "machines" a String array, then spring will do it automatically for you
machines=B,C,D
<property name="machines" value="${machines}"/>
public void setMachines(String[] test) {
Since Spring 3.0, it is also possible to read in the list of values using the #Value annotation.
Property file:
machines=B,C,D
Java code:
import org.springframework.beans.factory.annotation.Value;
#Value("#{'${machines}'.split(',')}")
private List<String> machines;
You can inject the values to the list directly without boilerplate code.(Spring 3.1+)
#Value("${machines}")
private List<String> machines;
for the key "machines=B,C,D" in the properties file by creating following two instance in your configuration.
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public ConversionService conversionService() {
return new DefaultConversionService();
}
Those will cover all the separate based split and whitespace trim as well.
I have a requirement to initialize the "flag" field in a java enum by spring:
public enum EntitySequenceType {
TypeOne(-1),
TypeTwo(-1000);
private boolean flag;
EntitySequenceType(long firstId){
System.out.println("enum's constructor: "+this.name()+" firstId="+firstId);
}
public void setFlag(boolean val) {
this.flag = val;
}
public boolean getFlag() {
return this.flag;
}
}
The spring config is:
<bean id="myEnum" class="com.maven.start.maven_spring.EntitySequenceType"
factory-method="valueOf">
<property name="flag" value="true"/>
<constructor-arg>
<value>TypeOne</value>
</constructor-arg>
</bean>
But I have met some problems, so I have the following questions:
1.It seems that I can only write a single value in the <constructor-arg> tag in the config xml, I can't figure out why it is like this.
2.When I debugging the code, I found that when spring is initializing the bean, although I only write one constructor-arg value in the config xml, the constructor is called twice.How could this happen?
3.In the constructor of EntitySequenceType, I found that the "flag"'s value is null, why? There is "afterPropertiesSet()" can be called if the enum implements InitializingBean, but it is not called every time a enum type is constructed, so is there any method to be called after the field is set by spring, but is called every time a enum type is called?
Thanks for your answers!
It seems that I can only write a single value in the
tag in the config xml, I can't figure out why it is like this.
Used with a factory-method, the constructor-arg values are referring to the parameter list of that factory-method. EntitySequenceType.valueOf(String) only takes one argument, a String.
When I debugging the code, I found that when spring is initializing
the bean, although I only write one constructor-arg value in the
config xml, the constructor is called twice.How could this happen?
Enum types, like any other types, have their .class file loaded and initialized when they are first referenced in the code. The enum constants
TypeOne(-1),
TypeTwo(-1000);
are actually static fields in the compiled byte code. As such, they are initialized when the class is initialized. Those are two constructor calls, so that is what you see.
The constructor-arg value has nothing to do with these constructors, it has to do with your factory-method.
In the constructor of EntitySequenceType, I found that the "flag"'s
value is null, why? There is "afterPropertiesSet()" can be called if
the enum implements InitializingBean, but it is not called every time
a enum type is constructed, so is there any method to be called after
the field is set by spring, but is called every time a enum type is
called?
It can't be null, it's a primitive type. Your property is going to be set after the factory-method is called and executed. There is no need to implement InitializingBean.
Don't use an enum for this. Enums are meant to be constant.
The problem is:
The constructor for an enum type must be package-private or private access. It automatically creates the constants that are defined at the beginning of the enum body. You cannot invoke an enum constructor yourself.
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.