Thursday 12 July 2012

Ignored EJB3 @Column name attribute

I am working on an EJB3 project after a few months on other work and I ran into a small issue with the EJB3 @Column name attribute. The attribute is meant to allow the mapping of a column to a different name in an entity. If your database table has an unusable (or just unfriendly) column name you can map it to a more logical field name in the entity.

In my case the table is a mapping table that I am creating an object model against and I wanted to map the "sub_account_name" column to "name". My initial implementation was as follows:


@Entity
@Table(name = "portfolio_subaccount")
public class Portfolio implements Serializable {
    private static final long serialVersionUID = 3450488234689579105L;

    @Id
    @GeneratedValue
    private long id;
    private String name;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    @Column(name = "sub_account_name", nullable = true)
    public String getName() {
        return name;
    }

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


The deployment does not report any errors however the test client code below causes a GenericJDBCException to be thrown.


public class Client {

    public static void main(String[] args) {
        try {
            Context context = getInitialContext();
            BeanRemote remote = (BeanRemote) context.lookup("SomeBean/remote");
            Portfolio portfolio = remote.getPortfolio(352);
            System.out.println(portfolio.getId() + ": " + portfolio.getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static Context getInitialContext() throws NamingException {
        Properties props = new Properties();
        props.put(Context.PROVIDER_URL, "jnp://server:1099");
        props.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
        props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");

        return new InitialContext(props);
    }
}

The exception (from the server logs) indicates that the name column is not found on the table:

2012-07-12 11:37:28,049 ERROR [org.hibernate.util.JDBCExceptionReporter] (WorkerThread#2[172.19.216.159:34038]) Invalid column name 'name'.

Which is quite interesting given the annotation indicating the column is actually called "sub_account_name". The problem is caused by the location of the annotation, it seems that Hibernate does not handle some annotations being on the variable declaration while others are on the accessor methods. Moving the @Column annotation to the variable declaration corrects the problem. The corrected class is below.

@Entity
@Table(name = "portfolio_subaccount")
public class Portfolio implements Serializable {
    private static final long serialVersionUID = 3450488234689579105L;

    @Id
    @GeneratedValue
    private long id;

    @Column(name = "sub_account_name", nullable = true)
    private String name;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id id;
    }

    public String getName() {
        return name;
    }

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