Enterprise Java Development@TOPIC@

Chapter 23. Create JPA Parent POM

23.1. Summary

Since you will likely have many JPA modules in your enterprise application, lets take a moment to break the current module into a parent and child before you quit. That way you can better visualize which parts are specific to the child module and which are reusable from a common parent.

  1. Create a sibling module called ../jpa-parent

    
    $ mkdir ../jpa-parent
  2. Add the module definition (../jpa-parent/pom.xml)

    
    <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>myorg.jpa</groupId>
        <artifactId>jpa-parent</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>pom</packaging>

        <name>JPA Parent POM</name>
        <description>
            This parent pom is intended to provide common and re-usable 
            definitions and constructs across JPA projects.
        </description>
    </project>
  3. Add the following parent declaration to your existing module. The relativePath is only useful if you find yourself changing the parent pom on a frequent basis. Otherwise the parent module can be found in the localRepository once it has been installed.

    
        <parent>
            <groupId>myorg.jpa</groupId>
            <artifactId>jpa-parent</artifactId>
            <version>1.0-SNAPSHOT</version>
            <relativePath>../jpa-parent</relativePath>
        </parent>

        <groupId>myorg.jpa</groupId>
        <artifactId>entityMgrEx-child</artifactId>

        <name>Entity Manager Exercise</name>
  4. Verify your project still builds. This will verify your relativePath is correct.

    $mvn clean verify
    ...
    [INFO] BUILD SUCCESS
  5. Move the following constructs from the entityMgrEx module to the jpa-parent module. These represent the *passive* definitions that will not directly impact the child module until the child requests that feature. Your child module should still have the same build and test functionality except now it should look a little smaller. One could also make a case for moving some of the SQL/DDL script execution definitions also to the parent -- which would make this module almost of trivial size.

    • properties

    • repositories

    • dependencyManagement

    • pluginManagement

    • select profiles

    
    <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>myorg.jpa</groupId>
        <artifactId>jpa-parent</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>pom</packaging>

        <name>JPA Parent POM</name>
        <description>
            This parent pom is intended to provide common and re-usable 
            definitions and constructs across JPA projects.
        </description>

        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <java.source.version>1.8</java.source.version>
            <java.target.version>1.8</java.target.version>

            <jboss.host>localhost</jboss.host>
            <db.host>${jboss.host}</db.host>

            <maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
            <maven-jar-plugin.version>3.1.0</maven-jar-plugin.version>
            <maven-surefire-plugin.version>2.22.0</maven-surefire-plugin.version>
            <sql-maven-plugin.version>1.5</sql-maven-plugin.version>        

            <h2db.version>1.4.197</h2db.version>
            <javax.persistence-api.version>2.2</javax.persistence-api.version>
            <hibernate-entitymanager.version>5.3.1.Final</hibernate-entitymanager.version>
            <junit.version>4.12</junit.version>
            <log4j.version>1.2.17</log4j.version>
            <slf4j.version>1.7.25</slf4j.version>
            <ejava.version>5.0.0-SNAPSHOT</ejava.version>
        </properties>

        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>javax.persistence</groupId>
                    <artifactId>javax.persistence-api</artifactId>
                    <version>${javax.persistence-api.version}</version>
                </dependency>        
                <dependency>
                    <groupId>org.hibernate</groupId>
                    <artifactId>hibernate-core</artifactId>
                    <version>${hibernate-entitymanager.version}</version>
                </dependency>
                <dependency>
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                    <version>${junit.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                    <version>${slf4j.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                    <version>${slf4j.version}</version>
                </dependency>
                <dependency>
                  <groupId>log4j</groupId>
                  <artifactId>log4j</artifactId>
                  <version>${log4j.version}</version>
                </dependency>    
            </dependencies>
        </dependencyManagement>

        <build>
            <pluginManagement>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-compiler-plugin</artifactId>
                        <version>${maven-compiler-plugin.version}</version>
                        <configuration>
                                <source>${java.source.version}</source>
                                <target>${java.target.version}</target>
                        </configuration>                    
                    </plugin>      

                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-jar-plugin</artifactId>
                        <version>${maven-jar-plugin.version}</version>
                    </plugin>

                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-surefire-plugin</artifactId>
                        <version>${maven-surefire-plugin.version}</version>
                        <configuration>
                            <argLine>${surefire.argLine}</argLine>
                            <systemPropertyVariables>
                                <property.name>value</property.name>
                            </systemPropertyVariables>
                        </configuration>
                    </plugin>            

                    <plugin>
                        <groupId>info.ejava.utils.jpa</groupId>
                        <artifactId>jpa-schemagen-maven-plugin</artifactId>
                        <version>${ejava.version}</version>
                        <executions>
                            <execution>
                                <goals>
                                  <goal>generate</goal>
                                </goals>
                            </execution>
                        </executions>
                   </plugin>

                   <plugin>
                       <groupId>org.codehaus.mojo</groupId>
                       <artifactId>sql-maven-plugin</artifactId>        
                       <version>${sql-maven-plugin.version}</version>        
                    
                       <dependencies>
                           <dependency>
                               <groupId>com.h2database</groupId>
                               <artifactId>h2</artifactId>
                               <version>${h2db.version}</version>
                           </dependency>
                       </dependencies>
                    
                       <configuration>
                           <username>${jdbc.user}</username>
                           <password>${jdbc.password}</password>
                           <driver>${jdbc.driver}</driver>
                           <url>${jdbc.url}</url>          
                       </configuration>
                    </plugin>
                </plugins>    
            </pluginManagement>
        </build>

        <profiles>
            <profile> <!-- H2 server-based DB -->
                <id>h2srv</id>
                <properties>
                      <jdbc.driver>org.h2.Driver</jdbc.driver>
                      <jdbc.url>jdbc:h2:tcp://${db.host}:9092/./h2db/ejava</jdbc.url>
                      <jdbc.user>sa</jdbc.user>
                      <jdbc.password/>
                      <hibernate.dialect>org.hibernate.dialect.H2Dialect</hibernate.dialect>
                </properties>
                <dependencies>
                    <dependency>
                        <groupId>com.h2database</groupId>
                        <artifactId>h2</artifactId>
                        <version>${h2db.version}</version>
                        <scope>test</scope>
                    </dependency>
                </dependencies>
            </profile>

            <profile> <!-- H2 file-based DB -->
                <id>h2db</id>
                <activation>
                    <property> 
                        <name>!jdbcdb</name>
                    </property>
                </activation>
                <properties>
                      <jdbc.driver>org.h2.Driver</jdbc.driver>
                      <jdbc.url>jdbc:h2:${basedir}/target/h2db/ejava</jdbc.url>
                      <jdbc.user>sa</jdbc.user>
                      <jdbc.password/>
                      <hibernate.dialect>org.hibernate.dialect.H2Dialect</hibernate.dialect>
                </properties>
                <dependencies>
                    <dependency>
                        <groupId>com.h2database</groupId>
                        <artifactId>h2</artifactId>
                        <version>${h2db.version}</version>
                        <scope>test</scope>
                    </dependency>
                </dependencies>
            </profile>

            <profile>
                <id>testing</id>
                <activation>
                    <property>
                        <name>!skipTests</name>
                    </property>
                </activation>
          
                <build>
                    <plugins>
                        <plugin>
                            <!-- runs schema against the DB -->
                            <groupId>org.codehaus.mojo</groupId>
                            <artifactId>sql-maven-plugin</artifactId>        

                            <executions>

                                <!-- place execution elements here  -->
                                <execution>
                                    <id>drop-db-before-test</id>
                                    <phase>process-test-classes</phase>
                                    <goals>
                                        <goal>execute</goal>
                                    </goals>
                                    <configuration>
                                        <autocommit>true</autocommit>
                                        <orderFile>decending</orderFile>
                                        <fileset>
                                            <basedir>${basedir}/src</basedir>
                                            <includes>
                                                <include>main/resources/ddl/**/*tuningremove*.ddl</include>
                                                <include>main/resources/ddl/**/*drop*.ddl</include>
                                            </includes>
                                        </fileset>
                                        <onError>continue</onError>
                                    </configuration>
                                </execution>

                                <execution>
                                    <id>create-db-before-test</id>
                                    <phase>process-test-classes</phase>
                                    <goals>
                                        <goal>execute</goal>
                                    </goals>
                                    <configuration>
                                        <autocommit>true</autocommit>
                                        <orderFile>ascending</orderFile>
                                        <fileset>
                                            <basedir>${basedir}/src</basedir>
                                            <includes>
                                                <include>main/resources/ddl/**/*create*.ddl</include>
                                                <include>main/resources/ddl/**/*tuningadd*.ddl</include>                 
                                            </includes>
                                        </fileset>
                                        <print>true</print>
                                    </configuration>
                                </execution>

                                <execution>
                                    <id>populate-db-before-test</id>
                                    <phase>process-test-classes</phase>
                                    <goals>
                                        <goal>execute</goal>
                                    </goals>
                                    <configuration>
                                        <autocommit>true</autocommit>
                                        <fileset>
                                            <basedir>${basedir}/src</basedir>
                                            <includes>
                                                <include>test/resources/ddl/**/*populate*.ddl</include>
                                            </includes>
                                        </fileset>
                                    </configuration>
                                </execution>

                                <!--
                                <execution>
                                    <id>drop-db-after-test</id>
                                    <phase>test</phase>
                                    <goals>
                                        <goal>execute</goal>
                                    </goals>
                                    <configuration>
                                        <autocommit>true</autocommit>
                                        <fileset>
                                            <basedir>${basedir}/src</basedir>
                                            <includes>
                                                <include>main/resources/ddl/**/*drop*.ddl</include>     
                                                </includes>
                                        </fileset>
                                    </configuration>
                                </execution>
                                -->
                            </executions>
                        </plugin>          
                    </plugins>          
                </build>
            </profile>
            
            <!--  tell Eclipse what to do with some of the plugins -->
            <profile>
              <id>m2e</id>
              <activation>
                <property>
                  <name>m2e.version</name>
                </property>
              </activation>
              <build>
                <pluginManagement>
                    <plugins>
                        <plugin>
                          <groupId>org.eclipse.m2e</groupId>
                          <artifactId>lifecycle-mapping</artifactId>
                          <version>1.0.0</version>
                          <configuration>
                            <lifecycleMappingMetadata>
                              <pluginExecutions>
                                
                                <pluginExecution>
                                  <pluginExecutionFilter>
                                    <groupId>org.codehaus.mojo</groupId>
                                    <artifactId>sql-maven-plugin</artifactId>
                                    <versionRange>[1.0.0,)</versionRange>
                                    <goals>
                                      <goal>execute</goal>
                                    </goals>
                                  </pluginExecutionFilter>
                                  <action>
                                    <ignore />
                                  </action>
                                </pluginExecution>

                              </pluginExecutions>
                            </lifecycleMappingMetadata>
                          </configuration>
                        </plugin>

                    </plugins>
                </pluginManagement>
               </build>
            </profile>
            
        </profiles>
    </project>
  6. Leave the following the child project. This is a collection of *active* project constructs.

    • plugins

    • dependencies

    • module-specific properties

    • profiles that declare plugins and dependencies

    
    <?xml version="1.0"?>
    <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/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>myorg.jpa</groupId>
            <artifactId>jpa-parent</artifactId>
            <version>1.0-SNAPSHOT</version>
            <relativePath>../jpa-parent</relativePath>
        </parent>


        <groupId>myorg.jpa</groupId>
        <artifactId>entityMgrEx</artifactId>
        <version>1.0-SNAPSHOT</version>

        <name>Entity Manager Exercise</name>


        <build>
            <!-- filtering will replace URLs, credentials, etc in the 
                 files copied to the target directory and used during testing.
                -->
            <testResources>
                <testResource>
                    <directory>src/test/resources</directory>
                    <filtering>true</filtering>
                </testResource>
            </testResources>
            <plugins>
                <plugin>
                    <artifactId>jpa-schemagen-maven-plugin</artifactId>
                    <groupId>info.ejava.utils.jpa</groupId>
                    <configuration>
                        <persistenceUnit>entityMgrEx</persistenceUnit>
                    </configuration>
                </plugin>
            </plugins>
        </build>

        <dependencies>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <scope>provided</scope>
            </dependency>
        
            <dependency>
                <groupId>javax.persistence</groupId>
                <artifactId>javax.persistence-api</artifactId>
                <scope>provided</scope>
            </dependency>        

            <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-core</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
                <scope>test</scope>
            </dependency>

            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <scope>test</scope>
            </dependency>
            <dependency>
              <groupId>log4j</groupId>
              <artifactId>log4j</artifactId>
              <scope>test</scope>
            </dependency>    
        </dependencies>

        <profiles>
            <profile>
                <id>testing</id>
                <activation>
                    <property>
                        <name>!skipTests</name>
                    </property>
                </activation>
          
                <build>
                    <plugins>
                        <plugin>
                            <!-- runs schema against the DB -->
                            <groupId>org.codehaus.mojo</groupId>
                            <artifactId>sql-maven-plugin</artifactId>        

                            <executions>

                                <!-- place execution elements here  -->
                                <execution>
                                    <id>drop-db-before-test</id>
                                    <phase>process-test-classes</phase>
                                    <goals>
                                        <goal>execute</goal>
                                    </goals>
                                    <configuration>
                                        <autocommit>true</autocommit>
                                        <orderFile>decending</orderFile>
                                        <fileset>
                                            <basedir>${basedir}/src</basedir>
                                            <includes>
                                                <include>main/resources/ddl/**/*tuningremove*.ddl</include>
                                                <include>main/resources/ddl/**/*drop*.ddl</include>
                                            </includes>
                                        </fileset>
                                        <onError>continue</onError>
                                    </configuration>
                                </execution>

                                <execution>
                                    <id>create-db-before-test</id>
                                    <phase>process-test-classes</phase>
                                    <goals>
                                        <goal>execute</goal>
                                    </goals>
                                    <configuration>
                                        <autocommit>true</autocommit>
                                        <orderFile>ascending</orderFile>
                                        <fileset>
                                            <basedir>${basedir}/src</basedir>
                                            <includes>
                                                <include>main/resources/ddl/**/*create*.ddl</include>
                                                <include>main/resources/ddl/**/*tuningadd*.ddl</include>                 
                                            </includes>
                                        </fileset>
                                        <print>true</print>
                                    </configuration>
                                </execution>

                                <execution>
                                    <id>populate-db-before-test</id>
                                    <phase>process-test-classes</phase>
                                    <goals>
                                        <goal>execute</goal>
                                    </goals>
                                    <configuration>
                                        <autocommit>true</autocommit>
                                        <fileset>
                                            <basedir>${basedir}/src</basedir>
                                            <includes>
                                                <include>test/resources/ddl/**/*populate*.ddl</include>
                                            </includes>
                                        </fileset>
                                    </configuration>
                                </execution>

                                <!--
                                <execution>
                                    <id>drop-db-after-test</id>
                                    <phase>test</phase>
                                    <goals>
                                        <goal>execute</goal>
                                    </goals>
                                    <configuration>
                                        <autocommit>true</autocommit>
                                        <fileset>
                                            <basedir>${basedir}/src</basedir>
                                            <includes>
                                                <include>main/resources/ddl/**/*drop*.ddl</include>     
                                                </includes>
                                        </fileset>
                                    </configuration>
                                </execution>
                                -->
                            </executions>
                        </plugin>          
                    </plugins>          
                </build>
            </profile>
        </profiles>

    </project>
  7. Verify your project still builds. This will verify your relativePath is correct.

    $mvn clean verify
    ...
    [INFO] BUILD SUCCESS
  8. Optionally change your jpa-parent dependency to the class examples base parent project.

    
    
        <parent>
            <groupId>info.ejava.examples.build</groupId>
            <artifactId>dependencies</artifactId>
            <version>x.x.x-SNAPSHOT</version>
            <relativePath>build/dependencies/pom.xml</relativePath>
        </parent>

    Note

    Replace x.x.x-SNAPSHOT with the correct version for class.

Note

It is never a good idea to declare *active* POM constructs in a parent of a multi-module project unless *ALL* child modules are of the same purpose. Strive for parent Maven projects to define standards to follow without inserting unecessary dependencies or other constructs.

In this chapter you re-factored your module into a reusable jpa-parent module (that could be replaced by the class example) and child module. The child is then freed of defining version#s and other constructs that can be shared across several modules -- allowing smaller child POMs to be created through templates that produce modules that extend the jpa-parent. Cool. You didn't want to do that again.

You have now finished all chapters of the Maven and JPA/EntityManager exercise that was geared at getting you started developing modules that implement the data tier.