Populating a spring bean using a constructor-arg field - java

How can i inject a properties file containing a Map to be used as additional constructor arg using the field.
With a Map being loaded from a properties file
the bean is currently setup using:
<bean id="graphDbService" class="org.neo4j.kernel.EmbeddedGraphDatabase"
init-method="enableRemoteShell" destroy-method="shutdown">
<constructor-arg index="0" value= "data/neo4j-db"/>
<constructor-arg index="1" value=? />
</bean>
Java Equivalent:
Map<String,String> configuration = EmbeddedGraphDatabase.loadConfigurations( "neo4j_config.props" );
GraphDatabaseService graphDb = new EmbeddedGraphDatabase( "data/neo4j-db", configuration );
Thanks

Something like this:
<bean id="configuration" class="org.neo4j.kernel.EmbeddedGraphDatabase"
factory-method="loadConfigurations">
<constructor-arg value="neo4j_config.props"/>
</bean>
<bean id="graphDbService" class="org.neo4j.kernel.EmbeddedGraphDatabase"
init-method="enableRemoteShell" destroy-method="shutdown">
<constructor-arg index="0" value="data/neo4j-db"/>
<constructor-arg index="1" ref="configuration" />
</bean>
This takes advantage of the ability to create beans using arbitrary static factory methods, in this case using loadConfigurations() as a factory method to create the configuration bean, which is then injected into the proper constructor of EmbeddedGraphDatabase.

Create a bean that loads the properties (and takes the file name as an argument) and inject that instead.
EDIT When using annotations, things like constructor injection become more simple:
#Bean
public Map<String,String> configuration() {
return EmbeddedGraphDatabase.loadConfigurations( "neo4j_config.props" );
}
#Bean
public GraphDatabaseService graphDb() {
return new EmbeddedGraphDatabase( "data/neo4j-db", configuration() );
}
Note that the second bean definition method "simply" calls the first. When this code is executed, Spring will do some magic so you can still override the bean elsewhere (i.e. beans still overwrite each other) and it will make sure that the method body will be executed only once (no matter how often and from where it was called).
If the config is in a different #Configuration class, then you can #Autowired it:
#Autowired
private Map<String,String> configuration;
#Bean
public GraphDatabaseService graphDb() {
return new EmbeddedGraphDatabase( "data/neo4j-db", configuration );
}

Related

Bean initialized with FactoryBean receives the FactoryBean instead of the Obect created by it

I'm trying to reference a bean from another with xml, sending an object produced with a FactoryBean. My problem is that the data generated by the beanFactory is, apparently a FactoryBean object and hasn't the type that should have been created by the factory.
The beans are defined like this:
<bean id="daFactoryBean" class="com.whatever.something.MyFactoryBean">
[...]
</bean>
<bean id="theBeanThatProducesProblems" class="com.whatever.something.AGoodName">
<constructor-arg ref="daFactoryBean"/>
<constructor-arg ref="anotherBean"/>
</bean>
Note that "daFactoryBean" would produce objects typed "TheClassIWantToProduce". And that "theBeanThatProducesProblems" expects that type on "daFactoryBean" but it receives the Factory itself.
The factoryBean is defined like this
public class MyFactoryBean implements
FactoryBean<TheClassIWantToProduce> {
FactoryBean([..]) { [...] }
[...]
#Override
public TheClassIWantToProduce getObject() { [...] }
}
and the class that I need to produce is this
public AGoodName extends RestTemplate {
AGoodName(TheClassIWantToProduce foo, AnotherClassThatDoesnTComeFromAFactory foo2){
}
}
The thing is that I don't exactly know how to say the spring's xml that I want the object produced by the factory, not the factory itself. As the types aren't valid, the expected value isn't being initialised. Any hints?
Solved, I had to create a sub-bean that used my factory-bean
<bean id="daFactoryBean" class="com.whatever.something.MyFactoryBean">
[...]
</bean>
<bean id="theBeanThatProducesProblems" class="com.whatever.something.AGoodName">
<constructor-arg>
<bean id="aNewBean" factory-bean="daFactoryBean" class="com.whatever.something.TheClassIWantToProduce"/>
</constructor-arg>
<constructor-arg ref="anotherBean"/>
</bean>

How to translate xml configuration bean to Java config bean?

