Showing posts with label maven2. Show all posts
Showing posts with label maven2. Show all posts

Monday, December 1, 2008

Improvement to code generated projects

In my previous post Executing a maven 2 plugin task more than once I exhibited an example where it's possible to run a plugin task a few times to generate several JAXB java beans from a XSD schema. The problem with this approach is that it is still not very intuitive since you'll find yourself filling your project dir with extra directories for generated src files ($basedir/packageA and $basedir/packageB in our case). This creates confusion since you'll soon lose track of these files and attempt to check them in to the respository if you are not careful.

That being said, I'll show you a better alternative to organize your projects. To get started, let's lay out the proposed structure (this time we will have 1 project for each XSD and then another project for the java project that uses them):


+-my_java_project
| `-src/main/java
| `-src/main/resources
|
+-my_xsd_project_a
| `-src/main/resources
|
`-my_xsd_project_b
`-src/main/resources


Now, let's examine the pom.xml used for XSD projects:


<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany</groupId>
<artifactId>my_xsd_project_a</artifactId>
<packaging>jar</packaging>
<name>My Company - Project A</name>
...
<build>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<executions>
<!-- Configuration for packageA -->
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>

<!-- Common JAXB configuration -->
<configuration>
<!-- Changes the default schema directory -->
<schemaDirectory>../xml-schemas-project/</schemaDirectory>
<extension>true</extension>
<generatePackage>com.mycompany.packageA</generatePackage>
<generateDirectory>generated-src-packageA</generateDirectory>
<schemaIncludes>
<include>xml-schemas/packageA/packageA.xsd</include>
</schemaIncludes>
</configuration>
</plugin>
</plugins>
</build>
</project>


Note that the configuration section has been extracted out of the <execution/> tag since we don't have any other <execution/> which needs particular configuration, thus we can move the configuration to the global configuration part of the plugin.

Next, if we run "mvn clean install" we will get a package with the generated classes in it. So, in order to use the generated classes we only need to include the my_xsd_project_a project as a maven2 dependency to my_java_project and that's it. Here's an example:


<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany</groupId>
<artifactId>my_java_project</artifactId>
<packaging>jar</packaging>
<name>My Company - My Java Project</name>
...
<dependencies>
<!-- Dependency to my_xsd_project_a (generated by JAXB) -->
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>my_xsd_project_a</artifactId>
</dependency>

<!-- Dependency to my_xsd_project_b (generated by JAXB) -->
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>my_xsd_project_b</artifactId>
</dependency>
</dependencies>
</project>

Executing a maven 2 plugin task more than once

For one particular project I needed to execute a task defined by a maven2 plugin more than once. I had to dig around maven site for a few hours to finally arrive at the deep-buried Using the executions tag page explaination saying that maven2 supported <executions/> in case you need to run several <execution/> with different configurations. So for saving me the trouble in the future and for you folks, here's an example:


<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<executions>
<!-- Configuration for packageA -->
<execution>
<id>JAXB - packageA</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<generatePackage>com.mycompany.packageA</generatePackage>
<generateDirectory>generated-src-packageA</generateDirectory>
<schemaIncludes>
<include>xml-schemas/packageA/packageA.xsd</include>
</schemaIncludes>
</configuration>
</execution>

<!-- Configuration for packageB -->
<execution>
<id>JAXB - packageB</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<generatePackage>com.mycompany.packageB</generatePackage>
<generateDirectory>generated-src-packageB</generateDirectory>
<schemaIncludes>
<include>xml-schemas/packageB/packageB.xsd</include>
</schemaIncludes>
</configuration>
</execution>
</executions>

<!-- Common JAXB configuration -->
<configuration>
<!-- Changes the default schema directory -->
<schemaDirectory>../xml-schemas-project/</schemaDirectory>
<extension>true</extension>
</configuration>
</plugin>

Working with JDBC datasources with Maven2

During my career I've seen too many database-driven maven2 projects that use maven 2 filtering of resources for jdbc properties in order to externalize the username, password, jdbc url and other JDBC specific configuration to $USER/.m2/settings.xml. The problem with this approach is that we become locked-in to maven2 and won't be able to run a simple JUnit test without first running "mvn clean install", so that the placeholders in jdbc properties file get replaced with the appropriate values from settings.xml.

In my opinion, jdbc properties file should be avoided at all if possible. In a web application for example, it's possible to create a datasource at the container (e.g. Tomcat) and then reference this datasource from the application via JNDI. By doing this, we can happily use JDBC datasources without having to run "mvn clean install", making the life for those folks building inside Eclipse much easier.

Now, we don't always want to run our code inside a container. One such example is when we are running unit tests. For those cases we should create a base JUnit class that is specific to our module, say "MyProjectModuleTestCase" and inject JNDI datasource as explained in Randy Carver's blog post Injecting JNDI datasources for JUnit Tests outside of a container.