Monday, February 1, 2016

Hibernate tools reverse engineering using Maven

Hibernate tools allows to generate mapping or Java code through reverse engineering, schema generation through Ant Tasks. There is a Maven plugin hibernate3-maven-plugin but I managed to make it work only with 2.2 version, which comes with an old version of hibernate-tools. Of course, there is the idea of running hibernate tools Ant tasks from Maven. Although Maven beautifuly run Ant tasks, I had quite hard time trying to make it work with the latest stable version of hibernate-tools, mostly because all the examples I found are heavily outdated. The current post describes step by step this process.

The pom.xml

We'll modify pom.xml by creating a Ant task runner to generate JPA entities from a given database. My database is Postgresql, if you are using something else, you'll have to modify the driver in the plugin dependency zone. The only necessary thing in the Maven project's pom is:
 
<plugin>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.8</version>
    <executions>
        <execution> <!--mvn antrun:run@hbm2java-->
            <id>hbm2java</id>
            <phase>none</phase>
            <configuration>
                <target>
                    <echo message="Start generating entities .."/>
                    <taskdef name="hibernatetool"
                    classname="org.hibernate.tool.ant.HibernateToolTask"/>
                    <hibernatetool>
                        <jdbcconfiguration
                 revengfile="src/your/path/to/hibernate.reveng.xml"
                            packagename="your.package.name"
                            detectmanytomany="true"
                   configurationfile="src/your/path/to/hibernate.cfg.xml"/>
                <hbm2java destdir="src/main/java" jdk5="true" ejb3="true"/>
                    </hibernatetool>
                    <echo message="End generating entities"/>
                </target>
            </configuration>
            <goals>
                <goal>run</goal>
            </goals>
        </execution>
    </executions>
    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.3.11.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>4.3.11.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.common</groupId>
            <artifactId>hibernate-commons-annotations</artifactId>
            <version>4.0.5.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.1-api</artifactId>
            <version>1.0.0.Final</version>
        </dependency>
        <dependency>
            <groupId>javax.transaction</groupId>
            <artifactId>jta</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.8</version>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.4.1207.jre7</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-tools</artifactId>
            <version>4.3.2.Final</version>
            <exclusions>
                <exclusion>
                    <groupId>*</groupId>
                    <artifactId>*</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</plugin>

The reddish zones are the only ones needing configuration. There are 2 important files:

hibernate.cfg.xml

  • It contains the database connection details:

 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
  <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</property>
    <property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
    <property name="hibernate.connection.url">jdbc:postgresql://localhost:5432/vetcab</property>
    <property name="hibernate.connection.username">postgres</property>
    <property name="hibernate.connection.password">postgres</property>
  </session-factory>
</hibernate-configuration>


Just modify the above file accordingly.

hibernate.reveng.xml

      • It configures the process of reverse engineering. For more details about how this file should look like go on official documentation. Bellow you can see an example:
   
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-reverse-engineering PUBLIC "-//Hibernate/Hibernate Reverse Engineering DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-reverse-engineering-3.0.dtd" >

<hibernate-reverse-engineering>
    <table-filter match-schema="public" match-name="sec_authorities"/>
    <table-filter match-schema="public" match-name="sec_users"/>
    <table-filter match-schema="public" match-name="sec_user_authorities"/>

    <table schema="public" name="sec_users">
        <meta attribute="extra-import">java.util.stream.Collectors</meta>
        <meta attribute="extra-import">java.util.List</meta>
        <meta attribute="extra-import">javax.persistence.Transient</meta>
        <meta attribute="class-code">
        <![CDATA[
    @Transient
    public List<SecAuthority> getSecAuthorities() {
        return getSecUserAuthorities().stream().map(e -> e.getSecAuthority()).collect(Collectors.toList());
    }

        ]]>
        </meta>
        <primary-key>
            <generator class="identity"></generator>
        </primary-key>
    </table>

    <table schema="public" name="sec_authorities">
        <meta attribute="class-description">
            Javadoc for the Person class
            @author eugen
        </meta>
        <primary-key>
            <generator class="identity"></generator>
        </primary-key>
    </table>

    <table schema="public" name="sec_user_authorities">
        <primary-key>
            <generator class="identity"></generator>
        </primary-key>
    </table>

</hibernate-reverse-engineering>

Now you can run it with:
mvn antrun:run@hbm2java
command. If you have modified templates (see the documentation) then, in pom.xml, modify the hibernate tool tag to look like:
<hibernatetool templatepath="src/the/path/to/the/directory/containing/pojo/directory">

The above path must point to the parent of the directory named pojo, containing your templates.   Also, if you have a custom reverse engineering strategy class the, in pom.xml add this attribute to jdbcconfiguration tag.
reversestrategy="fully.qualified.name.CustomDelegatingReverseEngineeringStrategy"

That's all, hope it helped. Don't forget to comment on my post.

Friday, January 23, 2015

An Eclipse plugin: JavaBean Inspector

Introduction

One of the most tedious things to do when building a Java web application is to handle the so called bindings.
But what is a binding? I'm going to give you an example to understand what I mean.
Let's suppose we have a web application whose back-end is written in Java while the font-end is HTML/JavaScript based. The communication between the two sides is done using JSON.
Suppose we have a Java model that looks like:

class Book {
   private name;
   private publishingDate;
   private Author author;
 
   //...setters/getters here
}

An instance of the above class gets JSON serialized, then lands to the client side (the web browser) and gets deserialized into a JavaScript object, that looks like:

{name: "Alice in Wonderland", publishingDate: "26 November 1865",
 author : {name: "Lewis Carroll", address: {town:"Guildford", country: "England"}}}

The relationship between the Java model and the resulting JavaScript model is called binding.
JavaScript allows the use of path expressions to refer the object's fields, for example: publishingDate, author, author.name, author.address.town
To write this path expressions requires some copy/paste operations if you don't have a good memory, or, if you are using Eclipse IDE, a plugin can insert them automatically.

The JavaBean Inspector Eclipse plugin

This plugin is open sourced and can be found  here
To  install it, you can use Help -> Eclipse Marketplace menu.
After installing, press Ctrl+Alt+8 the select the Java model. You'll see something like:



Search and select the JavaBean model you want to bind to HTML/JavaScript. Press OK button then open a HTML or JavaScript file, place the caret where you want to insert the path expression, then press Ctrl+Alt+Space. You'll see something like:


Navigate to the end of the desired path expression and select it. The selected path will be inserted at caret location. That's it.
One more thing that you can do is to validate a path expression against the selected JavaBean. Just select the path to validate and press Ctrl+Alt+9. If it's valid, you'll see a message like:


Any suggestions for improvement are welcomed.