EclipseLink / JPA Annotations – @MappedSuperclass

This tutorial will explain the using of @MappedSuperclass, that could be considered as an alternative choice for sharing a persistent entity state and mapping information. An entity may inherit from a super class that provides a persistent entity state and mapping information as we’ve seen previously in the @Inheritance tutorials. Unlike using of @Inheritance, the @MappedSuperclass doesn’t involve in any persistent activity and it doesn’t involve in any operations that managed by the EntityManager. The main purpose of using a @MappedSuperclass is to define a common states and mapping information that could be shared by multiple entity classes.

@MappedSuperclass annotated class is not persisted itself, but the sub-classes are persistent. So, this annotation is used for an abstract class or a non-persistent class. The equivalent XML element is mapped-superclass in the persistent configuration file.

Some of the characteristics of @MappedSuperclass is:

  • Normally class is abstract, but it never be a persistence instance
  • Mapped superclasses can not define a table, but can define mapping for attributes.
  • This annotation doesn’t have any attributes.

Classes Design

Let’s see the classes design that would be formed the field MappedSuperclass annotation could provide a help inside it. See figure 1.1.

MappedSuperclassDesign

Figure 1.1

The License class is an abstract class contains one attribute named licenseId. Set of classes have a chance to inherit from License abstract class, but because of we are not aware of the number of classes that may inherit it we’ve denoted for any future coming classes with (AnyClass extends License).

We are supposed to have a new class called DriverLicense as an extended class and you will see it in the next section.

License.java

package net.javabeat.eclipselink.data;

import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

@MappedSuperclass
public abstract class License {

 @Id protected int licenseId;

public int getLicenseId() {
 return licenseId;
 }

public void setLicenseId(int licenseId) {
 this.licenseId = licenseId;
 }
}

DriverLicense.java

package net.javabeat.eclipselink.data;

import java.util.Date;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity // Annotate the DriverLicense as an Entity that must be persisted by the JPA
@Table(name="driverlicenses") // The Table name that the instance of DriverLicense should be persisted there
public class DriverLicense extends License{
 // DriverLicense Inherited  protected int
 private String driverLicenseName;
 @Temporal(TemporalType.DATE) // The temporal is mandatory when we are coming to deal with Date
 private Date driverLicenseExpiryDate;
 @Temporal(TemporalType.DATE)
 private Date driverLicenseIssueDate;

 @ManyToOne(cascade=CascadeType.ALL)
 @JoinColumn(name="employeeId")
 private Employee employee;

 public Employee getEmployee() {
    return employee;
 }
 public void setEmployee(Employee employee) {
    this.employee = employee;
 }
 public String getDriverLicenseName() {
    return driverLicenseName;
 }
 public void setDriverLicenseName(String driverLicenseName) {
    this.driverLicenseName = driverLicenseName;
 }
 public Date getDriverLicenseExpiryDate() {
     return driverLicenseExpiryDate;
 }
 public void setDriverLicenseExpiryDate(Date driverLicenseExpiryDate) {
     this.driverLicenseExpiryDate = driverLicenseExpiryDate;
 }
 public Date getDriverLicenseIssueDate() {
     return driverLicenseIssueDate;
 }
 public void setDriverLicenseIssueDate(Date driverLicenseIssueDate) {
     this.driverLicenseIssueDate = driverLicenseIssueDate;
 }
}

Database Design

The License class annotated with MappedSuperclass, so no need for creating any database table for it, meanwhile and at the other side, any entities that inherit from License class and not annotated using MappedSuperclass need a database mapping table. See Figure 1.2 that shows you the final view for the database tables.

MappedSuperclassDatabaseDesign

Figure 1.2

Notes:

  • The License class doesn’t consider as a persisted entity, cause it’s annotated as a MappedSuperclass.
  • The DriverLicense class considered as an entity, cause it’s annotated as @Entity and it’s mapped into DriverLicense table.
  • The DriverLicense inherit a licenseId attribute from the License MappedSuperclass.
  • The DriverLicense can override any inherited attributes or associations using @AttributeOverride and @AssociationOverride.
  • The DriverLicense associate the Employee with an OneToMany unidirectional association.
  • The DriverLicense table should hold all attributes that are defined by the entity and its MappedSuperclass (licenseId).

Persistence Configuration

The persistence.xml should mention the mapped sueprclass and its sub classes. If you’ve omit the License mapped superclass you are almost getting a compiler error tells you (The License is managed but is not listed in the persistence.xml file). Even if the License will not be part of any EntityManager’s operation, but it should be declared there for making the mapping sharing possible.


<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
 <persistence-unit name="EclipseLink-JPA-Installation" transaction-type="RESOURCE_LOCAL">