I am rewriting a legacy project using Quartz and Spring Framework. The original configuration is in XML and now I am translating it into Java Config. The xml configuration uses jobDetail to set the job detail property of the trigger bean. However, when I try to use the equivalent method, i.e. the setter: setJobDetails(simpleJobDetail), I got a warning that the setter does not have correct type (expecting JobDetails, but got MethodInvokingJobDetailFactoryBean).
May I know whether it is correct to translate xml bean configuration to Java COnfig by using the equivalent named setter in Java COnfig?
Why in the XML property setting, the trigger bean can set its jobDetail property as the simpleJobDetail bean (which has type MethodInvokingJobDetailFactoryBean) , while the Java Config could not?
XML config:
<!-- For times when you just need to invoke a method on a specific object -->
<bean id="simpleJobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="reader" />
<property name="targetMethod" value="readData" />
</bean>
<!-- Run the job every 60 seconds with initial delay of 1 second -->
<bean id="trigger"
class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="simpleJobDetail" />
<property name="repeatInterval" value="600000" />
</bean>
Java Config:
#Bean
public MethodInvokingJobDetailFactoryBean simpleJobDetail() {
MethodInvokingJobDetailFactoryBean simpleJobDetail = new MethodInvokingJobDetailFactoryBean();
simpleJobDetail.setTargetObject(reader());
simpleJobDetail.setTargetMethod("readData");
return simpleJobDetail;
}
#Bean
private Object reader() {
// TODO: 10/13/2016
return null;
}
#Bean
public SimpleTriggerFactoryBean trigger() {
final SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean();
trigger.setJobDetail( simpleJobDetail()); // got warning about wrong type
trigger.setRepeatInterval(60000);
return trigger;
}
Note that simpleJobDetail() returns a factory, not the bean itself. You can rely on autowiring to inject a JobDetail built using this factory.
#Bean
public SimpleTriggerFactoryBean trigger(final JobDetail simpleJobDetail) {
final SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean();
trigger.setJobDetail(simpleJobDetail); // got warning about wrong type
trigger.setRepeatInterval(60000);
return trigger;
}
Hope it helps.

How to create java.util.Optional<T> object from Spring bean?

