Chapter 4. Essential Java Persistence API 3.2

Alice Walker said, "In search of my mother's garden, I found my own."

In the last chapter, we introduced the session beans, which are the business service endpoints for your Java EE application. In this chapter, we are changing over to persistence, in what used to be called entity EJBs in the older J2EE specifications, but are now simply called Persistence Capable Objects (PCO).

The Java Persistence API (JPA), JSR 338, Version 3.2 is the specification that mandates how persistence can be applied to the objects in the Java EE product. One solution is storing data and a standard. Other solutions do exist, which also handle the problem of accessing and reading data into different types of long-term storage products. JPA 3.2 adds advanced features, such as ability to work with stored procedures, mapped entities, and fetch plans. You can read about these features in Chapter 11, Advanced Topics in Persistence.

Entities and the Java Persistence API first appeared in Java EE 5 as EJB 3.0 open source frameworks, such as Red Hat's Hibernate and Spring Framework, and proprietary solutions such as Oracle's TopLink also heavily influenced them.

The Java Persistence API is the standard object relation mapping API for both Java SE and Java EE. It means that you can use JPA inside the container and outside of it in a standalone program. JPA is based on POJO that are denoted, annotated, or configured in XML, to be persisted somewhere. In other words, JPA does not care or dictate exactly where your data is stored, it simply helps to map data from the Java objects to the underlying data storage and vice versa. The data store can be a relation database for maximum effectiveness, and it can also be a document database with limited functionality. The only limits are the type of Object/Relational Mapping (ORM) implementation and the complexity of the data model.

JPA is a specification and there are several implementations, which include, unsurprisingly, Hibernate, Apache OpenJPA, and also EclipseLink. The EclipseLink is a product that serves as the reference implementation of JPA, which was denoted to Eclipse Foundation by Oracle, and in a previous life, EclipseLink was offered under a different guise as TopLink Essentials. OpenJPA is an open source alternative for the JPA implementation.

As this is supposed to be a reference handbook, we will only see the essential cookbook features of JPA. It is not a substitute for the JPA official specification, which is quite extensive. Nor does it compete with other writings, articles, and tomes that are purely aimed at Java Persistence and data storage. Rather, this chapter is the foundation description, it will get you started writing the entity classes for your next business Java EE application. Chapter 5, Object-Relational Mapping with JPA, advances this knowledge into more intermediate-level problems of persistence.

Entities

An entity is a persistence capable object. For the Java platform and in the language of Java, it is a plain and simply object instance that has been specially marked (or in the vernacular of the older object relational mapper product, enhanced) in a way that means that it can be persisted to long-term storage, which, for most of us souls, is a relational database.

An entity for the cloud-enabled Java EE products can also be persisted to a cloud database with usually some tighter restrictions on what you can do with those types of objects.

JPA entities are mapped to the database tables or views. Going forward with this chapter, we are going to consider only relational databases.

Defining Entity bean

What is an entity bean? The answer is almost any class can be declared as an entity bean.

  • An entity bean is an object that has been annotated with @javax.persistence.Entity
  • An entity bean must have a public accessible no-arguments constructor
  • An entity bean cannot be declared final and nor can any methods or instance methods inside of it be declared final
  • An entity bean must be a top-level class, it cannot be an inner class for example
  • An entity bean cannot be a Java interface nor can it be a Java enum
  • An entity bean can be a concrete class or an abstract class, because entity beans support object-oriented inheritance and polymorphism through associations and types

Persistence of entity beans is extended to special cases: if an entity bean inherits from a non-entity bean and also if a non-entity bean inherits from an entity bean, only the persistent entity beans parts will be guaranteed to be stored.

For entity beans that need to be transferred over a network, for example in a remote connection, we recommend that the entity bean implement the javax.io.Serializable marker interface. In fact, we strongly recommend this for all of your entity beans, in order to allow them to be detached from and reattached to the persistence context session. We will discuss more on this notion of attachment to persistence contexts in later sections.

There is one more way to denote an object as an entity bean, which is not by using the @Entity annotation, but by declaring it inside an XML configuration file.

Therefore, the process to make an ordinary Java class be persisted to long-term storage is to add metadata to the class, which can be applied through the annotations or an XML configuration file. It is the sole responsibility of the JPA provider to perform the correct database operations in order to save the entity to storage (and load it back again of course).

An entity bean example

Let's review an example of a JPA entity bean, in which we will see two versions of this class is as follows:

A Plain Old Java Object

The following class is a data object, a POJO, which represents a record of a particular genre of fictional books that have been popular for over 100 years. Some books from this particular genre about spying, intergovernmental agencies, and other forms of esoteric investigations, have been turned into motion-picture and television productions. The class SpyThriller, which contains an identity number, the writer of the book, the year it was published, and of course the title, is as follows:

