I have this weird behavior working with the Maven <filter> tag and Spring configs . My understanding is that a Spring config is a plain XML file to Maven but I'm encountering issues with the <context:component-scan base-package="com.xyz"/> tag . The test XML file is as below
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd"
default-autowire="byName">
<!-- Import the DataSource configurations -->
<import resource="classpath:spring/MyDataSource.xml"/>
<!-- Property File location -->
<context:property-placeholder location="${ext.properties.dir}"/>
<!--The services are auto-detected POJOs labeled with the #Service annotation.-->
<context:component-scan base-package="com.xyz"/>
</beans>
and the Maven profiles configuration as below
<build>
.....
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<filters>
<filter>src/main/resources/build/build-${environment}.properties</filter>
</filters>
</build>
<profiles>
<profile>
<id>uat</id>
<activation>
<property>
<name>env</name>
<value>uat</value>
</property>
</activation>
<properties>
<environment>uat</environment>
</properties>
</profile>
<profile>
<id>prod</id>
<activation>
<property>
<name>env</name>
<value>prod</value>
</property>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<environment>prod</environment>
</properties>
</profile>
</profiles>
Contents of build-dev.properties are
ext.properties.dir=file:///C:/Temp/myProp.properties
My issue was that the Maven profile filtering was not working and the property ${ext.properties.dir} was not getting replaced during the packaging process . It stated working when I removed the <context:component-scan base-package="com.xyz"/> tag and hence I placed it below the property which needs to be filtered . Now everything works fine . My question is what's the issue with <context:component-scan base-package="com.xyz"/> ?
I do not think that <context:component-scan base-package="com.xyz"/> but the comment above
<!--The services are auto-detected POJOs labeled with the #Service annotation.-->
The # has a special meaning in maven fitlers.
To be honest I have the feeling that there are to many overlapping in syntax between spring configuration files and maven filters to use them together. My "solution" is to use (as long as possible) two files for the spring configuration.
a Property file, that is manipulated by spring filters
a normal Spring configuration file (with placeholders) that uses a PropertyPlaceholder Configurer to load the property file.
Related
I'm creating a project which is on two modules: service and web
in service i'am injecting beans with properties defined in web module. properties depends on profiles defined in web module.
at jetty start a spring errors have been displayed informing me that he can't read properties so he can't instanciate beans.
So how to declare properties in web module and use them in service module?
in service module I'am injecting a bean which uses properties declared in another module
<bean id="universignService"
class="fr.lfm.dna.service.file.document.impl.UniversignServiceImpl"
autowire="byName" init-method="initWebService" lazy-init="true">
<property name="url" value="${ws.universign.url}">
</property>
<property name="username" value="${dna.ws.universign.username}">
</property>
<property name="password" value="${dna.ws.universign.password}">
</property>
</bean>
Well, as I understand, you have 2(ServiceProject and WebProject) maven projects. In ServiceProject you want to use propeties from WebProject/pom.xml. The thing is Spring doesn't know anything about this file.
There are few options, if you want to share these properties for multiple projects.
1) The first that comes to my mind is to create a parent maven-project. It's going to be a project with just one pom.xml, where you can define your properties in properties section.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>parent</artifactId>
<version>1.0.SNAPSHOT</version>
<properties>
<dna.ws.universign.username>ABC</dna.ws.universign.username>
<dna.ws.universign.password>XYZ</dna.ws.universign.password>
</properties>
</project>
After you do this, you can refer to this project in other projects.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>web</artifactId>
<parent>
<groupId>com.test</groupId>
<artifactId>parent</artifactId>
<version>1.0.SNAPSHOT</version>
</parent
</project>
As a result, properties from you parent project are included in your actual project (com.tests.web in my example).
2) Speaking of storing an username and a password, it might be more convenient and more natural to store them in an external *.properties file. In this case you don't need to create a parent project. Try to take a look at maven-properies-plugin.
Whether way you chose, after your properties are defined on maven-level, you should pass it to spring config. In case you use xml-configuration (like in your post), you should ask maven to process files with such ${...} placeholders. Just put this xml in your pom.xml:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>spring-config.xml</include>
</includes>
</resource>
</resources>
</build>
Where spring-config.xml is a file, where you store your configuration. After this, properties can be injected by Spring.
I have a situation. I am testing bunch of .drl files using the kie-spring. The DRL files are found/scanned only when they are co-located in the src/test/resources folder and not in the src/main/resources/ folder.
I even moved the drl files to a separate jar project/file into a src/main/resources folder along with the kie-spring .xml files. Still no luck! The following is the warning I get!
2014-09-30 15:24:51,227 [AbstractKieModule] [main] WARN No files found for KieBase MASTRT_KBase, searching folder \Users\mmadhavan.FACS_ORG\workspace\org.ncdb.facs.measures\target\test-classes
The following is my xml file!
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:kie="http://drools.org/schema/kie-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://drools.org/schema/kie-spring http://drools.org/schema/kie-spring.xsd">
<kie:kmodule id="kbase_inlist_op_test_rules">
<kie:kbase name="MASTRT_KBase" packages="org.xxx.xxx.xxxxx.drl.cancer.MASTRT">
<kie:ksession name="MASTRT_KSession" type="stateless" scope="prototype"/>
</kie:kbase>
</kie:kmodule>
<bean id="kiePostProcessor" class="org.kie.spring.annotations.KModuleAnnotationPostProcessor"/>
</beans>
I solved adding src/main/resources to testResources in pom.xml
<build>
<testResources>
<testResource>
<directory>${basedir}/src/test/resources</directory>
</testResource>
<testResource>
<directory>${basedir}/src/main/resources</directory>
</testResource>
</testResources>
</build>
I'm using maven build helper to automatically add integration-test/java and integration-test/resources folders to my project classpath. It works great when I run my tests with JUnit in Eclipse, but got a problem when I ran the web project where Tomcat always pick up the test resources instead of the production one.
My project structure is something like this:
DaoProject
src/main/resources/datasource.properties
src/main/resources/spring-data.xml
src/main/java/....
WebProject
src/main/resources/appContext.xml
src/integration-test/java/com/mypkg/controller/MyControllerIT.java
src/integration-test/resources/datasource.properties
The appContext.xml imports spring-data.xml which in turn loads datasource.properties as a propterties source place holder.
appContext.xml contents:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<context:annotation-config />
<tx:annotation-driven/>
<context:component-scan base-package="com.mypkg" />
<mvc:annotation-driven />
<mvc:resources mapping="/resources/**" location="/resources/" />
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"
p:defaultEncoding="UTF-8">
<property name="basenames">
<array>
<value>messages</value>
</array>
</property>
</bean>
<import resource="classpath:datasource.xml" />
datasource.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
>
<context:property-placeholder location="classpath:datasources.properties"/>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="${config.db.url}" />
<property name="username" value="${config.db.username}" />
<property name="password" value="${config.db.password}" />
pom.xml:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>add-integration-test-sources</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>src/integration-test/java</source>
</sources>
</configuration>
</execution>
<execution>
<id>add-integration-test-resources</id>
<phase>generate-test-resources</phase>
<goals>
<goal>add-test-resource</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>src/integration-test/resources</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
I think that the problem is with the way you load the datasource.properties file. Try specifying the entire path in the location attribute of the PropertyPlaceholderConfigurer:
<context:property-placeholder location="classpath:src/main/resources/datasources.properties"/>
Hope this helps.
I'm running JUnit tests with Maven profile.
Maven profile looks so:
<profile>
<id>someProfile</id>
<properties>
...
<some.param>some_value</some.param>
...
</properties>
</profile>
Spring context file(testContext.xml):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
...
xmlns:p="http://www.springframework.org/schema/p"
...
xsi:schemaLocation="...">
<bean id="someBean" class="someClass"
scope="singleton"
autowire="byName"
init-method="init"
p:someBeanParam="${some.param}"/>
</beans>
And test class begins so:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/testContext.xml"})
#Configurable
...
After running maven, I saw that testContext.xml wasn't changed - p:someBeanParam still had value ${some.param}.
Could you tell, please, what's the problem here and how to solve it?
Thank you in advance.
Enable resource filtering like this
<project>
...
<build>
...
<resources>
...
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
...
</resources>
<testResources>
...
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
</testResource>
...
</testResources>
...
</build>
....
Define variable for each profile and when no profile is used.
More information on Maven Resource Plugin page.
mvn -P dev
If I build my project using profile dev, then I want to use dev.properties in my spring bean like below. Is it possible ? If so , how could I get profile name ?
<bean id="xyz" class="abc.xyz">
<property name="propertyFile" value="${maven_profile_id}.properties" />
</bean>
Thanks in advance.
You can use Maven profiles to add a 'profile' property to the build:
<profiles>
<profile>
<id>dev</id>
<properties>
<profile>dev</profile>
</properties>
</profile>
</profiles>
Then pass the value into your application using a system property, here's an example with surefire:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<profile>${profile}</profile>
</systemPropertyVariables>
</configuration>
</plugin>
Finally this can be referenced in you application:
<bean id="xyz" class="abc.xyz">
<property name="propertyFile" value="${profile}.properties" />
</bean>
Alternatively, if you are using Spring 3.1 or later you might find the XML profile feature meets your needs (although it may be overkill).
Create a properties file that will be populated using Maven's resource filtering that specifies the profile you are using at build time.
build.properties
activatedProfile=${profileId}
pom.xml (You don't need to filter the complete directory, customise as required)
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<resources>
</build>
Add a profileId (or whatever you want to call it) property under each different profile:
<profile>
<id>dev</id>
<properties>
<profileId>dev</profileId>
</properties>
</profile>
<profile>
<id>qa</id>
<properties>
<profileId>qa</profileId>
</properties>
</profile>
You can then use ${activatedProfile}.properties as value for a bean
<bean id="xyz" class="abc.xyz">
<property name="propertyFile" value="${activatedProfile}.properties" />
</bean>