<!-- The entities mentioned here covers previous examples -->
 <class>net.javabeat.eclipselink.data.Employee</class>
 <class>net.javabeat.eclipselink.data.Developer</class>
 <class>net.javabeat.eclipselink.data.Address</class>
 <class>net.javabeat.eclipselink.data.Phone</class>
 <class>net.javabeat.eclipselink.data.Project</class>
 <class>net.javabeat.eclipselink.data.GlobalProject</class>
 <class>net.javabeat.eclipselink.data.LocalProject</class>
<!-- License & DriverLicense are required classes for this example -->
 <class>net.javabeat.eclipselink.data.License</class>
 <class>net.javabeat.eclipselink.data.DriverLicense</class>
 <properties>
 <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/JavaBeat"/>
 <property name="javax.persistence.jdbc.user" value="root"/>
 <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
 <property name="javax.persistence.jdbc.password" value="root"/>
 <property name="eclipselink.logging.level" value="FINEST"/>
 </properties>
 </persistence-unit>
</persistence>

Executable Application

Look at the Java code that runs a JPA persistence for persisting a DriverLicense associated with an Employee.

package net.javabeat.eclipselink;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import net.javabeat.eclipselink.data.Address;
import net.javabeat.eclipselink.data.Developer;
import net.javabeat.eclipselink.data.DriverLicense;
import net.javabeat.eclipselink.data.Employee;
import net.javabeat.eclipselink.data.GlobalProject;
import net.javabeat.eclipselink.data.LocalProject;
import net.javabeat.eclipselink.data.Phone;
import net.javabeat.eclipselink.data.Project;

public class JPAImpl {
 static EntityManagerFactory factory = null;
 static EntityManager em = null;
 static {
 factory = Persistence.createEntityManagerFactory("EclipseLink-JPA-Installation");
 em = factory.createEntityManager();
 }
 public static void main(String [] args){
 // Begin a Transaction
 em.getTransaction().begin();
 // Create Employee
 createEmployee();
 // Commit
 em.getTransaction().commit();

 // Begin another Transaction
 em.getTransaction().begin();
 // Find the Employee
 Employee employee = em.find(Employee.class, 2);
 // Create a Driver License
 createDriverLicense(employee);
 // Commit
 em.getTransaction().commit();

}

 public static void createDriverLicense(Employee employee){
 DriverLicense license = new DriverLicense(); // Create a driver license
 license.setLicenseId(1);// Set license id
 license.setDriverLicenseName("All Vehicles License"); // Set License Name
 license.setDriverLicenseIssueDate(new Date()); // Anonymous date
 license.setDriverLicenseExpiryDate(new Date()); // Anonymous date
 license.setEmployee(employee);
 em.persist(license);
 }

public static void createEmployee(){
 // Create an address entity
 Address address = new Address();
 address.setAddressId(2);
 address.setAddressCountry("United Kingdom");
 address.setAddressCity("London");
 // Create an employee entity
 Employee employee = new Employee();
 employee.setEmployeeId(2);
 employee.setEmployeeName("John Smith");
 // Associate the address with the employee
 employee.setAddress(address);
 // Create a Phone entity
 Phone firstPhone = new Phone();
 firstPhone.setPhoneId(3);
 firstPhone.setPhoneNumber("+221 4050 615");
 firstPhone.setEmployee(employee);
 // Create a new phone entity
 Phone secondPhone = new Phone();
 secondPhone.setPhoneId(4);
 secondPhone.setPhoneNumber("+221 4050 619");
 // Use the old employee entity
 secondPhone.setEmployee(employee);
 // Create a list of phone
 List<Phone> phones = new ArrayList<Phone>();
 phones.add(firstPhone);
 phones.add(secondPhone);

 // Create a Project entity
 Project project = new Project();
 project.setProjectId(2);
 project.setProjectName("Nasa Project");

 // Create a list of projects
 List<Project> projects = new ArrayList<Project>();

 // add the project into the list
 projects.add(project);

 // Set the project into employee
 employee.setProjects(projects);
 // Set the phones into your employee
 employee.setPhones(phones);

 // Persist the employee

 em.persist(employee);
 }
}

Summary

This tutorial introduced a new annotation for sharing a mapping information rather using @Inheritance@MappedSuperclass used to annotate a class whose instance won’t be persisted or participate in any persisting operation, while its sub classes will do. In the previous examples we’ve seen a License class that annotated with an @MappedSuperclass, even if it has no abstract non-access modifier, it’s will not considered in a any future persisting operation. However, all sub classes that inherit from the License and doesn’t marked as @MappedSuperclass will participate in the persisting operations such DriverLicense. Remember that – The main goal of @MappedSuperclass is to share the mapping information with the sub classes.

Comments

comments

About Amr Mohammed

Speak Your Mind

*