Maven Java Source Code Generation for Hibernate

2019-01-15 02:17发布

问题:

I´m busy converting an existing project from an Ant build to one using Maven. Part of this build includes using the hibernate hbm2java tool to convert a collection of .hbm.xml files into Java. Here's a snippet of the Ant script used to do this:

<target name="dbcodegen" depends="cleangen" 
        description="Generate Java source from Hibernate XML">
  <hibernatetool destdir="${src.generated}">
    <configuration>   
      <fileset dir="${src.config}">
        <include name="**/*.hbm.xml"/>
      </fileset>
    </configuration>   
    <hbm2java jdk5="true"/>
  </hibernatetool>   
</target>

I've had a look around on the internet and some people seem to do this (I think) using Ant within Maven and others with the Maven plugin. I'd prefer to avoid mixing Ant and Maven. Can anyone suggest a way to do this so that all of the .hbm.xml files are picked up and the code generation takes place as part of the Maven code generation build phase?

Thanks!

Adam.

回答1:

Well, there is the Maven Hibernate3 Plugin if you don't want to mix Ant and Maven (which is a good idea here IMO). It has a hbm2java goal which is bound by default to the generate-sources phase. Refer to the website of the Mojo for more details but the setup of the plugin might looks like something like this:

  <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>hibernate3-maven-plugin</artifactId>
    <version>2.2</version>
    <executions>
      <execution>
        <phase>generate-sources</phase>
        <goals>
          <goal>hbm2java</goal>
        </goals>
      </execution>
    </executions>
    <configuration>
      <components>
        <component>
          <name>hbm2java</name>
          <implementation>configuration</implementation>
          <outputDirectory>target/generated-sources/hibernate3</outputDirectory>
        </component>
      </components>
      <componentProperties>
        <drop>true</drop>
        <jdk5>true</jdk5>
        <configurationfile>/src/main/resources/hibernate.cfg.xml</configurationfile>
      </componentProperties>
    </configuration>
  </plugin> 

EDIT: The plugin actually looks for .hbm.xml in target/classes to generate the java source files. So, if you put your mapping files in src/main/resources, they will get copied into target/classes during the process-resources phase which is invoked by the plugin and things will just work. I've just tested this with the following sample project:

maven-hibernate3-testcase
|-- pom.xml
`-- src
    |-- main
    |   |-- java
    |   `-- resources
    |       |-- Person.hbm.xml
    |       `-- hibernate.cfg.xml
    `-- test
        `-- java

The pom.xml is almost empty, it just contains the plugin configuration seen above and a junit dependency. The hibernate.cfg.xml contains:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <!-- Database connection settings -->
    <property name="connection.driver_class">org.apache.derby.jdbc.ClientDriver</property>
    <property name="connection.url">jdbc:derby://localhost:1527/mydatabase</property>
    <property name="connection.username">app</property>
    <property name="connection.password">app</property>

    <!-- JDBC connection pool (use the built-in) -->
    <property name="connection.pool_size">1</property>

    <!-- SQL dialect -->
    <property name="dialect">org.hibernate.dialect.DerbyDialect</property>

    <!-- Echo all executed SQL to stdout -->
    <property name="show_sql">false</property>

    <!-- Mapping files -->
    <mapping resource="Person.hbm.xml" />
  </session-factory>
</hibernate-configuration>

And Person.hbm.xml looks as follow:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping
   PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

  <class name="Person" table="person">
    <id name="id" type="int">
      <generator class="increment" />
    </id>

    <property name="name" column="cname" type="string" />
  </class>

</hibernate-mapping>

With this configuration, running mvn install generates Person.java as shown below:

$ cat target/generated-sources/hibernate3/Person.java 
// default package
// Generated Dec 14, 2009 2:19:22 PM by Hibernate Tools 3.2.2.GA



/**
 * Person generated by hbm2java
 */
public class Person  implements java.io.Serializable {


     private int id;
     private String name;

    public Person() {
    }

    public Person(String name) {
       this.name = name;
    }

    public int getId() {
        return this.id;
    }

    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }




}

Everything works as described.



回答2:

Pascal, thanks again for your help! Your solution works well.

A couple of other things I encountered while working on this. The first relates to the fact that this is a fairly big project and so I've split it into multiple Maven modules to mirror the original ant multi-directory build. The module that contains the generated classes doesn't actually do any database access and so the hibernate.cfg.xml file need not, and in this case should not, contain any DB connection information. I've tried this out and it works just fine with a cut down version of the file provided by Pascal, with all of the properties tags removed.

With this in place, the build worked fine from the command line. However, try as I might, I couldn't persuade the other modules to pick up the generated classes when run from Eclipse. For the time being, the solution I have to this is to add the following line into the POM under configuration/components/component:

<outputDirectory>/src/main/java</outputDirectory>

This forces the files to be generated in a place that eclipse can pick them up for the other modules. Once this is done you must do a build on the command line and then request that Eclipse refresh the contents of the source directory to pick up the new files. As yet, I don't know of a cleaner way to handle this....



回答3:

If you need include *.hbm.xml on the phase compile; edit your pom.xml and add the next code:

<build>
                <resources>
            <resource>
                <directory>source/com/qfund/orm/</directory>
                <targetPath>com/qfund/orm/</targetPath>
                <includes>
                    <include>*.hbm.xml</include>
                </includes>
            </resource>
        </resources>
        <testResources>
            <testResource>
                <directory>src/test/java/</directory>
                <includes>
                    <include>*.xml</include>
                    <include>*.xsd</include>
                    <include>*.xslt</include>
                    <include>*.properties</include>
                </includes>
            </testResource>
        </testResources>
</build>