Annotation mapping

What are annotations?

An annotation is a tag which can be added to the source code. Annotations are used to add special behaviour, suppress warnings or to define Hibernate mappings. It starts with an @ and can have parameters. The following source code is having an annotation indicating a one-to-many relation:

@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "developer_id")
public Set<Hobby> getHobbies() {
   return hobbies;
}

A annotation resembles an interface declaration. Here is the source code of the @SequenceGenerator annotation.

/*
 * The contents of this file are subject to the terms
 * of the Common Development and Distribution License
 * (the License).  You may not use this file except in
 * compliance with the License.
 *
 * You can obtain a copy of the license at
 * https://glassfish.dev.java.net/public/CDDLv1.0.html or
 * glassfish/bootstrap/legal/CDDLv1.0.txt.
 * See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL
 * Header Notice in each file and include the License file
 * at glassfish/bootstrap/legal/CDDLv1.0.txt.
 * If applicable, add the following below the CDDL Header,
 * with the fields enclosed by brackets [] replaced by
 * you own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 */
package javax.persistence;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Target({TYPE, METHOD, FIELD})
@Retention(RUNTIME)
public @interface SequenceGenerator {
    String name();
    String sequenceName() default "";
    int initialValue() default 1;
    int allocationSize() default 50;
}

Field, Method, Class annotations

Annotations can be assigned to a class, method or a field.

@Entity
public class BoxTurtle implements Serializable {
    @EmbeddedId

This is not an option but defined in the annotation. In the source code of an annotation you can see where you can add the annotation. The following code shows an annotation which can be added to a field or a method.

@Target({METHOD, FIELD})

Pitfall: You must choose if you add your annotations to the field or the methods. If you add an @Id annotation to your id field, Hibernate ignores any annotations to methods and vice versa.

Requirements to use annotations

In order to use annotation mapping you need the following things:

Further information

In addition to the samples we provide in this chapter, you can find a complete reference of annotations in this book. Have a look in chapter Annotation reference the section called “Annotation Reference”.

Mapping fields

The following is the shortest possible mapping. It marks the class as Hibernate entity and the id field with @Id. The entity will be stored in a table player having two columns: id and name. Annotation mapping treats all fields as mapped by default. Inherited fields are not mapped by default.

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Player {

   @Id
   private Integer id;

   private String name;


    public Player() {
    }

    public Player(String name) {
        this.name = name;
    }

    public Integer getId() {
      return id;
   }

   public String getName() {
      return name;
   }

}

If you do not want to map a field, you need to mark it with @Transient.

@Entity
public class Player {

    @Transient
    private int value;
.....

If you want to map fields of parent classes you need to mark the parent class with @MappedSuperclass.

@MappedSuperclass
public class AbstractPlayer {
    @Id
    @GeneratedValue
    protected Integer id;
    protected String name;
}

If you want to be more explicit, you can use the @Basic and the @Column annotation. @Basic allows to define that a single field is not loaded immediately but lazy when the getter is called for this field. This is used extremely rare for single fields and in order to get this to work, you need to use byte code instrumentation. In addition @Basic allows to define that a field is not nullable what is possible with @Column as well.

@Column(name = "player_name", unique = true, nullable = false,
   updatable = false, length = 5)
private String name;

The sample maps the field name to the database column player_name. unique, nullable and length are hints for the schema generation. If you let Hibernate generate your tables, unique or not null constraints will be created. Length corresponds to the length of the varchar column.

Furthermore Hibernate will check nullable=false constraints itself, without sending a query to the database.

updatable allows to disable update statements to a field. You should use it for immutable fields. An immutable field can be saved once but an update is not possible. The field will not be included in the fields of an update statement. There is an insertable option available as well, which can turn a field into a read only value.

java.util.Date

A java.util.Date could be a date, a time or a date and time value. You can specify the type for a field using @Temporal

@Temporal(TemporalType.DATE)   // TIMESTAMP, TIME or DATE
private Date birthDay;

Enum types

Annotation mapping supports enum types without using a user defined type.

public class Player {
   public enum Experience {BASIC, MEDIUM, PROFESSIONAL}

   @Enumerated
   private Experience experience;

The value are stored with the enum type’s ordinal value, which is 0 for the first enum value (BASIC), 1 for the second and so on.

If you prefer a text representation (for example BASIC for Experience.BASIC), you can use @Enumerated(EnumType.STRING). I tend to use a text representations for all tables which are not very big, as there are more readable.

Components

A component is a class containing multiple fields. It is a good object oriented development practise to compose a class of other classes instead of having a single class with a lot of fields. Imagine the frequent use case of addresses. We want to store street and city of the player. Instead of adding individual fields, a new class Address is created containing the address fields. You need to mark it as @Embeddable. We will see components in greater detail later.

@Embeddable
public class Address {
    private String street;
    private String city;

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }
}

Inside of the player class you just need to add the field and add the @Embedded annotation. The fields of the address are by default stored in the same table as the player.

public class Player {
    @Embedded
    private Address address;
//....

Where to put annotations

You can add annotations to your fields and to your getter methods. First, of all you need to choose one approach. Inside of a class Hibernate looks for the @Id annotation. If it is found in front of a field, Hibernate will only consider annotations in front of fields. It the @Id is found in front of a getter method it will only look for annotations in front of getters.

Player with getter annotations. 

@Entity
public class Player {
    @Id
    @GeneratedValue
    public Integer getId() {
        return id;
    }

    @Column(name = "player_name")
    public String getName() {
        return name;
    }

The placement of the annotation influences the default behaviour how Hibernate is writing values from a database row to a class. Annotation in front of getters let Hibernate use the setter and getter methods, whereas annotations in front of fields let Hibernate use direct field access.

Use the @AccessType annotation to override the default behaviour.

// the name is accessed using the getter and setter method

@Access(AccessType.PROPERTY)
protected String name;