Hibernate

Toggle view

ServiceLoader or "Sometimes you just don't need a full blown dependency injection container"

I like Springframework very much and use it in my day to day business as it eases development in many places. A few days ago I started using Hibernate Envers in order to implement a simple auditing solution for a JPA based application. I was faced with the (typical) requirement that the username of the user currently logged in was written into the audit entity. With Envers you would do that using a org.hibernate.envers.RevisionListener. This is instantiated by the Envers runtime. That listener required access to the FacesContext (it’s a JSF based application) to get the user principal from the HTTP request. Not a big deal in general! Still I wanted to keep that testable and usable in various environments, so an abstraction was needed and finally something would have to inject that into my listener.
As I said I’m a fan of Spring and this would be the perfect job and eventually one would propose “yeah, let’s do Spring AOP with AspectJ weaving”. As this application was already in production I didn’t want to add that at this time and was seeking for something more simple but still elegant.

Java as of 1.6 has the concept of SPI and ServiceLoader already built-in. I had never used it before. Here it seemed to perfectly match and it did.

import java.security.Principal;
public interface UserPrincipalProvider {
	Principal getUserPrincipal();
}

import java.security.Principal;
public class TestUserPrincipalProvider implements UserPrincipalProvider {

	public Principal getUserPrincipal() {
		return new Principal() {
			public String getName() {
				return "TEST";
			}
		};
	}
}

A file named META-INF/services/at.package.auditing.UserPrincipalProvider would be responsible for registering the provider implementation, it only contains one or multiple class names:

at.package.auditing.TestUserPrincipalProvider

For getting a runtime instance of such a provider I implemented a helper like

public static <T> T lookup(Class<T> clazz) {
	Iterator<T> iterator = ServiceLoader.load(clazz).iterator();
	return iterator.hasNext() ? iterator.next() : null;
}

It is called like ...lookup(UserPrincipalProvider.class).

Hibernate entity-name

In a complex application a persistent entity is typically used by multiple use cases. These use cases put different requirements on mapping such a persistent entity. For example, in a simple case only basic attributes must be mapped whereas in a more complex situation for the same entity a larger set of attributes (+ relationships) must be mapped.
When mapping a persistent entity, tradeoffs must be made regarding performance and the required code to implement the solution.
For the above scenario a developer would probably just map all of the persistent attributes (regardless whether they are required in all of the use casesor not) and eventually map relationships with some lazy loading enabled.
Dealing with it this way mostly works even in larger projects but can totally fail in others (especially when mappings are created by more than one developer and no design rules are in place).

Hibernate provides a mechanism to deal with this kind of troubles very well. One can actually provide multiple mappings for a single persistent class through the mapping attribute ‘entity-name’.
For example I had a situation where an entity had a primary key but also an alternate key which was used heavily in other entities for referencing this one.

So I just created 2 different mappings for this one class, mapping different attributes as id.

	
		

	

	

		
	

When referring to a specific mapping the ‘entity-name’ attribute is used

  

When using the Hibernate API, look out for overloaded methods that allow passing in a entity-name!

Hibernate isPersistent Element

Rarely you need to be able to detect whether some class or property is managed by Hibernate (i.e. it is mapped) or not. In this case SessionFactory.getClassMetdata helps with this problem.
It returns mapping information or throws an exception if it is not mapped!

Oracle 9.2+ JDBC Driver DATE type problem

With Oracle 9.2 some changes regarding the DATE type and the new TIMESTAMP type were introduced. These are causing problems with the JDBC driver when an application is expecting a DATE column to contain time information. These issues and a workaround are discussed in this article from Oracle.

This article proposes a few workarounds that you might be able to apply or not. Today I encountered a case that was troubling me for a while.

I’m using Hibernate 3.2.5.ga to map a class to some legacy table containing a DATE column holding date + time information. The property mapping looks as simple as <property name="timestamp" column= "MESSAGE_TIMESTAMP"/ >.

I have configured Hibernate with hibernate.hbm2ddl.auto=validate so my mapping files are checked against database metadata. As a result Hibernate would throw an exception at me telling that it can’t match the column type with the POJO property type.

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/context-web.xml]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: Wrong column type: COMM_MSGDT, expected: timestamp
Caused by: org.hibernate.HibernateException: Wrong column type: COMM_MSGDT, expected: timestamp
	at org.hibernate.mapping.Table.validateColumns(Table.java:261)
...

If you don’t need time information you can get around this execption by tweaking the type information for the property mapping (<property name="timestamp" column="MESSAGE_TIMESTAMP" type="date"/>) otherwise if time is required then you are in trouble!