package je7hb.basic.jpa;

public class SpyThriller {
  private long id;
  private String writer;
  private int year;
  private String title;
  
  public SpyThriller() {}
  
  public SpyThriller(String writer, int year, String title) {
    this.writer = writer;
    this.year = year;
    this.title = title;
    }
  
  public long getId() {return id;}
  public void setId(long id) {this.id = id;}
  
  public String getWriter() {return writer;}
  public void setWriter(String writer) {this.writer = writer;}
  
  public int getYear() {return year;}
  public void setYear(int year) {this.year = year;}
  
  public String getTitle() {return title;}
  public void setTitle(String title) {this.title = title;}
  
  // toString() method omitted
  }

So far there is nothing special to see here in the SpyThriller bean. These are the usual pair methods for fulfilling the constraints of a valid JavaBean object that has properties. It is important to note that we can access each property of this Java bean through the getter and setter methods.

Note that we have the constructor that can populate all of the fields of the bean, except for the identity property, which is called id. We will see in this section, why this was written this way.

Let us now transform this bean into a JPA entity bean with some annotations. The second version of our bean is as follows:

A simple entity bean

The SpyThriller bean with some annotations that transforms it into a working entity bean is as follows:

package je7hb.basic.jpa;
import javax.persistence.*;

@Entity
public class SpyThriller {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;
  private String writer;
  private int year;
  private String title;
  
  public SpyThriller() {}
  
  // Full constructor omitted
  
  public long getId() {return id;}
  public void setId(long id) {this.id = id;}
  
  public String getWriter() {return writer;}
  public void setWriter(String writer) {this.writer = writer;}
  
  public int getYear() {return year;}
  public void setYear(int year) {this.year = year;}
  
  public String getTitle() {return title;}
  public void setTitle(String title) {this.title = title;}
  
  // toString() method omitted
  }

First, we applied the annotation @javax.entity.Entity to the class itself, which denotes that the bean is a persistent capable object suitable for enhancement.

Second, we also make sure that this POJO is serializable and it can be detached from the persistent session by extending the java.io.Serializable marker interface. This means that the SpyThriller entity bean can also be sent across a network, for example, using a session bean with a remote business interface.

Third, we applied the id property with two new annotations: @javax.entity.Id and @javax.entity.GeneratedValue.

The annotation @Id denotes a Java property to be the primary key of the entity bean. In particular, every entity must have a primary key. The primary key of the entity is the unique identifier for the bean inside the database.

The annotation @GeneratedValue denotes the entity has a unique value that is generated by the database. There are different strategies for creating the database unique identifier, and in the preceding example, strategy=AUTO means that we are relying on the database to explicitly generate this identifier for our SpyThriller bean.

So, when we first insert a SpyThriller bean into the database, the identifier id will be automatically generated for us by the underlying database, and the bean's id property will be populated with this value by the JPA provider. This is the reason why the identifier id was not specified as part of the bean's constructor arguments.

In SpyThriller, all of the properties, the fields of the bean, are by default persistent capable, and they will be stored inside the database. What happens if we do not want this persistence for a particular field? We can apply to the field an annotation @javax.entity.Transient. Another version of our entity bean so far is as follows:

@Entity
public class SpyThriller extends java.io.Serializable {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;
  private String writer;
  private int year;
  private String title;
  
  @Transient
  private String secretCode;
  
  public SpyThriller() {}
  // Same code as before
  }

In the preceding code fragment, the field secretCode is not persistent capable, and it will never be stored inside the database because it is annotated with @Transient.

Let us summarize the annotations so far as follows:

Annotation

Description

@Entity

Specifies the bean as persistence capable

@Id

Specifies the primary key of the entity bean

@GeneratedValue

Specifies the value of the property generated using a strategy in the underlying database or custom implementation

@Transient

Specifies the property is not being persisted inside the database

Expanded entity bean definition

The JPA specification is designed to allow programming by convention-over-configuration in order to ease software development. This means there are reasonable defaults; it follows the principle of least astonishment.

There are more annotations that the last example code hid from the naked eye. Let us look at an expanded definition of entity bean as follows:

import javax.persistence.*;

@Entity(name = "SpyThriller")
@Table(name = "SPY_THRILLER_BOOK")
public class SpyThriller extends Serializable {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "BOOK_ID", table = "THRILLER_BOOK", unique = true, nullable = false, insertable = true, updatable = true)
  private long id;
  @Basic(fetch = FetchType.EAGER)
  @Column(name = "AUTHORS", nullable = false)
  private String writer;
  @Column(name = "BOOK_YEAR", nullable = false)
  private int year;
  @Column(name = "TITLE", nullable = false)
  private String title;
  
  public SpyThriller() {}
  }