Java
public class MyObject{}
public class MyFactory{
private Optional<MyObject> myproperty;
public Optional<MyObject> getMyproperty{...}
public void setMyproperty{...}
}
Spring config xml (doesn't work)
<bean id="myproperty" class="java.util.Optional">
<constructor-arg>
<value>com.MyObject</value>
</constructor-arg>
</bean>
<bean id="myfactory" class="com.Myfactory">
<property name="myproperty" ref="myproperty" />
</bean>
Does spring support generics beans?
The reason for using Optional is it provide some useful features such as checking value if null. You can complete checking and further action in one line of code.
getMyproperty().ifPresent(id -> call.setId(id));
Seems the problem have nothing to do with generics.
You simply need to properly tell Spring to create the bean using a factory method, as Optional can only be created though factory methods. Something like:
<bean id="myproperty" class="java.util.Optional" factory-method="of">
<constructor-arg type="java.lang.Object" value="com.MyObject" />
</bean>
for which it is supposed to mean creating the myproperty bean by Optional.of(com.MyObject.class) (Change the factory-method to ofNullable if that's the one you want to use)
Another option is to use SpEL (Spring Expression Language):
<bean id="mybean" ...>
<property name="optProp" value="#{ T(java.util.Optional).of( #wrapme) }"/>
</bean>
Where "wrapme" is the name of a bean defined elsewhere that you want to wrap in java.util.Optional.

Creating a singleton bean using runtime parameters

I am new to the Spring framework and can't find a way to achieve the following:
I am using a class whose attributes are all private and there are no setters (the intended way to use objects of that class is to set attributes once with a constructor) - I will refer to it as Preferences. I also have a few classes that each has the same instance of Preferences as an attribute. Preferences is intended to contain certain properties, among which some can only be resolved at runtime (e.g. provided by the user).
In my .xml file I would write something along the lines of:
<bean id="preferenes" class="Preferences" scope="singleton">
<constructor-arg index="0" value="defaultAttrOne" />
<constructor-arg index="1" value="defaultAttrTwo" />
<constructor-arg index="2" value="defaultAttrThree" />
</bean>
<bean id="someOtherBean" class="SomeOtherClass" scope="singleton">
<constructor-arg index="0" ref="preferences" />
</bean>
That is, I could provide default values and replace some of them with custom ones at runtime. As I cannot modify attributes of an existing instance of Preferences, I would have to construct a new object and somehow make the instance of SomeOtherClass point to that new object (is this possible through the bean mechanism?).
Rather, I'd pass the desired runtime constructor arguments to the preferences bean before instantiating any of the beans (those arguments will be known before the first call to the ApplicationContext's constructor). I know there is a flavour of the getBean() method that takes varargs as initialization parameters, though it only applies to prototype beans. In this case I want to initialize Preferenes once and have all helper classes refer to that single instance.
Thank you for any hints.
This is pretty much what Spring does for you by default so there is nothing special you'll have to do: if you create that singleton bean reference (called preferences), you'll be able to inject it to any other bean as you would expect.
Regarding your attributes with default values, there's several ways to achieve that:
Regular XML config
You can keep a purely XML-based configuration if you want and configure a PropertyPlaceholderConfigurer with default values. Something like:
<bean class="org.s.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="prefrences.properties"/>
</bean>
<bean id="preferenes" class="Preferences" scope="singleton">
<constructor-arg index="0" value="$[preferences.one:12]" />
<constructor-arg index="1" value="$[preferences.two:AUTO]" />
<constructor-arg index="2" value="$[preferences.three:false]" />
</bean>
And have a prefrences.properties at the root of the classpath hold the specific values if you don't want the default
prefrences.three=true
FactoryBean
As you're already using XML, you can go with a FactoryBean that would create the Preferences instance, something like
<bean id="preferences" class="org.myproject.PreferencesFactoryBean"/>
in the code of the factory you could use whatever mechanism you want to retrieve the non default values for your configuration, including injecting custom properties.
Java config
You can also go the java config way but as you're a beginner this may be a bit of a change. However, java config is really powerful and flexible so you may want to give it a try.
#Configuration
#PropertySource("classpath:preferences.properties")
public class AppConfig {
#Value("${preferences.one}")
private int preferenceOne = 12;
#Value("${preferences.two}")
private MyEnum preferenceTwo = MyEnum.AUTO;
#Value("${preferences.three}")
private boolean preferenceThree;
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public Preferences preferences() {
return new Preferences(preferenceOne, preferenceTwo, preferenceThree);
}
}

Optional Spring bean references

In my application I am using ContextLoaderListener to load context files from many jars using:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/contextBeans.xml</param-value>
</context-param>
This means I can reference beans from other jars without doing import.
In the application there are multiple deployment options and in some deployments jars can be excluded. To support that I would like some bean references to be optional. For example:
<bean id="mainAppBean" class="com.someapp.MyApplication">
<constructor-arg index="0" ref="localBean"/>
<constructor-arg index="1" ref="optionalBeanReference1"/>
<constructor-arg index="2" ref="optionalBeanReference2"/>
</bean>
In the example above I would like to have optionalBeanReference1 equal null if the reference was not found (mark it optional in some way)
Can this be done in Spring? or what method do you recommend for handling dynamic references?
My best guess is to use autowire-ing with required false. Don't know how you can express this in XML but using annotation configuration this would look like:
#Autowired(required=false)
With recent versions of Spring (tested with spring 4.1) and Java Configuration and Java 8, you can use Optional in parameters, and are only autowired if available.
#Autowired
public MyApplication(Optional<YourOptionalObject> maybeObject) {
// do something with the optional autowired
}
what method do you recommend for handling dynamic references?
I think #cristian's #Autowired answer is a good one. That will call the setter methods if the beans of that type are available. However, if you have multiple beans of the same type, I believe Spring throws an exception. If you cannot use #Autowired for this or some other reason, I see a couple of solutions:
You could make your class ApplicationContextAware and lookup the beans in the context yourself:
public void setApplicationContext(ApplicationContext applicationContext) {
if (applicationContext.containsBean("optionalBeanReference1")) {
setOptionalBeanReference1(
(OptionalBeanReference1)applicationContext.bean(
"optionalBeanReference1");
}
...
}
You could invert the dependency. Each of the optional classes could set themselves on the mainAppBean. I use this in certain situations when a direct dependency would cause loops or other problems.
<bean id="optionalBeanReference1" class="com.someapp.SomeClass">
<constructor-arg index="0" ref="mainAppBean"/>
</bean>
Then in the SomeClass:
public SomeClass(com.someapp.MyApplication mainAppBean) {
mainAppBean.setOptionalBeanReference1(this);
}
You could stay with your direct dependency and then either import a file with the beans defined or import another file where you define the beans as having null values by using a factory bean. See this factory code.
Good luck.
There's no built-in mechanism for this. However, you could write a pretty trivial FactoryBean implementation to do this for you, something like this:
public class OptionalFactoryBean extends AbstractFactoryBean<Object> implements BeanNameAware {
private String beanName;
#Override
public void setBeanName(String beanName) {
this.beanName = BeanFactoryUtils.originalBeanName(beanName);
}
#Override
protected Object createInstance() throws Exception {
if (getBeanFactory().containsBean(beanName)) {
return getBeanFactory().getBean(beanName);
} else {
return null;
}
}
#Override
public Class<?> getObjectType() {
return null;
}
}
You can then use it like this:
<bean id="mainAppBean" class="com.someapp.MyApplication">
<constructor-arg index="0" ref="localBean"/>
<constructor-arg index="1">
<bean name="optionalBeanReference1" class="com.someapp.OptionalBeanFactory"/>
</constructor-arg>
<constructor-arg index="2">
<bean name="optionalBeanReference2" class="com.someapp.OptionalBeanFactory"/>
</constructor-arg>
</bean>
Given that the bean references in your XML config are defined via expression language (EL) you can do the following:
<property name="cache" value="#{getObject('optionalCache')}" />
which makes use of the BeanExpressionContext.getObject() method. See here for more details.

Categories