Reference‎ > ‎

The Map entity mode

Since version 2.0, ABL supports Hibernate's Map entity mode. This mode uses Maps to represent persistent objects, rather than Java beans (also known as POJO's).

The main benefit of this approach is that it gives you great flexibility: since you don't have any hard-coded Pojo's, you can theoretically run against any database schema.

However, there are also downsides to consider:

You still need to map your database

Even in Map mode, Hibernate still needs to know about your database schema. You will therefore need to create a mapping (typically in XML). However, this is still more flexible than hard-coding your database schema in Java classes.

Coding is more difficult

This is probably the main downside. Using map objects is not as natural as using Pojo's. Because everything is generic, there will be no compile-time checking, so it's easy to mistype the name of an attribute, and you will need to do a lot of casting (unless you use Groovy).


Using the Map mode

The ABL engine requires no special configuration to use Hibernate's Map mode. It will simply detect that Hibernate is using that mode.

This will of course affect how you define your business logic, because you will not get any Pojo's for CurrentBean and so on. So instead of the standard:

// Using the Pojo mode
public class CustomerLogic {
    @CurrentBean
    public Customer customer;

you will have:

// Using the Map mode
public class CustomerLogic {
    @CurrentBean
    public Map<String, Object> customer;

Your logic code will then have to access data using this object:

@Constraint
public void checkBalance() {
    BigDecimal balance = (BigDecimal)customer.get("balance");
    Map<String, Object> company = (Map<String, Object>)customer.get("company");
    BigDecimal creditLimit = (BigDecimal)company.get("creditLimit");
    if (balance.compareTo(creditLimit) > 0)
        ConstraintFailure.failConstraint("Sorry - Balance {balance} exceeds credit limit");
}

Note that Groovy makes this significantly easier by allowing you to (mostly) ignore types and casting.

A big gotcha

One very common problem with the Map mode is that, if you have objects that may, directly or indirectly, reference themselves (i.e. if your object model contains cycles), you may run into a StackOverflowError if you (or anyone else) call toString() on an object.

To understand why this is, consider the following code:

Map map1 = new HashMap();
Map map2 = new HashMap();
map1.put("map2", map2);
map2.put("map1", map1);
System.out.println(map1.toString()); // This blows up

This code will cause a StackOverflowError because HashMap.toString() calls toString() on the members of the map, and in this case that leads to infinite recursion.

This is not a problem that is specific to Hibernate: any Java program can exhibit this behavior.

To avoid this issue, ABL provides the method ObjectUtil.safeToString(). It can take any object as a parameter, and will avoid this infinite recursion.

Comments