The Oracle article above is suggesting to set a system property (as a JVM start parameter) which is kind of difficult to handle during deployment. So I was investigating the other option which is to set the connection property (oracle.jdbc.V8Compatible=true) for the Oracle JDBC driver, this option would allow a deployment configuration that is working “out-of-the-box”. Reading the Tomcat documentation on how to configure a JNDI DataSource led me to the DBCP documentation that is explaining this thoroughly.

I’m using a Tomcat managed DataSource. So I’m having a META-INF/context.xml file to set up the DataSource. To fix the type problem just add the property connectionProperties.


Create reusable hibernate mappings

Complex mappings very often tend to result in repetitive mapping definitions especially when trying to apply concepts from Domain Driven Design. Value objects (value types as they are called by Hibernate) are a typical example for those kind of repetitive tasks.

Let us assume that you want to keep track of user and time a set of entity types has been updated. So you would add a component mapping to all of the entity mappings where this feature is required.




This can get really tedious, so you might want to look for a more elegant solution that allows re-using this component mapping. Hibernate does not offer a mapping element that allows to include some externalized mapping fragment. But XML supports including XML documents through it’s DTD entity facility.

So you first start by moving the XML fragment that should be reusable to a file (e.g. domain/model/LastUpdate.xml)





For mapping file that requires the lastUpdate component an external ENTITY declaration must be added, the entity reference (&lastUpdate;) is a place holder that is replaced by the entity.


]>

	
		

		
		&lastUpdate;
	

Hibernate and Generics

Wherever possible I try to apply some principles from Domain Driven Design. So I also use Value Objects – some of them implemented based on Java5 Generics

Example:

public class Range {
	private T start;
	private T end;

	public Range() {
		super();
	}

	public Range(T start, T end) {
		super();
		this.start = start;
		this.end = end;
	}

	public T getStart() {
		return start;
	}

	public void setStart(T start) {
		this.start = start;
	}

	public T getEnd() {
		return end;
	}

	public void setEnd(T end) {
		this.end = end;
	}
}

Hibernate is not able to determine the proper type (org.hibernate.MappingException: property mapping has wrong number of columns …) for the properties of the value object unless they are explicitely described in the class mapping.

For a Range with Date as template parameter you would map:


Hibernate Validator

I have been using Hibernate for quite a number of projects now mostly all of them with JSF for implementing the web interface. I’d always found it boring to do the “form validation thing” – mostly it is look at the constraints in the mapping definition and attach the proper validation tag to a form input element.

So today I had a look at the Hibernate Validator project that promises to make those validation constraints  from the model available across all layers of application code. The project provides plenty of annotation types for annotating the domain classes. In general I try not to overuse annotations, especially those for mapping domain attributes to database entities – but this kind of annotations make sense to me!

As you would expect Hibernate Validations integrates with Hibernate core of course and JPA implementations so all of your annotated elements will be validated when persisted.

To perform application level validation a validation API is provided for validating bean instances or single bean properties.

ClassValidator validator = new ClassValidator(Car.class);

InvalidValue[] validationMessages = validator .getInvalidValues(porsche);
InvalidValue[] propertyMessages = validator .getInvalidValues(porsche, "engine");

Overall the API looks fairly slim and simple! In the next days I will investigate if the API allows “nested properties”. I’m thinking of creating some JSF tag (like the Seam tags) to perform validation of complete forms :)

Hibernate versus Hibernate JPA

I’m currently porting an application from Hibernate to JPA using Hibernate EntityManager. Initially I was thinking that this should be an easy task but it is not. JPA changes the behaviour of Hibernate quite a lot.

For example: Hibernate is not trying to persist any properties that are not mapped, but JPA does! So, generally speaking JPA’s mapping files (orm.xml) tend to be much bigger than hibernate mapping files.

In addition JPA has a lot of issues with relationships and inheritance so that one spends alot of time getting complex object networks to work (or fails at all). See the links below (1, 2, 3, …).

So the task of porting this application is on hold for a while after another issue had hit me. For a project that I have just started I have totally stopped any efforts on doing it with JPA. Instead I have fallen back to Hibernate. Maybe this is not a fall back, it should rather be called a lift-off :)

For now my conclusion is: JPA is just the common least denominator of existing mapping products with Hibernate on top of all of them! I guess like with most of the JavaEE specifications there ist another iteration required until it is really usable (seems that this soup is already boiling)!

green red blue grey