Friday, August 30, 2013

Hibernate reverse engineering tool adjustments

Hibernate reverse engineering tool adjustments - how to add your own activities.


Whenever you use hibernate reveng file to generate your entities - this could be helpfull for you, I spend some time to findout how hib-tool.jar is build  and here some easy-peasy example how to adjust them. How to create some additional parameters automatically on entity mapping level.

Basically hib-tool internally uses ftl - FreeMarker Template language. Short introduction to it you could find here: http://viralpatel.net/blogs/introduction-to-freemarker-template-ftl/

This post is not about ftl but how simply you can adjust reveng tool, let's start with some easy-funny change to give you heads up:
Lets change default comment for auto generated entities, to something that will tell everybody that you was there ;-) 

As tool is responsible for generating pojo classes from tables existing in DB, file that we want to change will be:
PojoTypeDeclaration.ftl

/**
${pojo.getClassJavaDoc(pojo.getDeclarationName() + " generated by hbm2java a little bit modified by yarenty.", 0)}
*/
<#include "Ejb3TypeDeclaration.ftl"/>
${pojo.getClassModifiers()} ${pojo.getDeclarationType()} ${pojo.getDeclarationName()} ${pojo.getExtendsDeclaration()} ${pojo.getImplementsDeclaration()}

Example output: ;-)

/**
* Model generated by hbm2java a little bit modified by yarenty. */

Real life example: 

We want to add property on the column level to make sure that this column will not be update-able by hibernate [immutable on DB level].
So if you look into reveng.xml file we would like to add attribute here, lets introduce it as "update-disabled".

<table name="out_model" class="com.yarenty.core.persistence.entities.out.Model" schema="dev" catalog="out_model_dev">
<meta attribute="extra-import">javax.persistence.EntityListeners</meta>
<meta attribute="class-description">
Example Model.
@author Automatic Seam Generator (updated by yarenty)
</meta>
<meta attribute="scope-class">
@EntityListeners(com.yarenty.core.intercept.EntityListener.class)
public
</meta>
<primary-key><generator class="com.yarenty.core.persistence.hibernate.id.InformixSequenceGenerator"><param name="sequence_name">market_sequence</param><param name="increment_size">10</param></generator></primary-key> <column name="result">
<meta attribute="update-disabled"/></column>
</table> 

OK, we wrote it but real thing is: how to make it work?
We need to change two files - one responsible for processing xml, second for processing DB (hbm).
In file: pojo/Ejb3PropertyGetAnnotation.ftl we need to add another property


<#if ejb3>
<#if pojo.hasIdentifierProperty()>
<#if property.equals(clazz.identifierProperty)>
${pojo.generateAnnIdGenerator()}
<#-- if this is the id property (getter)-->
<#-- explicitly set the column name for this property-->
</#if>
</#if>
<#if pojo.hasMetaAttribute(property, "update-disabled")>
${property.setUpdateable(false)}
</#if>
[...]

And now in file: hbm/property.hbm.ftl when output java class will be created we need to add our output text that we want to see: 


<property
name="${property.name}"
type="${property.value.typeName}"
<#if !property.updateable> update="false"</#if> <#if !property.insertable> insert="false"</#if> <#if !property.basicPropertyAccessor>
access="${property.propertyAccessorName}"
</#if>

So our output, will be:
  

@Column(name = "result", updatable = false, length = 1) public Character getResult() { return this.result; }

TIP: As you can see - highlighted in yellowish - there is quite similar method to avoid insertion of column.