I have a spring boot application where I am trying to convert the following spring xml config to java config:
<bean id="pageDAO" factory-bean="springWSDaoFactory"
factory-method="createPageDAO" lazy-init="true">
<constructor-arg type="java.lang.String" value="${cds.host}" />
<constructor-arg type="java.lang.Integer" value="${cds.port}" />
</bean>
<!-- CoreApi + plugins configuration -->
<import resource="classpath:coreAPI_SpringWSContext.xml"/>
<bean name="springWSDaoFactory" class="com.blan.torque.dao.springws.SpringWSDAOFactory" lazy-init="true">
<property name="serviceVersion" value="${service.version}"/>
<property name="securityKey" value="${service.key}"/>
</bean>
Here's what I have for javaconfig so far:
#Bean
public PageDAO pageDAO() {
return springWSDAOFactory().createPageDAO(null, null);
}
#Bean
public SpringWSDAOFactory springWSDAOFactory() {
SpringWSDAOFactory springWSDAOFactory = new SpringWSDAOFactory();
springWSDAOFactory.setServiceVersion(null);
springWSDAOFactory.setSecurityKey(null);
return springWSDAOFactory;
}
I have no idea how to implement <import resource...../> in Java let alone import the variables like ${cds.host}. I've put null everywhere as place holders. But any ideas on how to do this with annotations?
In your configuration class you can use the annotation #ImportResource instead of <import resource... />.
To read Strings from a property file, try to declare an String using #Value and the use the previously declared string.
For example:
#Value("${service.version}")
private String serviceVersion;
Then using it as parameter
springWSDAOFactory.setServiceVersion(this.serviceVersion);
I hope have helped you.
Related
Config my custom type converters by using (Spring 4.x)XML properties like this.
<mvc:annotation-driven conversion-service="factoryBean" />
<bean class="org.springframework.context.support.ConversionServiceFactoryBean" id="factoryBean" >
<property name="converters">
<list>
<bean class="com.mvc.convertor.MyConvertor" />
</list>
</property>
</bean>
MyConvertor implements org.springframework.core.convert.converter.Converter.
And how can I config my custom type converters by using SpringBoot.I have tried many methods but failed.Hope any one can help me to resolve.Thanks!
As Stephane Nicoll pointed out spring boot should automatically pick up any converters registered as bean configuration in your application.
#Configuration
#EnableWebMvc
public class MyConfiguration {
#Bean
public HttpMessageConverters customConverters() {
HttpMessageConverter<?> additional = ...
HttpMessageConverter<?> another = ...
return new HttpMessageConverters(additional, another);
}
}
So I currently am working on a project that uses Spring to inject a schema location for the xsd when calling an xsl, something like:
<bean id="transformer" class="com.mypackage.Transformer">
<property name="xsl" value="sample.xsl" />
<property name="params">
<map>
<entry key="schemaLocation" value-ref="schema" />
</map>
</property>
</bean>
<bean id="schema" class="java.lang.String">
<constructor-arg value="http://www.sample.com/schema/sampleSchema.xsd" />
</bean>
This works fine when you use a url as the schema location, but say for example you want to refer to a schema that is brought in on the classpath as a maven dependency. I've found that using something like 'classpath:sampleSchema.xsd' doesn't work. I would've thought this kind of behaviour was fairly common, is there an accepted workaround to this? Create a custom class that looks up the schema on the classpath and returns its path as a string?
OK so I thought I would share how I fixed this.
Two spring beans:
<bean id="schema" factory-method="getSchemaLocation" factory-bean="schemaFinder" />
<bean id="schemaFinder" class="com.mypackage.SchemaFinder">
<constructor-arg value="NAME_OF_SCHEMA" />
</bean>
And a class:
public class SchemaFinder
{
private String schemaLocation;
public SchemaFinder(String schemaName) throws Exception
{
try
{
URL absoluteSchemaUrl = getClass().getClassLoader().getResource(schemaName);
setSchemaLocation(absoluteSchemaUrl.toString());
}
catch (Exception e)
{
//whatever you want here
}
}
public void setSchemaLocation(String schemaLocation)
{
this.schemaLocation = schemaLocation;
}
public String getSchemaLocation()
{
return this.schemaLocation;
}
}
Quite easy when you think about it...
I have a service which refers to a single source.
<bean id="XYZService" class="com.services.impl.DataService1">
<constructor-arg ref="DataSource1" />
</bean>
<bean id="DataSource1" class="com.source.impl.DataSource1">
<constructor-arg ref="DBDataSource"/>
<constructor-arg value="xyz"/>
</bean>
<bean id="DataSource2" class="com.source.impl.DataSource2">
<constructor-arg ref="MsgDataSource"/>
<constructor-arg value="xyz"/>
</bean>
Now if i want to perform a conditional check and my service should be able listen to particular source based on a input variable something like below.
<bean id="XYZService" class="com.services.impl.DataService1">
<constructor-arg ref=" $VARIABLE == true ? DataSource1 : DataSource2" />
</bean>
I did tried SPEL however no luck. I am beginner in spring. Any help will be appreciated.
Thanks.
There are many solutions. Here are two: You can use profiles for this. Define two profiles, define the DataSource beans with the same name but different profiles. (docs)
Alternatively, you can use a single bean and a static factory method (docs).
<bean id="DataSource" class="com.source.impl.DataSourceFactory"
factory-method="createInstance"/>
Inside of DataSourceFactory.createInstance(), you can check the flag and then create the correct data source in plain Java.
The latter is a bit easier to understand, IMO. Using profiles allows you to keep everything in XML (but you should really consider switching to the Java Configuration). The drawback with profiles is that you must not forget to activate at least one of the bean won't be defined.
A third option is to use three XML files and then modify the list of XML files that should be parsed when you pass it to the ApplicationContext. But that only works if you have control over this part of the code.
Assuming you are using Spring 3.1 or later, Spring Profiles may be the best solution.
Using the example of Production and Dev/QA environments, common bean declarations go in a shared file
<beans>
<bean id="XYZService" class="com.services.impl.DataService1">
<constructor-arg ref="DataSource" />
</bean>
</beans>
A separate configuration contains production references
<beans profiles="prod">
<bean id="DataSource" class="com.source.impl.DataSource1">
<constructor-arg ref="DBDataSource"/>
<constructor-arg value="xyz"/>
</bean>
</beans>
Another contains dev references
<beans profile="dev">
<bean id="DataSource" class="com.source.impl.DataSource2">
<constructor-arg ref="MsgDataSource"/>
<constructor-arg value="xyz"/>
</bean>
</beans>
To activate the given profile add -Dspring.profiles.active=prod to your JVM arguments
You can find more info here
Another approach uses factory methods.
<bean id="DataSource" class="com.source.impl.DataSourceFactory" factory-method="getInstance">
<constructor-arg value="#{VARIABLE}" />
</bean>
The above fragment assumes that you want your factory method to explcitly invoke the constructor of each of your services. If you dead set on using Spring to create the instances you can pass each datasource implementation as constructor arguments and use the constructor method as a simple dispatcher.
You need something like this:
<constructor-arg
ref="#{systemProperties.variable == 'true' ? 'DataSource1' : 'DataSource2'}" />
where "variable" is set like -Dvariable=true.
I have the following XML configuration:
<bean id="bean1" class="Simple"/>
<bean id="bean2" class="Simple"/>
<bean id="tasks" class="java.util.ArrayList">
<constructor-arg>
<list>
<ref bean="bean1" />
<ref bean="bean2" />
</list>
</constructor-arg>
</bean>
<bean id="list" class="Comp">
<property name="tasks" ref="tasks"/>
</bean>
The "tasks" contains all beans of type Simple. The problem with this is that I might forget to add a Simple bean I've configured to the list.
I could do this programatically using
Map map = context.getBeansOfType(Simple.class);
and setting the list bean with the beans retrieved.
Is there any way of doing this using just XML configuration?
Your context file should like this:
<bean id="bean1" class="Simple"/>
<bean id="bean2" class="Simple"/>
<bean id="list" class="Comp" autowire="byType"/>
Note the autowire="byType" addition, and the autowiring documentation.
I would suggest writing your own FactoryBean for creating such a list. This would be reusable and then configurable using XML only. The FactoryBean would look like
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.Assert;
public class CollectingListFactoryBean implements FactoryBean, ApplicationContextAware {
private ApplicationContext appCtx;
private Class type;
public Object getObject() {
Assert.notNull(type, "type must be initialized");
List result = new ArrayList();
result.addAll(appCtx.getBeansOfType(type).values());
return result;
}
public Class getObjectType() {
return List.class;
}
public boolean isSingleton() {
return false;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.appCtx = applicationContext;
}
public void setType(Class type) {
this.type = type;
}
}
Then your XML configuration would be
<bean id="bean1" class="Simple"/>
<bean id="bean2" class="Simple"/>
<bean id="tasks" class="CollectingListFactoryBean">
<property name="type" value="Simple" />
</bean>
<bean id="list" class="Comp">
<property name="tasks" ref="tasks"/>
</bean>
NOTE: I didn't have the time to test the example above. I just used code I already had as a template. ;) Especially I'm not sure if passing Simple as a Class argument for the type property works this way. Just give it a try. In the worst case you would have to use String as the property type and use Class.forName(type) to get your class. But my guess is that Spring does this transformation for you.
EDIT Even though this solution should work, I recommend Robert Munteanu's answer.
I'd like to create a spring bean that holds the value of a double. Something like:
<bean id="doubleValue" value="3.7"/>
Declare it like this:
<bean id="doubleValue" class="java.lang.Double">
<constructor-arg index="0" value="3.7"/>
</bean>
And use like this:
<bean id="someOtherBean" ...>
<property name="value" ref="doubleValue"/>
</bean>
It's also worth noting that depending on your need defining your own bean may not be the best bet for you.
<util:constant static-field="org.example.Constants.FOO"/>
is a good way to access a constant value stored in a class and default binders also work very well for conversions e.g.
<bean class="Foo" p:doubleValue="123.00"/>
I've found myself replacing many of my beans in this manner, coupled with a properties file defining my values (for reuse purposes). What used to look like this
<bean id="d1" class="java.lang.Double">
<constructor-arg value="3.7"/>
</bean>
<bean id="foo" class="Foo">
<property name="doubleVal" ref="d1"/>
</bean>
gets refactored into this:
<bean
id="propertyFile"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="classpath:my.properties"
/>
<bean id="foo" class="Foo" p:doubleVal="${d1}"/>
Why don't you just use a Double? any reason?
Spring 2.5+
You can define bean like this in Java config:
#Configuration
public class BeanConfig {
#Bean
public Double doubleBean(){
return new Double(3.7);
}
}
You can use this bean like this in your program:
#Autowired
Double doubleBean;
public void printDouble(){
System.out.println(doubleBean); //sample usage
}