Creating a mapped superclass

In this recipe, we'll look at how to create an entity which inherits a mapped superclass. The fields of a mapped superclass are stored into the table to which the inheriting entity is mapped. The mapped superclass itself is not mapped to any table. In this recipe, we'll create the Flight entity, which extends the AuditFields class. The AuditFields class represents a mapped superclass; the fields of AuditFields are stored into the table to which the Flight entity is mapped.

The following figure shows the relationship between the Flight entity and the AuditFields mapped superclass:

Creating a mapped superclass

Getting ready

Exit the Roo shell and delete the contents of the C: oo-cookbookch03-recipes directory.

Start the Roo shell from the C: oo-cookbookch03-recipes directory.

Execute the ch03_jpa_setup.roo script which creates the flight-app Roo project, sets up Hibernate as persistence provider, and configures MySQL as the database for the application. If you are using a different database than MySQL or your connection settings are different than what is specified in the script, then modify the script accordingly.

How to do it...

To create an entity which inherits a mapped superclass, follow the given steps:

  1. Create the AuditFields class using the entity command and add fields to it:
    .. roo> entity --class ~.domain.AuditFields --mappedSuperclass
    ~.domain.AuditFields roo> field date --type java.util.Date --fieldName createdDate
    ~.domain.AuditFields roo> field date --type java.util.Date --fieldName modifiedDate
    ~.domain.AuditFields roo> field string --fieldName createdBy
    ~.domain.AuditFields roo> field string --fieldName modifiedBy
    
  2. Create the Flight entity using the entity command and add fields to it:
    .. roo> entity --class ~.domain.Flight --extends ~.domain.AuditFields --table FLIGHT_TBL
    
    ~.domain.Flight roo> field date --type java.util.Date --fieldName departureDate --column DEPARTURE_DATE
    ~.domain.Flight roo> field date --type java.util.Date --fieldName arrivalDate --column ARRIVAL_DATE
    

How it works...

The mappedSuperclass argument of the entity command is responsible for creating a mapped superclass. It's a flag type argument; if present, it indicates that the generated class must be annotated with the @MappedSuperclass JPA annotation. The following code shows the relevant annotations of the AuditFields mapped superclass, as generated by the entity command:

@RooJavaBean
@RooToString
@RooEntity(mappedSuperclass = true)
public class AuditFields {..}

As shown in this code, the AuditFields class is annotated with the @RooEntity annotation. As we saw earlier, the @RooEntity annotation triggers Roo to generate a *_Roo_Entity.aj AspectJ ITD file corresponding to the AuditFields class. The mappedSuperclass attribute of the @RooEntity annotation instructs Roo to add a declaration in the corresponding *_Roo_Entity.aj that annotates the AuditFields class with the @MappedSuperclass annotation (instead of the @Entity JPA annotation).

When an entity class extends a mapped superclass, the Roo generates a *_Roo_Entity.aj Aspect ITD file corresponding to the mapped superclass and defines an identifier field (annotated with @Id JPA annotation), along with methods such as persist, merge, refresh, and so on. (that we saw in the Creating persistent entities recipe of Chapter 2). In this case, the inheriting entity's *_Roo_Entity.aj file only defines the static count and finder methods for the entity.

The following code listing shows the AuditFields_Roo_Entity.aj file:

privileged aspect AuditFields_Roo_Entity
{
   declare @type: AuditFields: @MappedSuperclass;

   @PersistenceContext
   transient EntityManager AuditFields.entityManager;
   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   @Column(name = "id")
    private Long AuditFields.id;
    
   @Version
   @Column(name = "version")
   private Integer AuditFields.version;
   @Transactional
   public void AuditFields.persist()
   {
      if (this.entityManager == null) 
        this.entityManager = entityManager();
      this.entityManager.persist(this);
}
    
   @Transactional
   public void AuditFields.remove() {...}

    public static final EntityManager 
             AuditFields.entityManager() {...}
   ...
}

The given code shows that the AuditFields_Roo_Entity.aj ITD annotates the AuditFields class with the @MappedSuperclass annotation. Also, notice that the ITD doesn't annotate the AuditFields class with @Entity and @Table annotation. This code shows that the *_Roo_Entity.aj ITD of a mapped superclass is the same as that of an entity—consisting of identifier and version definitions, persist, remove, and so on methods, and a method to obtain the JPA EntityManager instance.

As the Flight entity inherits from the AuditFields class, Roo generates a Flight_Roo_Entity.aj ITD that doesn't contain identifier and version definitions or persistence methods for persisting, refreshing, and merging the

