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:
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.
To create an entity which inherits a mapped superclass, follow the given steps:
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
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
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.
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 {..}
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:
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
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
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;
3.22.61.218