JavaEnterprise JavaThe Top 5 New Annotations in JPA 2

The Top 5 New Annotations in JPA 2

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

When the version 2 release of the Java Persistence API (JPA 2) was released in November 2009, it introduced a number of advancements and new features. Among them were new annotations to help simplify many common programming tasks that Java developers must perform when using JPA 2 for object relational mapping (ORM). In this article, we provide a reference list of the five most notable new annotations introduced in JPA 2, complete with code examples. We also highlight the changes made to existing JPA 1.x annotations in order to make them easier to use.

Note: We assume you have a good understanding of the previous release of JPA. The article will not be as helpful if you are trying to learn JPA.

New Annotations in JPA 2

Here is a brief look at some of the support for major new annotations in JPA 2:

  1. Access Type — This annotation helps the developer to change the default access mode for a property.
  2. Order Column — This annotation is used on a ManyToMany or OneToMany relationship, or even on an element collection, to preserve the order/index of a list.
  3. Element Collection — This annotation enables the developer to have a collection of non-entity types, which can be an embeddable or basic.
  4. Additional Map support — Additional support for Maps is provided by allowing the developer to use basic, embeddable or entity as keys for a map.
  5. Derived Identifiers — With this feature, a developer can now annotate the foreign key relationship with the @Id annotation.

Let’s dive deeper into these annotations, as well as some other annotations introduced as part of JPA 2, with code samples.

Access Type

In JPA 1.x, access type was restricted to being either field based or property based for the entity hierarchy, which is achieved by decorating the fields or the properties of the entity class with metadata annotations. The specification provided no support for combining both the access types within a given entity hierarchy.

An embeddable class can have a different access type from the access type of the entity within which it is embedded. With JPA 1.x, it was not possible to retain the same access type of the embeddable class within the entity which was containing it. This problem is resolved in JPA 2 with the @Access annotation. The @Access annotation enables the entity classes to have a combination of both field-based and property-based access. Here is an example:

