I have a set of unit tests. Some will use dataSource, others will want to use hsqlbDataSource. This datasource is not a wired bean into my unit tests/code, but is transitively used via templates and transaction managers. Therefore I intend to use bean defs like this:
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/myDataSource"
cache="true" resource-ref="true" lookup-on-startup="false"
proxy-interface="javax.sql.DataSource" />
<jee:jndi-lookup id="hsqlbDataSource" jndi-name="jdbc/myDataSource"
cache="true" resource-ref="true" lookup-on-startup="false"
proxy-interface="javax.sql.DataSource" />
<bean id="qmat-das-jdbcTemplate"
class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"
c:dataSource-ref="${test.datasource:dataSource}" />
<bean id="transactionManager"
class="org.springframework.transaction.jta.WebSphereUowTransactionManager">
<property name="dataSource" ref="${test.datasource:dataSource}"/>
</bean>
I want for my unit tests (there are many of them, of course) to pick and choose which datasource to use. Ideally what makes sense to me is for each unit test to have an annotation which sets the system property to override the default datasouce with its own. Is there an elegant way to achieve that without property files, but just set the java property via an annotation?
With an annotation it's not possible with out-of-the-box functionality, but have a look at Spring 3 profiles as it allows to activate/deactivate groups of beans.
The beans can be activated with system properties or via code. This code could be put in a test superclass to activate the test-only beans:
springContext.getEnvironment().setActiveProfiles("test")
Related
I've got a Spring Integration flow which uses an inbound gateway to get messages from an IBM MQ queue:
<int-jms:inbound-gateway id="InputGateway"
request-destination="RequestQueue"
request-channel="RequestChannel"
reply-channel="ReplyChannel"
/>
However I'm not capable of assigning security settings. In particular, I need an username, password and userAuthenticationMQCSP = false (for reasons beyond the scope of this post, I won't get into details but my broker will throw a MQRC = 2009 otherwise).
I've followed the IBM guide to connect with jmsTemplate and works just fine. This uses the official Spring boot starter from IBM MQ which will kindly create a connection factory and will autoconfigure it with some defaults from application.properties:
ibm.mq.queueManager=myQMName
ibm.mq.channel=myChannel
ibm.mq.connName=myhostname(myPort)
ibm.mq.user=username
ibm.mq.password=*******
ibm.mq.userAuthenticationMQCSP=false
Now, back to the Spring Integration case. According to the int-jms:inbound-gateway spec, a connectionFactory will be injected to the gateway, by name (attribute: connection-factory) which is set up to be "jmsConnectionFactory" by default
By default, all of the JMS adapters that require a reference to the
ConnectionFactory automatically look for a bean named
jmsConnectionFactory. That is why you do not see a connection-factory
attribute in many of the examples. However, if your JMS
ConnectionFactory has a different bean name, you need to provide that
attribute.
I don't see any way to set up a predictable name for the connection factory that I can plug into the int-jms:inbound-gateway.
Now, taking a different approach, as per this example I've created my connectionFactory with an adecuate name:
<bean id="jmsConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="transportType" value="1"/>
<property name="queueManager" value="myQMName"/>
<property name="hostName" value="myhostname"/>
<property name="port" value="myPort" />
<property name="channel" value="myChannel"/>
</bean>
But now I need somewhere to put the credentials and the security parameters. Looking at the example above, it looks like I need to plug something like:
<bean id="secureJmsConnectionAdapter" class="**yourpackages.SecureJMSConnectionAdapter**">
<property name="targetConnectionFactory" ref="${jms.mq.connection.factory}" />
<property name="userName" value="${jms.username}"/>
<property name="pwdAlias" value="${jms.alias}"/>
</bean>
However it is unclear to me how to implement this SecureJMSConnectionAdapter.
Additionally, if I set up my own connection factory, I will lose all of MQ boot starter automagic thanks to this annotation on the MQAutoConfiguration class:
#ConditionalOnMissingBean(value=javax.jms.ConnectionFactory.class)
Any ideas on how to put these pieces together?
EDIT: Just to avoid any possible red herrings to anyone, the MQRC2009 was irrelevant to ibm.mq.userAuthenticationMQCSP=false.
Some of my old projects I used a bean like this:
<bean id="jmsQueueConnectionFactory"
class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="jmsConnectionFactory"/>
<property name="username" value="${jms.username}"/>
<property name="password" value="${jms.alias}"/>
</bean>
Should work well as a wrapper for your com.ibm.mq.jms.MQQueueConnectionFactory, but you have to use this jmsQueueConnectionFactory in the target components.
Although it looks like the mentioned IBM MQ JMS Spring doesn't that for us properly exposing a jmsConnectionFactory bean. You can rely on the default from Spring Integration in this case or use that jmsConnectionFactory explicitly for the connection-factory.
Also with Spring Boot you should consider to go away from XML configuration and give a chance for Spring Integration Java DSL: https://docs.spring.io/spring-integration/docs/5.1.7.RELEASE/reference/html/#java-dsl
I was wondering if I can configure how spring boot handles internationalization using the application.properties file instead of writing it in code.
For example:
To define a LocaleChangeInterceptor I have to declare a bean like this:
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang" />
</bean>
However, a look at the most used properties in the documentation shows only 3 values that can be configured for internationalization:
# INTERNATIONALIZATION (MessageSourceAutoConfiguration)
spring.messages.basename=messages
spring.messages.cache-seconds=-1
spring.messages.encoding=UTF-8
So is there a way to achieve this? is there a convention on how to map this to a properties file?
is there a convention on how to map this to a properties file?
No there isn't. It's only a single bean definition and it's entirely optional, so I would prefer to leave that in Java.
I'm running tests using spring (SpringJUnit4ClassRunner and #ContextConfiguration). The tests are run in parallel.
Some of my beans are singleton, and I would like to change them to be in scope "thread" of the tests. I want each test to have its own instance of the bean.
I've managed to it by having an applicationContext.xml file and a applicationTestContext.xml file which is used for tests.
In the applicationTestContext.xml I define those beans with scope "thread".
The problem with this is that everytime we add a new bean of that type, we'll have to add it to both applicationContext.xml and applicationTestContext.xml which is pretty annoying.
Is there a way to do it with less boilerplate?
Gather up all the beans whose scope you want to customize and put them in a separate bean config file, included from both applicationContext and applicationTestContext, e.g.
<import resource="customScopedBeans.xml"/>
Then use a placeholder for the scope
<bean class="com.Foo" scope="${threadOrSingleton}" />
and declare the property differently in the parent config file.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties">
<value>threadOrSingleton=thread</value>
</property>
</bean>
I didn't write unit or integration testing but now I am trying. I am having a hard time setting up the environment.
I have my application context under WEB-INF/applicationContext*.xml
and in my applicationContext.xml, it has a reference to a properties file for DB user/pass, LDAP host, etc
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>/WEB-INF/spring-config/dev.properties</value>
</list>
</property>
</bean>
I have another properties for log4j config (diff config for DEV/Staging/Production). ${webapp.root} is defined in web.xml
<!-- log4j setting -->
<bean id="log4jInitialization" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="org.springframework.util.Log4jConfigurer" />
<property name="targetMethod" value="initLogging" />
<property name="arguments">
<list>
<value>${webapp.root}/${log4j.properties.location}</value>
</list>
</property>
</bean>
And now I am trying to put the following in a test class.
#Override
protected String[] getConfigLocations() {
return new String[]{
"file:trunk/code/web/WEB-INF/applicationContext.xml",
};
}
This references my xml correctly, but all the properties are screwed up.
I want to know the following:
Is there a way to set up in the test class properly? If not, should I move these classes?
How can I set up Log4j if there is a reference to webroot which only exist in a container?!
What is the best practice of Spring config location?
Please Advise
Thanks
This blogpost of mine describes the basic steps to achieve your goal.
Note that the unit tests shouldn't know that you have a webapp-root - they are usually run without any servlet container started. So place the alternative config files in the test packages and try.
For unit testing you should not be using the Spring application context. You should be testing all your spring beans and controllers individually as they are the individual units within the system. As they are POJOs it is easy to wire everything together programatically in your test case code. The also solves issues such as the location of the logging properties file as you can programatically specify a different path that does not rely on the webroot property.
The testing chapter in the Spring Reference provides a good overview of how to approach unit and integration testing of applications that use Spring. It also provides details of the various support classes that Spring provides to help with writing unit and integration tests.
You could use annotations to reference the necessary configuration from the tests, like this:
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class })
#ContextConfiguration(locations = {
"file:../WebService/src/main/resources/application-context.xml",
"file:../ServiceLayer/src/test/resources/ServiceLayer-dao-test-context.xml" })
public class MyTest {
// class body...
}
I am trying to use Log4j as part of the Spring Framework,
as far as i understand through the use of a an appropriate bean
the system is supposed to map a singleton instance accessible in the code
while mapping the logging depth automatically to the class
Similar to the normal use of Log4J as in
Logger log = Logger.getLogger(getClass());
i have been using the following Spring bean definition
<bean id="log4jInitialization"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass"
value="org.springframework.util.Log4jConfigurer" />
<property name="targetMethod" value="initLogging" />
<property name="arguments">
<list>
<value>conf\log4j.xml</value>
</list>
</property>
</bean>
But i am unable to map this bean to a specific member in a given class
nor am i able to use it through #autowired
Please let me know if there are any better ways to integrate Log4j and Spring
Best Regards
Mark
The short answer to your question is that log4j is not DI friendly.
The Log4jConfigurer.initLogging() method has a void return value, so there's nothing to inject. The idea is that you call that method, which bootstraps log4j, and then you use the Log4j API as usual (using Logger.getLogger(getClass())).
You generally wouldn't configure Log4jConfigurer as a Spring bean, though, but more usually you'd invoke it directly from your own code during application startup.
If this is a webapp, then Spring provides alternatives to Log4jConfigurer that are better suited to that environment (Log4jWebConfigurer, Log4jConfigListener).
Incidentally, 2 years ago I filed a feature request to allow loggers to be autowired, and it's finally been marked as fix for Spring 3.1. Horray.