The @Table annotation

The @javax.entity.Table annotation specifies the target name of the database table, and applying the annotation to the code allows us to override the default. Every entity bean typically represents a single row in a database table, and each database table has a set of table columns. In order for the JPA provider to map the entity to the database, it needs to know the database table name. If the @Table annotation is not provided, then the name of the entity bean is used. Because the database systems support only certain character cases, be it only uppercase, lowercase, or mixed case, with or without some underscore characters, there has to be a way out for the software developer to explicitly override the sensible convention on their chosen system.

In most cases, the database table name will default to the uppercase of the entity bean's class name with underscores in between the camel case. For example, SpyThriller is mapped to SPY_THRILLER. If you need a specific datable table name then use the @Table annotation.

The @Entity annotation

For the purpose of the Java Persistence Query Language (JPQL), @javax.entity.Entity allows the entity query name to be overridden. Please note that the query name is not necessarily the same as the target database name. The annotation @Table sets the database table name. @Entity specifies that the Java class is persistence capable under a JPA provider, and is suitable for enhancement and mapping to a database.

The @Basic annotation

The @javax.entity.Basic annotation defines the simple enhancement possible in JPA. It maps a field or persistent property to a database column. It maps the Java primitive types, the primitive wrapper types, the serializable types, the user-defined serializable types, and certain standard class types from SDK and certain array types. See the following table for the full list.

The main use of @Basic defines how the JPA provider actually retrieves dependent columns and links to the associated records from the database. There are two forms of access: LAZY and EAGER.

publicenumFetchType {LAZY, EAGER};
@Target({METHOD, FIELD}) @Retention(RUNTIME)

The EAGER strategy informs the JPA provider that the data must be readily fetched. In other words, it should be fetched eagerly. The LAZY strategy informs the JPA provider that it permits it to fetch the data, only when the property or field is about to be accessed. The default mode is EAGER.

A list of valid mappings for @Basic field/properties is shown in the following table:

Class and types

Remarks

Java primitive types

boolean, byte, char, short, int, long, float, double

Java wrapper types

java.lang.Boolean, java.lang.Byte, java.lang.Character, java.lang.Short, java.lang.Integer, java.lang.Long, java.lang.Float, java.lang.Double

Serializable type

Standard Java serialized types and user-defined types implementing the java.io.Serializable marker interface

Enums

Standard Java enumerations

String

The standard java.lang.String implementation

Math

java.math.BigInteger and java.math.BigDecimal

Database JDBC temporal types

java.sql.Date, java.sql.Time, and java.lang.DateTime

Array primitives

byte[] and char[]

Wrapper Primitives

java.lang.Byte[] and java.lang.Character[]

The JPA specification, as you can see yourself, allows most types to be mapped by default to the database. The extra wrapper array primitives and array primitives are quite useful for the binary object (BLOB) mapping.

The @Column annotation

As each entity bean maps to a single database table row, there is another annotation that corresponds to @Table. The annotation @javax.entity.Column specifies how a field or persistent property maps to a database table column.

The @Column annotation allows the configuration of the database table name, whether it can be a null column, whether a new record with that column can be inserted, and/or whether an existing record with that particular column can be updated.

Most of the time developers will just want to override the column name, and see if the column can contain the NULL values or not.

In the preceding example code there are two examples where we override the configuration. We override the field year to the target database column name BOOK_YEAR because in the Apache Derby database, year is a reserved keyword! Also, we override the writer field to map explicitly the target database column name AUTHORS.

A table of the @javax.entity.Column annotation arguments is as follows:

Name

Type

Description

Default Value

name

String

The name of the column.

The name of the field or property

unique

Boolean

Defines if this column is unique in the database table.

false

nullable

Boolean

Defines if this column accepts the NULL values.

false

insertable

Boolean

Defines whether this column is included in the SQL INSERT command generated by the JPA provider.

true

updatable

Boolean

Defines whether this column is included in the SQL UPDATE commands that are generated by the JPA provider.

true

columnDefinition

Boolean

Defines SQL fragment that is used when generating the database description language for the column, for example, CLOB NOT NULL.

Generated SQL from the JPA provider, which creates the database table column

table

String

Defines the database table that contains the column. This argument is used to override the primary table from the entity.

Column is in the primary table of the entity bean

length

int

The column length. This argument is only applicable for a String value column.

255

precision

int

The precision for a decimal type column. This is typically for real number database columns.

0

scale

int

The scale for a decimal column. This is typically configured only for real number database columns.

0

All the @Column annotation arguments are optional, but at least one argument must be defined for sensible operation.

Annotating entity beans

As a developer, you can annotate the field variables of an entity bean in order to inform the JPA provider how to enhance the object-relation mapping to the target database table. You have seen how this works previously, but there is a second way to annotate entity beans. Alternatively, you can also annotate the getter and setter methods on entity beans.

