I have a Maven project with multiple modules. Module ModuleB uses ModuleA as an internal Maven dependency. In moduleA I have a Spring xml config module.a.xml that loads a module.a.properties file. In the Spring xml config of moduleB I import the module.b.properties file together with the module.a.xml config.
In the end I end up with a Spring xml config with two property file imports. Depending of the order of the imports I can only access properties of one file: either module.a.properties or module.b.properties. How can I use both properties at the same time?
The problem with a solution using the PropertyPlaceholderConfigurer is that the properties files reside at different modules and moduleB shouldn't worry about a properties file of moduleA.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" id="corePlaceHolder">
<property name="locations">
<list>
<value>classpath:modula.a.properties</value>
<value>classpath:modula.b.properties</value>
</list>
</property>
</bean>
The problem with using ignore-unresolvable="true" is that a forgotten property can easily be missed and putting ignore-unresolvable="true" on the property-placeholder can easily be missed.
<context:property-placeholder location="module.a.properties" order="0" ignore-unresolvable="true"/>
<context:property-placeholder location="module.b.properties" order="1" ignore-unresolvable="true"/>
Not sure this can solve your problem but, since you are using a maven multi-module build, have you considered suing a maven plugin to create a third properties file as a merge of A and B with proper override strategy?
Here is a sample using maven-merge-properties-plugin
<plugin>
<groupId>org.beardedgeeks</groupId>
<artifactId>maven-merge-properties-plugin</artifactId>
<version>0.2</version>
<configuration>
<merges>
<merge>
<targetFile>${moduleB.output.dir}/module-final.properties</targetFile>
<propertiesFiles>
<propertiesFile>${moduleB.src.dir}/moduleB.properties</propertiesFile>
<propertiesFile>${moduleA.src.dir}/moduleA.properties</propertiesFile>
</propertiesFiles>
</merge>
</merges>
</configuration>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>merge</goal>
</goals>
</execution>
</executions>
</plugin>
In this way you will get all A and B properties in just on file. If a property exists on both A and B, B will win (check file order in configuration).
Being both modules in the same project retrieve both files should be quite easy.
You could even use another plugin to unpack just needed properties files from external jars.
Hope this helps.
Related
How can the Arquillian configuration file Arquillian.xml be shared between projects and team members?
<arquillian xmlns="http://jboss.org/schema/arquillian"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://jboss.org/schema/arquillian
http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<container qualifier="jbossas-managed-wildfly-8" default="true">
<configuration>
<property name="jbossHome">C:\test\wildfly-8.1.0.Final</property>
<property name="javaVmArguments">-Djboss.socket.binding.port-offset=2 -Xmx512m -XX:MaxPermSize=128m</property>
<property name="managementPort">9992</property>
</configuration>
</container>
The problem is this points to specific locations on the the disk, and different team members use Wildfly in different locations.
In addition we must duplicate Arquillian.xml for each project that uses it.
We use Arquillian for Maven testing (which could inject the values) and JUnit tests within Eclipse (which cannot inject them).
Any ideas how to do this?
Since there is already Maven support and structure then you can make use of Maven properties and replace of place holder values. It is simple
I guess your Arquillian.xml is under src/test/resources/arquillian.xml right? Then you can replace the absolute values with properties.
<configuration>
<property name="jbossHome">${jboss.home}</property>
</configuration>
The above property can be either defined in the properties section of your pom or can be overridden during mvn executuon using -Djboss.home=C:\myPath
In order though this thing to work, you want Maven automatically for each developer when is about to package arquillian.xml to replace this place-holder ${jboss.home} with a value, that we have either defined on top in the properties section or we have passed it from the command line. This is done through the resource filtering functionality
<build>
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
</testResource>
<testResources>
</build>
See the simple examples here
I have a project MyProject which has a dependency on configuration in another project, BaseProject. Inside BaseProject I have dependencies to many different projects like ErrorLogging, PerformanceLogging, etc... I want to be able to build the top level project (MyProject) and have it filter all the spring xml files in those projects that it has as dependencies. I'm not having any luck. I can see the beans but they are not being filtered. Some of the beans are being filtered with default filters defined in their own poms but non are using the filters from MyProject.
MyProject - This contains the filter files and imports the config from the other projects.
BaseProject - Has spring beans defined which require filtering.
ErrorLogging - Has spring beans defined which require filtering.
When I run a package from MyProject all the spring files are correctly extracted into the jar file but they still contain the property placeholder values ${error.logging.host} for example... The beans in MyProject are correctly filtered. The alternative to this is to define the beans in MyProject but there are about 10 of these projects which use BaseProject and it's beans and I do not want to have to redefine them across 10 seperate projects.
If anyone could shed any light on this issue it'd be great. Thanks
Edit :
To make this clearer, I have a spring beans xml definition inside of the project ErrorLogging called errors-config.xml which defines beans for connecting to databases. This just has place holders for the connection details which should be provided by the filter.properties file that is inside of MyProject.
errors-config.xml is imported as a resource into baseproject-config.xml which sits inside of the BaseProject. Base project and it's config file are imported to MyProject.
I then build MyProject using Maven and I would like the property placeholders inside of errors-config.xml to be replaced with the values in the filter.properties in MyProject. MyProject can successfully filter it's own files but not those of ErrorsLogging project. ErrorsLogging seems to pick up filters from it's own src/main/resources folder instead of that of MyProject.
You can achieve that by unpacking all the dependencies, filtering and packing again, the whole process depends on the structure of your project, for a basic configuration this may suffices:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack-dependencies</id>
<!--unpack all the dependencies to the target of this project-->
<phase>initialize</phase>
<inherited>false</inherited>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<configuration>
<includeGroupIds>${pom.groupId}</includeGroupIds>
<overWrite>true</overWrite>
<outputDirectory>${project.build.directory}/${artifactId}</outputDirectory>
<includes>**/*.properties,**/*.xml</includes>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>${config.maven.plattform.resources}/assembly/zip.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>zip</id>
<phase>package</phase>
<inherited>true</inherited>
<goals>
<goal>assembly</goal>
</goals>
</execution>
</executions>
</plugin>
This should work as long as you have correctly defined the correct filtering of the resources (which takes places later and also uses the maven-resources-plugin).
You could use the PropertyOverrideConfigurer to override the initial properties.
For example, if you have the folowing datasource definition in errors-config.xml :
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${hibernate.driverClassName}" />
<property name="jdbcUrl" value="${hibernate.url}" />
<property name="user" value="${hibernate.username}" />
<property name="password" value="${hibernate.password}" />
</bean>
You can override the database connection properties in the MyProject context like this :
<bean id="propertyOverideConfigurer" class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<property name="locations">
<list>
<value>filter.properties</value>
</list>
</property>
</bean>
And in the filter.properties file you need to specify the bean names and properties you wish to override :
datasource.driverClass = oracle.jdbc.driver.OracleDriver
datasource.jdbcUrl = jdbc:oracle:thin:#localhost:1521:xe
datasource.user = username
datasource.password = password
Hope this helps.
I'm using the jetty maven plugin to run a webapp locally and I'm getting a class cast exception when I try to pull in a JNDI resource.
I have a jetty config with a resource object, which is a configuration bean that is utilized via JNDI. This class resides in a different jar on the classpath that is in the lib directory:
<Configure class="org.mortbay.jetty.Server">
<New class="org.mortbay.jetty.plus.naming.Resource">
<Arg>config/MyConfigObject</Arg>
<Arg>
<New class="my.config.ConfigObject">
<Set name="foo">bar</Set>
</New>
</Arg>
</New>
</Configure>
This is retrieved via Spring:
<bean id="MyConfigObject" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/config/MyConfigObject" />
</bean>
Inside of a servlet, I'm grabbing the object manually:
final MyConfigObject config = (MyConfigObject) applicationContext.getBean("MyConfigObject");
But when I try to access the servlet, I get:
java.lang.ClassCastException: my.config.MyConfigObject cannot be cast to my.config.MyConfigObject
I'm pretty sure the problem is due to class loading, but I'm not 100% certain. MyConfigObject's class loader is the default sun class loader, while the thread's current class loader is jetty's WebAppClassLoader. My jar is in WEB-INF/lib, and I've even added it manually to extraClasspath in the maven plugin configuration:
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<version>6.1.25</version>
<configuration>
<jettyConfig>${basedir}/test/jetty.xml</jettyConfig>
<webAppSourceDirectory>${basedir}/target/${project.artifactId}</webAppSourceDirectory>
<webXml>${basedir}/war/WEB-INF/web.xml</webXml>
<webAppConfig>
<extraClasspath>${basedir}/target/${project.artifactId}/WEB-INF/lib/myConfigJar-1.0.jar</extraClasspath>
</webAppConfig>
</configuration>
<dependencies>
<dependency>
<groupId>testing</groupId>
<artifactId>myConfigJar</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</plugin>
I'm kind of stuck at this point. Does anyone know how to resolve this?
The problem is that you've got the jar listed in too many places - you attempts to add it to extraClasspath will actually make it worse, not better.
You say it's in WEB-INF/lib, but I assume it's also listed as a dependency in your pom.xml
You don't want to do that, you need to have 1 single reference to it. Either as a dependency in your pom.xml or in your lib directory, or in extraClasspath, but only in 1 place.
(Hint: pom.xml is almost certainly the right place, get rid of the others)
your webapp should not include the "my.config.MyConfigObject" class (and related classes) in it.
the underlying problem is that you are getting the class loaded by 2 different classloaders. you need to eliminate the class from your webapp classloader so that your webapp will use the same class that jetty is using.
I have two persistence.xml files, for the sake of testing:
src/main/resources/META-INF/persistence.xml
src/test/resources/META-INF/persistence.xml
How to instruct Maven to ignore the first file during testing? Now it is not ignored since OpenEJB says:
ERROR - FAIL ... Finder: #PersistenceContext unitName has multiple matches:
unitName "abc" has 2 possible matches.
Check out the alternate descriptors functionality which is aimed at what you're trying to do.
Try this setup:
src/main/resources/META-INF/persistence.xml
src/main/resources/META-INF/test.persistence.xml
Then you can construct OpenEJB to prefer the test.persistence.xml file by setting the openejb.altdd.prefix System or InitialContext property to test
A different possible solution could be to override the persistence unit properties in the test. With that approach you could avoid the need for a second persistence.xml which can be nice as maintaining two can be a pain.
You can use the Maven approach, but be aware that per spec the persistence provider will only look (aka scan) for #Entity beans in the exact jar or directory where the persistence.xml is found. So be keenly aware that in Maven these are two different locations:
target/classes
target/test-classes
EDIT More details on the overriding capabilities
You can override any property in your test setup via either system properties or the initial context properties (this includes jndi.properties files). The format is:
<unit-name>.<property>=<value>
So for example with the following persistence.xml:
<persistence>
<persistence-unit name="movie-unit">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>movieDatabase</jta-data-source>
<non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
<properties>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.max_fetch_depth" value="3"/>
</properties>
</persistence-unit>
</persistence>
You can override and add persistence unit properties in your test case. There are currently no facilities for removing them (if you have a need for that let us know – it hasn't really come up so far).
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY,"org.apache.openejb.client.LocalInitialContextFactory");
p.put("movie-unit.hibernate.hbm2ddl.auto", "update");
p.put("movie-unit.hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
context = new InitialContext(p);
Or alternatively via a jndi.properties file
java.naming.factory.initial=org.apache.openejb.client.LocalInitialContextFactory
movie-unit.hibernate.hbm2ddl.auto = update
movie-unit.hibernate.dialect = org.hibernate.dialect.HSQLDialect
I think you can create two profiles in your pom.xml:
<properties>
<environment>dev</environment>
</properties>
<profiles>
<profile>
<id>prod</id>
<properties>
<environment>test</environment>
</properties>
</profile>
</profiles>
After that, in your src folder, create two folders named dev/resoruces and test/resources and copy your different resources there. After that, add something like this:
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
<filtering>false</filtering>
</resource>
<resource>
<directory>${basedir}/src/main/${environment}/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
The ${basedir} depends on the command line parameter, it can be test or dev.
You run the maven command like this: mvn clean package -P test.
I have been testing these and other similar solutions without involving the pom.xml... In my opinion, the best way to solve this issue is to have two application-context.xml (one only to be used in test classes) and to add a custom persistence unit manager bean in the test's application-context.xml. Like this example:
<bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocation">
<value>classpath*:META-INF/test.persistence.xml</value>
</property>
<property name="defaultDataSource" ref="dataSource"/>
</bean>
This solution runs.
:)
Better add both files - in general, making test/production or debug/profile/production distinction in build makes only trouble.
Better try to use different perasistence unit name for production (say abc-production) and for tests (abc-tests).
I have very simple persistance.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="eventractor" transaction-type="RESOURCE_LOCAL">
<class>pl.michalmech.eventractor.domain.User</class>
<class>pl.michalmech.eventractor.domain.Address</class>
<class>pl.michalmech.eventractor.domain.City</class>
<class>pl.michalmech.eventractor.domain.Country</class>
<properties>
<property name="hibernate.hbm2ddl.auto" value="validate" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
and it works.
But when I remove <class> elements application doesn't see entities (all classes are annotated with #Entity).
Is there any automatic mechanism to scan for #Entity classes?
The persistence.xml has a jar-file that you can use. From the Java EE 5 tutorial:
<persistence>
<persistence-unit name="OrderManagement">
<description>This unit manages orders and customers.
It does not rely on any vendor-specific features and can
therefore be deployed to any persistence provider.
</description>
<jta-data-source>jdbc/MyOrderDB</jta-data-source>
<jar-file>MyOrderApp.jar</jar-file>
<class>com.widgets.Order</class>
<class>com.widgets.Customer</class>
</persistence-unit>
</persistence>
This file defines a persistence unit
named OrderManagement, which uses a
JTA-aware data source jdbc/MyOrderDB. The jar-file and class elements specify managed persistence classes: entity classes, embeddable classes, and mapped superclasses. The jar-file element specifies JAR files that are visible to the packaged persistence unit that contain managed persistence classes, while the class element explicitly names managed persistence classes.
In the case of Hibernate, have a look at the Chapter2. Setup and configuration too for more details.
EDIT: Actually, If you don't mind not being spec compliant, Hibernate supports auto-detection even in Java SE. To do so, add the hibernate.archive.autodetection property:
<persistence-unit name="eventractor" transaction-type="RESOURCE_LOCAL">
<!-- This is required to be spec compliant, Hibernate however supports
auto-detection even in JSE.
<class>pl.michalmech.eventractor.domain.User</class>
<class>pl.michalmech.eventractor.domain.Address</class>
<class>pl.michalmech.eventractor.domain.City</class>
<class>pl.michalmech.eventractor.domain.Country</class>
-->
<properties>
<!-- Scan for annotated classes and Hibernate mapping XML files -->
<property name="hibernate.archive.autodetection" value="class, hbm"/>
<property name="hibernate.hbm2ddl.auto" value="validate" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
In Java SE environment, by specification you have to specify all classes as you have done:
A list of all named managed persistence classes must be specified in Java SE environments to insure portability
and
If it is not intended that the annotated persistence classes contained in the root of the persistence unit be included in the persistence unit, the exclude-unlisted-classes element should be used. The exclude-unlisted-classes element is not intended for use in Java SE environments.
(JSR-000220 6.2.1.6)
In Java EE environments, you do not have to do this as the provider scans for annotations for you.
Unofficially, you can try to set <exclude-unlisted-classes>false</exclude-unlisted-classes> in your persistence.xml. This parameter defaults to false in EE and truein SE. Both EclipseLink and Toplink supports this as far I can tell. But you should not rely on it working in SE, according to spec, as stated above.
You can TRY the following (may or may not work in SE-environments):
<persistence-unit name="eventractor" transaction-type="RESOURCE_LOCAL">
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.hbm2ddl.auto" value="validate" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
Do I need Class elements in persistence.xml?
No, you don't necessarily. Here is how you do it in Eclipse (Kepler tested):
Right click on the project, click Properties, select JPA, in the Persistence class management tick Discover annotated classes automatically.
For those running JPA in Spring, from version 3.1 onwards, you can set packagesToScan property under LocalContainerEntityManagerFactoryBean and get rid of persistence.xml altogether.
Here's the low-down
You can provide for jar-file element path to a folder with compiled classes. For example I added something like that when I prepared persistence.xml to some integration tests:
<jar-file>file:../target/classes</jar-file>
for JPA 2+ this does the trick
<jar-file></jar-file>
scan all jars in war for annotated #Entity classes
Hibernate doesn't support <exclude-unlisted-classes>false</exclude-unlisted-classes> under SE, (another poster mentioned this works with TopLink and EclipseLink).
There are tools that will auto-generate the list of classes to persistence.xml e.g. the Import Database Schema wizard in IntelliJ. Once you've got your project's initial classes in persistence.xml it should be simple to add/remove single classes by hand as your project progresses.
Not sure if you're doing something similar to what I am doing, but Im generating a load of source java from an XSD using JAXB in a seperate component using Maven. Lets say this artifact is called "base-model"
I wanted to import this artifact containing the java source and run hibernate over all classes in my "base-model" artifact jar and not specify each explicitly. Im adding "base-model" as a dependency for my hibernate component but the trouble is the tag in persistence.xml only allows you to specify absolute paths.
The way I got round it is to copy my "base-model" jar dependency explictly to my target dir and also strip the version of it. So whereas if I build my "base-model" artifact it generate "base-model-1.0-SNAPSHOT.jar", the copy-resources step copies it as "base-model.jar".
So in your pom for the hibernate component:
<!-- We want to copy across all our artifacts containing java code
generated from our scheams. We copy them across and strip the version
so that our persistence.xml can reference them directly in the tag
<jar-file>target/dependency/${artifactId}.jar</jar-file> -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.5.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>process-resources</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
</execution>
</executions>
<configuration>
<includeArtifactIds>base-model</includeArtifactIds>
<stripVersion>true</stripVersion>
</configuration>
</plugin>
Then I call the hibernate plugin in the next phase "process-classes":
<!-- Generate the schema DDL -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>hibernate3-maven-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>generate-ddl</id>
<phase>process-classes</phase>
<goals>
<goal>hbm2ddl</goal>
</goals>
</execution>
</executions>
<configuration>
<components>
<component>
<name>hbm2java</name>
<implementation>annotationconfiguration</implementation>
<outputDirectory>/src/main/java</outputDirectory>
</component>
</components>
<componentProperties>
<persistenceunit>mysql</persistenceunit>
<implementation>jpaconfiguration</implementation>
<create>true</create>
<export>false</export>
<drop>true</drop>
<outputfilename>mysql-schema.sql</outputfilename>
</componentProperties>
</configuration>
</plugin>
and finally in my persistence.xml I can explicitly set the location of the jar thus:
<jar-file>target/dependency/base-model.jar</jar-file>
and add the property:
<property name="hibernate.archive.autodetection" value="class, hbm"/>
It's not a solution but a hint for those using Spring:
I tried to use org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean with setting persistenceXmlLocation but with this I had to provide the <class> elements (even if the persistenceXmlLocation just pointed to META-INF/persistence.xml).
When not using persistenceXmlLocation I could omit these <class> elements.
I'm not sure this solution is under the spec but I think I can share for others.
dependency tree
my-entities.jar
Contains entity classes only. No META-INF/persistence.xml.
my-services.jar
Depends on my-entities. Contains EJBs only.
my-resources.jar
Depends on my-services. Contains resource classes and META-INF/persistence.xml.
problems
How can we specify <jar-file/> element in my-resources as the version-postfixed artifact name of a transient dependency?
How can we sync the <jar-file/> element's value and the actual transient dependency's one?
solution
direct (redundant?) dependency and resource filtering
I put a property and a dependency in my-resources/pom.xml.
<properties>
<my-entities.version>x.y.z-SNAPSHOT</my-entities.version>
</properties>
<dependencies>
<dependency>
<!-- this is actually a transitive dependency -->
<groupId>...</groupId>
<artifactId>my-entities</artifactId>
<version>${my-entities.version}</version>
<scope>compile</scope> <!-- other values won't work -->
</dependency>
<dependency>
<groupId>...</groupId>
<artifactId>my-services</artifactId>
<version>some.very.sepecific</version>
<scope>compile</scope>
</dependency>
<dependencies>
Now get the persistence.xml ready for being filtered
<?xml version="1.0" encoding="UTF-8"?>
<persistence ...>
<persistence-unit name="myPU" transaction-type="JTA">
...
<jar-file>lib/my-entities-${my-entities.version}.jar</jar-file>
...
</persistence-unit>
</persistence>
Maven Enforcer Plugin
With the dependencyConvergence rule, we can assure that the my-entities' version is same in both direct and transitive.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.4.1</version>
<executions>
<execution>
<id>enforce</id>
<configuration>
<rules>
<dependencyConvergence/>
</rules>
</configuration>
<goals>
<goal>enforce</goal>
</goals>
</execution>
</executions>
</plugin>
Not necessarily in all cases.
I m using Jboss 7.0.8 and Eclipselink 2.7.0. In my case to load entities without adding the same in persistence.xml, I added the following system property in Jboss Standalone XML:
<property name="eclipselink.archive.factory" value="org.jipijapa.eclipselink.JBossArchiveFactoryImpl"/>