@Entity@Table(name = "employee")@Access(AccessType.FIELD)public class Employee {          @Idprivate Integer id;          private String name;          private int age;@Access(AccessType.PROPERTY)@Column(name="name")          public String getName() {             return this.name;}// Other methods       }

The @Access annotation helps developers to specify the access type for an entity class, an embeddable class or a mapped super class explicitly without affecting the other entities or the mapped classes. In the above code, the default access for the Employee entity is set using @Access(AccessType.FIELD), which makes it field based. Using @Access(AccessType.PROPERTY) would enable property-based access.

For an instance variable, a developer can instruct the persistence provider to use @Access(AccessType.FIELD) for field-based access and can use @Access(AccessType.PROPERTY) for property-based access to the persistent state of an instance variable. In the above code, property-based access is enabled for the name property by using @Access for the getter method of the name attribute. If the access is applied at the class level then by default it is applied for all the instance variables. If the same instance variable is mapped using both field- and property-based access you should use the @Transient annotation to avoid the default mapping by the persistence provider.The persistence provider throws a ValidationException if the default behavior of the entity is field-based while the getter method of that instance variable specifies property-based access — via metadata mapping without annotating it with @Access(AccessType.PROPERTY). The same point holds when the default access mode is property based while a particular instance variable is field based and not annotated using @Access(AccessType.FIELD).

OrderColumn

In JPA 1.x, the @OrderBy annotation was used to specify the element ordering based on a specific column in a table. JPA 2 specifies a new annotation called OrderColumn that is specified on a ManyToMany or OneToMany relationship or even on an element collection to preserve the order/index of a list. It is vendor specific because the persistence provider handles the insertion order of the list whenever it is updated, inserted or deleted, thereby reducing the developer’s burden of maintaining a separate column. The @OrderColumn annotation is currently supported by EclipseLink and it is utilized by maintaining an additional order column in the database, which need not be mapped in the entity class. The drawback is that the persistence provider has to update the order column of every persistence instance when the list is modified.

In the following example, the Employee entity has a list of products that is decorated with the @OrderColumn annotation:

@Entity@Tablepublic class Employee {   // Other Code@OneToMany(cascade = CascadeType.ALL, mappedBy="empId")@OrderColumn(name="indexno")private List<Product> productCollection;}

orphanRemoval Attribute for Mapping Annotation

The orphanRemoval attribute is specified for a @OneToOne or @OneToMany annotation. It is used to manage the relationship automatically between the parent and the child entities. Consider the following example:

@Entity@Tablepublic class Employee {   // Other Code@OneToMany(mappedBy = "empId", orphanRemoval=true)private List<Project> projectList;}

The Employee entity has a list of projects for which the orphanRemoval attribute is specified for @OneToMany. When the parent/child relationship between Employee and Project is removed by setting the projectList property to null, the managed projectList entity is removed from the database. Similarly, if a specific project entity is removed from the projectList, then that particular entity is removed from the database. The orphanRemoval attribute can also be used when cascade = CascadeType.REMOVE is applied for a relationship.

@ElementCollection

JPA 2 provides a collection of non-entity types, which are either embeddable or basic. This is supported in JPA 2 using the @ElementCollection and @CollectionTable annotation:

  • @ElementCollection specifies that the objects of this collection type are stored in a particular collection table
  • @CollectionTable specifies the table to which the objects in the collection are stored

To demonstrate the collection of basic types, consider the following code snippet where the Employee entity has a list of String type that stores phone numbers. PHONE is the collection table and the joinColumns attribute specifies the column name in the PHONE table, which will be joined with the EMPLOYEE table without specifying the foreign key relationship in the database. While storing the Phone objects, the phone numbers will be stored in the NUM column specified in @Column.

@Entity@Tablepublic class Employee {// Other Code   @ElementCollection          @CollectionTable(name = "PHONE",    joinColumns = @JoinColumn(name = "OWNERID"))@Column(name = "num")private List<String> phones;}

The following snippet shows a collection of embeddable types where the Employee entity has a list of Address objects, which are embeddable. EMPID is the column defined in the ADDRESS table, which is not mapped in the EMPLOYEE table.

@Entity@Tablepublic class Employee {// Other Code@ElementCollection@CollectionTable(name = "ADDRESS",joinColumns = @JoinColumn(name = "EMPID"))private List<Address> addresses;}

Additional Map Support in JPA 2

In JPA 1.x, maps used in OneToMany or ManyToMany relationships could have the map key either as the primary key of a table or as a column which is imposed with a unique constraint. JPA 2 overcomes this limitation by providing the flexibility of having the map keys or values be basic, embeddable or entity types.

The following code demonstrates the usage of map with the basic key type, which in this case is of type String and holds Product objects as the map value. The key is mapped to the type column of the PRODUCT table, which is specified using @MapKeyColumn. It is necessary to set the insertable and updatable attribute for the type property to false to avoid multiple mappings for the same field.

@Entity@Tablepublic class Employee {// Other Code@OneToMany(cascade = CascadeType.ALL, mappedBy = "empid")@MapKeyColumn(name="type")private Map<String, Product> productCollection;   @Column(name = "type", insertable=false, updatable=false)private String type;}

Let’s consider an example where the map key is of entity type, which is defined using @MapKeyJoinColumn. The Employee has a OneToMany relationship with the Project entity, where the collection is defined through maps. The PROJECT table contains references to the EMPLOYEE table and to the PROJECTTYPE table, which stores the map keys. Note that it is essential to set the insertable and updatable attributes to false to avoid multiple mapping.

   @Entity   public class Employee {@OneToMany(cascade = CascadeType.ALL, mappedBy = "empid")@MapKeyJoinColumn(name="projtypeid", insertable=false, updatable=false)private Map<ProjectType, Project> projectCollection;// Other code}@Entitypublic class ProjectType {   @OneToMany(cascade = CascadeType.PERSIST, mappedBy = "projtypeid")private Collection<Project> empProjectCollection;// Other Code}@Entitypublic class Project {   @JoinColumn(name = "projtypeid", referencedColumnName = "id")@ManyToOne(cascade=CascadeType.PERSIST, optional = false)private ProjectType projtypeid;@JoinColumn(name = "empid", referencedColumnName = "id")@ManyToOne(cascade=CascadeType.PERSIST, optional = false)private Employee empid;// Other Code}

You can define map keys of embeddable types in JPA 2. In the following example, the Employee entity has a OneToMany relationship to Project. The join table EMPLOYEE_PROJECT is used to store the foreign keys of the EMPLOYEE and PROJECT tables along with the TYPE column, which is used to store the map keys. The map keys are specified using @MapKeyClass and the actual map value can be determined by the targetEntity attribute of @OneToMany. Note that @MapKeyClass is not necessary when you use Java Generics syntax.

@EntityEmployee {@OneToMany(cascade = CascadeType.ALL, targetEntity=Project.class)@JoinTable(name = "employee_project", joinColumns =       @JoinColumn(name = "employee_id", referencedColumnName = "id"),    inverseJoinColumns =       @JoinColumn(name = "project_id", referencedColumnName = "id"))       @MapKeyClass(ProjectType.class)       private Map projectList;   // Other properties and methods}@EntityProject{     @ManyToOne(cascade = CascadeType.ALL)       @JoinTable(name = "employee_project", joinColumns =       @JoinColumn(name = "project_id", referencedColumnName = "id"), inverseJoinColumns =@JoinColumn(name = "employee_id", referencedColumnName = "id"))       private Employee employee;   // Other properties and methods}@EmbeddableProjectType {    private String type;}

Derived Identifiers

Consider the case in which the EMPLOYEE table has a relationship a PROJECT table that has a composite primary key comprising the projectId and a foreign key of the EMPLOYEE table. Typically you would work around this situation in JPA 1.x by having two attributes of the Project entity, namely the projectId and the employeeId, decorated with @Id and defining a primary key class using @IdClass and another property marked with @ManyToOne.

This extra work is reduced in JPA 2 by eliminating the foreign key attribute from the Project entity and marking the relationship attribute itself with @Id. But it is very important to note that the relationship attribute name should exactly match with the name of the attribute in the primary key class. The described scenario is shown below:

@Entity@IdClass (ProjectPK.class)public class Project {@Id String name;@Id @ManyToOne Employee employee;// Other Code.}public class ProjectPK {String name;    // matches name of @Id attributelong employee;    // matches name of @Id attribute and type of Employee PK}

Enhancements to Existing JPA 1.x Annotations

In this section, we will describe some changes made to the existing JPA 1.x annotations.

Additional Support for Embeddable Classes

Embeddable classes in JPA 2 can contain other embeddable classes and can also contain relationships to other entities, which was not possible in JPA 1.x. The Employee entity has an embedded PersonalInfo type which has a nested embeddable object Address. The PersonalInfo entity also has a bidirectional ManyToOne relationship with the Project entity. The mappedBy attribute of OneToMany determines the field that owns the relationship. In the following example it is determined by the attribute of the Employee entity followed by the dot (.) operator and the attribute of the PersonalInfo entity.

@EntityEmployee{@Embeddedprivate PersonalInfo personalInfo;// Other properties and methods}@EmbeddablePersonalInfo{@JoinColumn(name = "projectId", referencedColumnName = "id")@ManyToOne(optional = false, cascade=CascadeType.ALL)private Project project;      @Embeddableprivate Address address;// Other Properties and methods}   @EntityAddress{      // All the Properties and methods}   @EntityProject {@OneToMany(cascade = CascadeType.ALL, mappedBy = "personalInfo.project")          private List<Employee> employeeCollection;      // Other code}

@JoinTable for OneToOne Relationships

Suppose the Employee entity has a OneToOne relationship with the EmployeeRecord entity. In the EMPLOYEERECORD table a foreign key is maintained which corresponds to the EMPLOYEE table. But when the foreign keys are maintained in a separate table, you can decorate the EmployeeRecord instance with @JoinTable, which specifies the name of the join table. Here’s an example:

@Entity@Tablepublic class Employee {// Other Code      @OneToOne(cascade = CascadeType.ALL)          @JoinTable(name = "employee_record", joinColumns = {@JoinColumn(name="employeeId", referencedColumnName = "id")},          inverseJoinColumns = {@JoinColumn(name = "recordId", referencedColumnName = "id")})          private EmployeeRecord employeeRecord;}

@JoinColumn for Unidirectional OneToMany Relationships

JPA 1.x supports unidirectional OneToMany mapping by using a join table that stores the two foreign keys of the participating entities. JPA 2 avoids the usage of this join table by storing the foreign key in the many-to-one side.

Consider the Employee entity, which has a OneToMany unidirectional relationship with the File entity by having a List object. Theoretically the File entity should not have any relationship to the Employee entity, but it is not possible to insert a File object through the Employee entity without having the relationship. Hence, the File entity will have an Employee type that will not be part of the relationship. The @JoinColumn annotation specifies the foreign key in the File table, and this snippet shows very clearly that @JoinTable is not required to achieve the same result:

   @Entity@Tablepublic class Employee {// Other Code@OneToMany(cascade=CascadeType.ALL)          @JoinColumn(name="empId")          private List<File> fileList;}

Conclusion

In this article, we have discussed the new annotations introduced in JPA 2 with code examples. All these features have been implemented in EclipseLink. We also covered some additional capabilities provided by the existing annotations to make JPA perform a better and more convenient ORM.

Acknowledgements

The authors would like to sincerely thank Mr. Subrahmanya SV (VP, ECOM Research Group, E&R) for his constant encouragement and Ms. Sangeetha S. for providing the idea for this article, as well as guidance, valuable comments and reviews.

About the Authors

Mahalakshmi K. works at the E-Commerce Research Labs at Infosys Technologies Ltd. on Java EE technologies. Her core interest is in researching image processing, and she is also involved in the design and development of Java EE applications using Hibernate and JPA.

Nitin KL works at the E-Commerce Research Labs at Infosys Technologies. He is involved in design and development of Java EE applications using Hibernate, iBATIS, and JPA.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories