The Java Persistence Architecture API (JPA) is a Java specification
for accessing, persisting, and managing data between Java objects /
classes and a relational database.
Let's take a further look at
this definition. As the API portion of the name implies, JPA is a
specification, meaning it provides guidelines for developing an
interface that complies with a certain standard. While JPA dictates an
interface, it does not provide an implementation of that interface,
meaning there is no underlying code that performs the operations to
persist an object to a relational database.
It should also be
noted the term Object Relational Mapping, is often used to describe the
process of accessing, persisting and managing data between Java objects
and a relational database.
To look at the concept of JPA from another perspective, imagine if you were provided this interface.
public
interface
JPA {
public
void
insert(Object obj);
public
void
update(Object obj);
public
void
delete(Object obj);
public
Object select();
}
Without further development, what immediate value does this interface
provide? While this interface has potential to provide value, at this
point, very little value is provided because the interface lacks an
implementation. If this interface is used within any code it will not
execute because no concrete objects that implement this interface exist
to perform the work. This same concept applies to JPA just on a larger
scale since the API specification defines many interfaces and
annotations.
This is where the role of the JPA provider comes
into play. JPA providers develop a JPA implementation that meets the
requirements of the JPA specification. Hibernate is a JPA Provider, as
well as others such as EclipseLink and TopLink. With a JPA
implementation in place Java objects can be now be persisted to a
relational database, since there is underlying code to perform the work.
Returning to our interface analogy, if JPA is the interface then Hibernate represents a class that implements the interface.
public
class
Hibernate
implements
JPA {
public
void
insert(Object obj) {
}
public
void
update(Object obj) {
}
public
void
delete(Object obj) {
}
public
Object select() {
}
public
Object superSelect(){
}
}
Notice that in addition to implementing the JPA interface, the
Hibernate class contains some methods superfluous to the interface.
Keep this in mind for later. Given this JPA implementation, we could
now write some code that relies upon it to persist some data to a
relational database.
|
|
public class MyApplication {
public static JPA jpa = new Hibernate();
public static void main(String[] args) {
Object object = new Object();
jpa.insert(object);
}
}
|
The new application works well initially, but after a couple of
months its performance degrades. Let's assume that the Hibernate
implementation behind the scenes has several deficiencies causing the
poor performance. Remember, this is for example purposes and I am not
judging the merit of Hibernate.
Upon encountering this issue,
another provider may decide the need for another JPA implementation
exists. This provider creates their own implementation of the JPA
specification and publishes the code.
public class ToThoughtJpa implements JPA {
}
|
|
Having used the JPA interface in our application, we can now easily make the switch to the more reliant JPA implementation.
|
|
public class MyApplication {
public static JPA jpa = new ToThoughtJpa();
public static void main(String[] args) {
Object object = new Object();
jpa.insert(object);
}
}
|
The concept illustrated in our simple example is the main value JPA
provides only on a much larger scale. If we choose to use JPA, we can
eventually switch out our chosen JPA implementation for another
implementation as long as they both meet the JPA specification. In
reality, this is not always a seamless transition, since we often
utilize features of the implementation that are not support by the
specification and each implementation has its own little quirks. To
illustrate this point, consider if we had called the superSelect method
within our application.
public class MyApplication {
public static Hibernate jpa = new Hibernate();
public static void main(String[] args) {
Object object = new Object();
jpa.insert(object);
jpa.superSelect();
}
}
|
|
Notice that in order to call the method, the interface of type JPA
must be replaced with the Hibernate implementation. At this point, we
cannot swap our JPA implementation to the ToThoughtJpa JPA
implementation because its interface does not contain the superSelect
method. This example attempts to illustrate the restrictions that occur
when a developer chooses to use the straight Hibernate implementation,
which is not bound by the JPA specification.
In summary, JPA is
not an implementation, it will not provide any functionality within your
application. Its purpose is to provide a set of guidelines that can be
followed by JPA providers to create an ORM implementation in a
standardized manner. This allows the underlying JPA implementation to
be swapped and for developers to easily transition (think knowledge
wise) from one implementation to another. Hibernate is arguably the
most popular JPA provider. Hibernate's JPA implementation is used by
many developers, however some choose to use the actual Hibernate
implementation itself because the implementation may contain advanced
functionality not contained in the JPA implementation.