Flight entity, as shown in the following code listing:

privileged aspect Flight_Roo_Entity
{
   declare @type: Flight: @Entity;
   declare @type: Flight: @Table(name = "FLIGHT_TBL");
   public static long Flight.countFlights() {..}
   public static List<Flight> Flight.findAllFlights(){..}
   public static Flight Flight.findFlight(Long id) {..}
   public static List<Flight> Flight.findFlightEntries(
      int firstResult, int maxResults) {..}
}

The given code shows that the Flight entity contains only the find and count methods and inherits the identity, version definitions, and persistence related methods from the AuditFields mapped superclass. As in the case of any other JPA entity, the ITD annotates the Flight class with the @Entity and the @Table annotations.

There's more...

Even though the mapped superclass contains the identifier definition, you can override it in the inheriting entity by using @AttributeOverride or @AttributeOverrides JPA annotation. The following code shows how the Flight entity can override the identifier definition in the AuditFields class to map the identifier field to the FLT_ID column of FLIGHT_TBL table:

@RooJavaBean
@RooToString
@RooEntity(table="FLIGHT_TBL")
@AttributeOverride(name="id", column=@Column(name="FLT_ID"))
public class Flight extends AuditFields {..}

Creating @Embeddable annotated classes

In the last recipe, we saw that the Flight entity inherits the AuditFields mapped superclass. You could have modelled the Flight entity such that it contained the AuditFields instance in the Flight entity itself instead of inheriting from it. To do so, you need to create an AuditFields class annotated with @Embeddable JPA annotation, define the reference to the AuditFields class in the Flight entity, and annotate the referencing field with the @Embedded JPA annotation. Let's see how we can do this in Roo:

  1. Create the AuditFields class using the entity command and add fields to it as shown here:
    .. roo> embeddable --class ~.domain.AuditFields
    ~.domain.AuditFields roo> field date --type java.util.Date --fieldName createdDate
    ~.domain.AuditFields roo> field date --type java.util.Date --fieldName modifiedDate
    ~.domain.AuditFields roo> field string --fieldName createdBy
    ~.domain.AuditFields roo> field string --fieldName modifiedBy
    
  2. Create the Flight entity using the entity command and add fields to it as shown here:
    .. roo> entity --class ~.domain.Flight --table FLIGHT_TBL
    
    ~.domain.Flight roo> field date --type java.util.Date --fieldName departureDate --column DEPARTURE_DATE
    ~.domain.Flight roo> field date --type java.util.Date --fieldName arrivalDate --column ARRIVAL_DATE
    
  3. Using the field embedded command, define AuditFields as an embedded object in the Flight entity as shown here:
    ~.domain.Flight roo> field embedded --fieldName auditFields --type ~.domain.AuditFields
    

The following code shows the AuditFields class generated by the embeddable command:

@RooJavaBean
@RooToString
@Embeddable
public class AuditFields
{
   @Temporal(TemporalType.TIMESTAMP)
   @DateTimeFormat(style = "S-")
   private Date createdDate;

   @Temporal(TemporalType.TIMESTAMP)
   @DateTimeFormat(style = "S-")
   private Date modifiedDate;

   private String createdBy;

   private String modifiedBy;
}

The given code shows that the AuditFields class is annotated with the JPA @Embeddable annotation. It is not annotated with the @RooEntity annotation, which means that it doesn't contain identifier and version definitions, and persistence related methods.

The following code shows the Flight entity:

@RooJavaBean
@RooToString
@RooEntity(table = "FLIGHT_TBL")
public class Flight
{
...
   @Embedded
   private AuditFields auditFields;
}

This code shows that the Flight entity contains a reference to the AuditFields class. The AuditFields reference is added by the field embedded command and it is annotated with the @Embedded JPA annotation.

If you want to override the mapping of the fields defined in the AuditFields class, you can use the @AttributeOverrides and @AttributeOverride JPA annotations. The following code snippet shows how these annotations can be used in the Flight entity to map the createdDate and modifiedDate fields of the AuditFields class to the C_DATE and M_DATE columns of the table to which the Flight entity maps:

@Embedded
@AttributeOverrides({
  @AttributeOverride(name="createdDate",
    column=@Column(name="C_DATE")),
  @AttributeOverride(name="modifiedDate", 
    column=@Column(name="M_DATE"))
})
private AuditFields auditFields;

See also

  • Refer to the Creating persistent entities recipe of Chapter 2 to see how to create persistent entities, which do not inherit from a mapped superclass
..................Content has been hidden....................

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