As all of you who are familiar with Hibernate know, not all entity annotations are mandatory. These non mandatory annotations include @Table and @Column annotations. However, even though these annotations are not required, leaving them out has never been an option for me. I simply don’t like the table and column names which are generated by Hibernate unless they are explicitly set.
The naming convention of database objects and schema elements is controlled by the used implementation of the org.hibernate.cfg.NamingStrategy interface. Hibernate 3.6 has four implementations of this interface:
- org.hibernate.cfg.DefaultComponentSafeNamingStrategy
- org.hibernate.cfg.DefaultNamingStrategy
- org.hibernate.cfg.EJB3NamingStrategy
- org.hibernate.cfg.ImprovedNamingStrategy
However, none of these implementations fulfill my requirements which are:
- All characters must be lowercase.
- Table names must be in plural form.
- Words must be separated by using an underscore.
Since the ImprovedNamingStrategy class is almost what I am looking for (its only fault is that it returns the table name in a singular form), I decided to create a custom naming strategy by extending it and overriding its classToTableName() method. The source code of my implementation is given in following:
1package net.petrikainulainen.hibernate.util;
2import org.hibernate.cfg.ImprovedNamingStrategy;
3
4/**
5 * A custom naming strategy implementation which uses following naming conventions:
6 * <ul>
7 * <li>Table names are lower case and in plural form. Words are separated with '_' character.</li>
8 * <li>Column names are lower case and words are separated with '_' character.</li>
9 * </ul>
10 * @author Petri Kainulainen
11 */
12public class CustomNamingStrategy extends ImprovedNamingStrategy {
13
14 private static final String PLURAL_SUFFIX = "s";
15
16 /**
17 * Transforms class names to table names by using the described naming conventions.
18 * @param className
19 * @return The constructed table name.
20 */
21 @Override
22 public String classToTableName(String className) {
23 String tableNameInSingularForm = super.classToTableName(className);
24 return transformToPluralForm(tableNameInSingularForm);
25 }
26
27 private String transformToPluralForm(String tableNameInSingularForm) {
28 StringBuilder pluralForm = new StringBuilder();
29
30 pluralForm.append(tableNameInSingularForm);
31 pluralForm.append(PLURAL_SUFFIX);
32
33 return pluralForm.toString();
34 }
35}
The next step is to configure the Hibernate to use my custom naming strategy. If you are using Hibernate, you can either
- You can set a reference to the custom naming strategy by calling the setNamingStrategy() method of the Configuration class as described in the Implementing a Naming Strategy Section of the Hibernate Reference Documentation.
- You can set the value of hibernate.ejb.naming_strategy property to net.petrikainulainen.hibernate.util.CustomNamingStrategy in the Hibernate XML configuration file as described in the XML Configuration Section of the Hibernate Reference Manual.
If you are using JPA, you can set the used naming strategy by setting the value of hibernate.ejb.naming_strategy property to net.petrikainulainen.hibernate.util.CustomNamingStrategy in the persistence.xml as described the Packaging Section of the Hibernate EntityManager reference manual.
After you have configured Hibernate to use the implemented custom naming strategy, you can remove the @Table and @Column annotations from entity classes (This is not entirely true but I will describe the shortcomings of my solution later). For example, if you have an entity class Person, its source code could look something like this:
1@Entity
2@Table("persons")
3public class Person {
4
5 @Column(name="first_name")
6 private String firstName;
7
8 @Column(name="last_name")
9 private String lastName;
10
11 public Person() {
12
13 }
14}
After Hibernate is using the new naming strategy, the source code of the Person entity would look like this (but Hibernate would still use the same table and column names which were explicitly specified in the previous example):
1@Entity
2public class Person {
3
4 private String firstName;
5
6 private String lastName;
7
8 public Person() {
9
10 }
11}
I have now described to you how you can implement and configure a custom naming strategy with Hibernate. However, the solution described in this blog entry is far from perfect. It has following shortcomings:
- It does not always produce grammatically correct table names. For example: The plural form is a word entity is not entitys. It is entities. This problem is pretty hard to tackle automatically but remember that you can always use the @Table annotation to solve these cases.
- If you want to add restrictions to the column in the entity class, you still have to add the @Column annotation. This is not a problem to me because I always generate the database creation scripts manually and add constraints to the database. However, if you want to generate your database by using Hibernate, you would have to specify the constraints by using the @Column annotation or add the needed constraints manually to the created database.
- You still have to configure the relationships between entities by using annotations. Creating an automatic solution for this problem would mean that I would have to invent some kind of naming convention for the names of join tables and columns. This is something which I am not willing to do. However, If you have an another solution in mind, let me know!