The decision to annotate on the field variables or the getter properties is down to personal preference. After all is considered, you in the role as the bean provider make this decision. Let us look at the case of the getter and setter annotations.

Annotating entities with the instance variables

Here is an entity bean class for a train system, Train, which is a very simple data object. It has three field variables standing for the source and target locations, and a time that is formatted as a long primitive with the pattern: yyyyMMdd.

package je7hb.basic.jpa;
import javax.persistence.*;
import java.io.Serializable;

@Entity
public class Train implements Serializable {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private long id;
  
  @Column(name = "FROM_LOC", nullable = false)
  private String from;
  
  @Column(name = "TO_LOC", nullable = false)
  private String to;
  
  /** Pattern format yyyyMMdd */
  @Column(name = "TRAIN_DATE")
  private int trainDate;
  
  public Train() {this(null,null,0);}
  public Train(String from, String to, int trainDate) {
    this.from = from;
    this.to = to;
    this.trainDate = trainDate;
    }
  
  public long getId() {return id;}
  public void setId(long id) {this.id = id;}
  
  public String getFrom() {return from;}
  public void setFrom(String fromLoc) {
    this.from = fromLoc;
    }
  
  public String getTo() {return to;}
  public void setTo(String toLoc) {this.to = toLoc;}
  
  public int getTrainDate() {return trainDate;}
  public void setTrainDate(int trainDate) {
    this.trainDate = trainDate;
    }
  // toString() method omitted
  }

The Train entity class is annotated on the field variables: id, from, to, and trainDate. We have used the @Column annotation to explicitly specify the target database column names, because the field variables named are mostly reserved keywords in the underlying database.

Annotating entities with property accessors

The same entity class annotated on the getter and setter methods is as follows:

package je7hb.basic.jpa;

import javax.persistence.*;
import java.io.Serializable;

@Entity
public class Train implements Serializable {
  private long id;
  private String from;
  private String to;
  private int trainDate;
  public Train2() {this(null,null,0);}
  
  public Train(String from, String to, int trainDate) {
    this.from = from;
    this.to = to;
    this.trainDate = trainDate;
    }
  
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  public long getId() {return id;}
  public void setId(long id) {this.id = id;}
  
  @Column(name = "FROM_LOC", nullable = false)
  public String getFrom() {return from;}
  public void setFrom(String fromLoc) {
    this.from = fromLoc;
    }
  
  @Column(name = "TO_LOC", nullable = false)
  public String getTo() {return to;}
  public void setTo(String toLoc) {this.to = toLoc;}
  
  /** Pattern format yyyyMMdd */
  @Column(name = "TRAIN_DATE")
  public int getTrainDate() {return trainDate;}
  public void setTrainDate(int trainDate) {
    this.trainDate = trainDate;
    }
  
  // toString() method omitted
  }

Moving the annotations to the getter and setter methods has one advantage in that it allows the LAZY instantiation of the property. Let us suppose the Train entity had an expensive or large-dependent entity bean that implied significant performance cost, then annotating the getter and setter properties may be useful.

Developer, the bean provider, must ensure that there is no public access to the fields of the instance variables. In particular, the clients of entity bean and related entity beans must always call the getter methods in to access an entity's properties.

For entity beans that are standalone, the decision to annotate the field variables versus the accessor methods can be trivial. When entity bean is part of the object hierarchy, then choosing one style or the other is very important. If you choose the field instance for the root class of the hierarchy, you are advised to follow it for all the subentity bean classes. Do not mix the two styles.

Comparing annotating styles

A table of cost and benefits of annotating the instance variables versus the property accessor methods is as follows:

 

Benefits

Costs

Instance Variable

  • Fastest performance, avoids the overhead of the method calls
  • The JPA provider persistence manager has direct access in order to read and write from and to the DB
  • Less lines of code
  • Not possible to achieve the LAZY initialization
  • Can be expensive for the property objects that really require the LAZY initialization

Property Accessor

  • The LAZY initialization of the property
  • Creation of the values on demand
  • Provides a simple way to add an extra behavior during the initialization
  • Performance loss with extra method calls
  • Impact on properties, if entity bean is involved in a query
  • More lines of code

There are two styles to annotate JPA and entity beans. Injecting into the bean getter and setter methods, obviously, provides a way of intercepting the incoming argument, and also computing a result or triggering some other action. On the other hand, we recommend that entities should be kept relatively simple, and serious business logic should go into either Bean Validation or service endpoints.

Tip

Choose one style of annotating entity beans at the beginning of your software development team's project and stay with it for the duration. Remember not to mix the annotation styles in the entity bean hierarchies, especially.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.131.10