Describe the use of annotations and XML mapping files, individually and in combination, for object-relational mapping.

[Note]
  • [EJB_3.0_PERSISTENCE] 9.1.1; 9.1.4; 9.1.8; 9.1.15; 9.1.9; 9.1.17; 9.1.18; 9.1.19; 9.1.20; 9.1.21; 9.1.16

Persistence metadata is specified using either the Java 5 annotations defined in the javax.persistence package, XML mapping files, or a mixture of both. In the latter case, XML declarations override conflicting annotations. If you choose to use XML metadata, the XML files must be available at development and runtime, and must be discoverable via either of two strategies:

  1. In a resource named orm.xml placed in a META-INF directory within a directory in your classpath or within a jar archive containing your persistent classes.

  2. Declared in your persistence.xml configuration file. In this case, each XML metadata file must be listed in a mapping-file element whose content is either a path to the given file or a resource location available to the class' class loader.

Table Annotation

The Table annotation specifies the primary table for the annotated entity. Additional tables may be specified using SecondaryTable or SecondaryTables annotation.

@Target({TYPE}) @Retention(RUNTIME)
public @interface Table {
	String name() default "";
	String catalog() default "";
	String schema() default "";
	UniqueConstraint[] uniqueConstraints() default {};
}
					

If you omit the Table annotation, base entity classes default to a table with their Entity name. The default table of an entity subclass depends on the inheritance strategy.

Example of Mapping Classes:

@Entity
@Table(name="SUB", schema="CNTRCT")
public class Subscription {
	...
}
					
@Entity(name="Lifetime")
public class LifetimeSubscription extends Subscription {
	...
}
					
@MappedSuperclass
public abstract class Document {
	...
}
					
@Embeddable
public class Address {
	...
}					
					

The same mapping information expressed in XML:


<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd"
	version="1.0">
    
	<entity class="org.mag.subcribe.Subscription">
		<table name="SUB" schema="CNTRCT"/>
		...
	</entity>    
    
	<entity class="LifetimeSubscription" name="Lifetime">
		...
	</entity>    
    
	<mapped-superclass class="Document">
		...
	</mapped-superclass>
	
	<embeddable class="Address">
		...
    </embeddable>
    
</entity-mappings>

					

UniqueConstraint Annotation

The UniqueConstraint annotation is used to specify that a unique constraint is to be included in the generated DDL for a primary or secondary table.

@Target({}) @Retention(RUNTIME)
public @interface UniqueConstraint {
	String[] columnNames();
}
					

Unique constraints ensure that the data in a column or combination of columns is unique for each row. A table's primary key, for example, functions as an implicit unique constraint. In JPA, you represent other unique constraints with an array of UniqueConstraint annotations within the table annotation. The unique constraints you define are used during table creation to generate the proper database constraints, and may also be used at runtime to order INSERT, UPDATE, and DELETE statements. For example, suppose there is a unique constraint on the columns of field F. In the same transaction, you remove an object A and persist a new object B, both with the same F value. The JPA runtime must ensure that the SQL deleting A is sent to the database before the SQL inserting B to avoid a unique constraint violation.

UniqueConstraint has a single property: String[] columnNames - the names of the columns the constraint spans. Note that the columnNames array refers to the LOGICAL column names.

In XML, unique constraints are represented by nesting unique-constraint elements within the table element. Each unique-constraint element in turn nests column-name text elements to enumerate the contraint's columns.

The following defines a unique constraint on the TITLE column of the ART table:

@Entity
@Table(name="ART", uniqueConstraints=@UniqueConstraint(columnNames={"TITLE"}))
public class Article {
	...
}
					

The same metadata expressed in XML form:


<entity class="Article">
	<table name="ART">
		<unique-constraint>
			<column-name>TITLE</column-name>
		</unique-constraint>
	</table>
	...
</entity>

					

Column Annotation

The Column annotation is used to specify a mapped column for a persistent property or field.

@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface Column {
	String name() default ""; 
	boolean unique() default false;
	boolean nullable() default true;
	boolean insertable() default true;
	boolean updatable() default true;
	String columnDefinition() default "";
	String table() default "";
	int length() default 255;
	int precision() default 0; // decimal precision
	int scale() default 0; // decimal scale
}
					

The column(s) used for a property mapping can be defined using the @Column annotation. Use it to override default values (for example: the name of the column is the same as the property or field name). You can use this annotation for properties or fields that are:

Example below shows the name property mapped to the flight_name column, which is not nullable, has a length of 50 and is not updatable (making the property immutable):

@Entity
public class Flight implements Serializable {

	@Column(updatable = false, name = "flight_name", nullable = false, length=50)
	public String getName() { 
		... 
	}
}
					

Example:

@Column(name="DESC", nullable=false, length=512)
public String getDescription() {
	return description;
}
					

Example:

@Column(name="DESC", columnDefinition="CLOB NOT NULL", table="EMP_DETAIL")
@Lob
public String getDescription() {
	return description;
}
					

Example:

@Column(name="ORDER_COST", updatable=false, precision=12, scale=2)
public BigDecimal getCost() {
	return cost;
}
					

The equivalent XML element is column. This element has attributes that are exactly equivalent to the Column annotation's properties.

Id Annotation

The Id annotation specifies the primary key property or field of an entity. The Id annotation may be applied in an entity or mapped superclass.

By default, the mapped column for the primary key of the entity is assumed to be the primary key of the primary table. If no Column annotation is specified, the primary key column name is assumed to be the name of the primary key property or field.

@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface Id {}
					

The equivalent XML element is id. It has one required attribute:

name: The name of the identity field or property.

Example:

@Entity
@Table(name="COMP")
public class Company {

	@Column(name="CID")
	@Id private long id;

	...
}
					

The same metadata for Company expressed in XML form:


<entity class="org.mag.pub.Company">
	<table name="COMP"/>
	<attributes>
		<id name="id">
			<column name="CID"/>
		</id>
		...
	</attributes>
</entity>

					

IdClass Annotation

The IdClass annotation is applied to an entity class or a mapped superclass to specify a composite primary key class that is MAPPED to multiple fields or properties of the entity.

The names of the fields or properties in the primary key class and the primary key fields or properties of the entity MUST correspond and their types MUST be the SAME.

The Id annotation must also be applied to the corresponding fields or properties of the entity.

@Target({TYPE}) @Retention(RUNTIME)
public @interface IdClass {
	Class value();
}
					

Example - Magazine.isbn field is mapped to a VARCHAR(9) column instead of a VARCHAR(255) column, which is the default for String fields.

@Entity
@IdClass(MagazineId.class)
@Table(name="MAG")
public class Magazine {

	@Column(length=9)
	@Id private String isbn;
	@Id private String title;

	...
}
					
public class MagazineId {

	// Each identity field in the Magazine class must have a
	// corresponding field in the identity class

	public String isbn;
	public String title;

	public boolean equals(Object other) {
		...
	}
     
	public int hashCode() {
		...
	}
}
					

The same metadata for Magazine expressed in XML form:


<entity class="Magazine">
	<id-class class="MagazineId"/>
	<table name="MAG"/>
	<attributes>
		<id name="isbn">
			<column length="9"/>
		</id>
		<id name="title"/>
		...  
	</attributes>
</entity>

					

GeneratedValue Annotation

The GeneratedValue annotation provides for the specification of generation strategies for the values of primary keys. The GeneratedValue annotation may be applied to a primary key property or field of an entity or mapped superclass in conjunction with the Id annotation.

The types of primary key generation are defined by the GenerationType enum:

public enum GenerationType { 
	TABLE, 
	SEQUENCE, 
	IDENTITY, 
	AUTO 
};
					

The TABLE generator type value indicates that the persistence provider must assign primary keys for the entity using an underlying database table to ensure uniqueness.

The SEQUENCE and IDENTITY values specify the use of a database sequence or identity column, respectively.

The AUTO value indicates that the persistence provider should pick an appropriate strategy for the particular database. The AUTO generation strategy may expect a database resource to exist, or it may attempt to create one. A vendor may provide documentation on how to create such resources in the event that it does not support schema generation or cannot create the schema resource at runtime.

EJB 3.0 specification does not define the exact behavior of these strategies.

@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface GeneratedValue {
	GenerationType strategy() default AUTO;
	String generator() default "";
}
					

Example 1:

@Entity
@Table(name="ART", uniqueConstraints=@UniqueConstraint(columnNames={"TITLE"}))
@SequenceGenerator(name="ArticleSeq", sequenceName="ART_SEQ")
public class Article {

	@Id
	@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="ArticleSeq")
	private long id;

	...
}
					

The same metadata for Article expressed in XML form:


<entity class="Article">
	<table name="ART">
		<unique-constraint>
			<column-name>TITLE</column-name>
		</unique-constraint>
	</table>
	<sequence-generator name="ArticleSeq" sequence-name="ART_SEQ"/>
	<attributes>
		<id name="id">
			<generated-value strategy="SEQUENCE" generator="ArticleSeq"/>
		</id>
		...
	</attributes>
</entity>

					

Example 2:

@Entity
@Table(name="AUTH")
public class Author {

	@Id
	@GeneratedValue(strategy=GenerationType.TABLE, generator="AuthorGen")
	@TableGenerator(name="AuthorGen", table="AUTH_GEN", pkColumnName="PK",
		valueColumnName="AID")
	@Column(name="AID", columnDefinition="INTEGER64")
	private long id;

	...
}
					

The same metadata for Author expressed in XML form:


<entity class="Author">
	<table name="AUTH"/>
	<attributes>
		<id name="id">
			<column name="AID" column-definition="INTEGER64"/>
			<generated-value strategy="TABLE" generator="AuthorGen"/>
			<table-generator name="AuthorGen" table="AUTH_GEN" 
				pk-column-name="PK" value-column-name="AID"/>
		</id>
		...
	</attributes>
</entity>

					

Version Annotation

The @Version annotation specifies the version field or property of an entity class that serves as its optimistic lock value. The version is used to ensure integrity when performing the merge operation and for optimistic concurrency control.

Only a SINGLE @Version property or field should be used per class; applications that use more than one @Version property or field will not be portable.

The Version property should be mapped to the primary table for the entity class; applications that map the Version property to a table other than the primary table will not be portable.

In general, fields or properties that are specified with the @Version annotation SHOULD NOT be updated by the application.

The following types are supported for version properties: int, Integer, short, Short, long, Long, Timestamp.

@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface Version {}
					

Example:

@Version
@Column(name="OPTLOCK")
protected int getVersionNum() { 
	return versionNum; 
}
					

Example:

@Entity
@IdClass(MagazineId.class)
public class Magazine {

	@Id private String isbn;
	@Id private String title;
	@Version private int version;

	...
}
					
@Entity
@Table(name="SUB", schema="CNTRCT")
public class Subscription {

	...
	@Column(name="VERS")
	@Version private int version;
	...
}
					
					

The same metadata declarations in XML:


<entity-mappings>

	<entity class="Magazine">
        <id-class="MagazineId"/>
        <attributes>
            <id name="isbn"/>
            <id name="title"/>
            <version name="version"/>
            ...
        </attributes>
	</entity>

	<entity class="Subscription">
		<table name="SUB" schema="CNTRCT"/>
		<attributes>
			...
			<version name="version">
				<column name="VERS"/>
			</version>
			...
		</attributes>
	</entity>

</entity-mappings>

					

Basic Annotation

The @Basic annotation is the simplest type of mapping to a database column. The @Basic annotation can be applied to a persistent property or instance variable of any of the following types: Java primitive types, wrappers of the primitive types, java.lang.String, java.math.BigInteger, java.math.BigDecimal, java.util.Date, java.util.Calendar, java.sql.Date, java.sql.Time, java.sql.Timestamp, byte[], Byte[], char[], Character[], enums, and any other type that implements Serializable. The use of the @Basic annotation is OPTIONAL for persistent fields and properties of these types.

@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface Basic {
	FetchType fetch() default EAGER;
	boolean optional() default true; // can be 'null' ?
}
					

The FetchType enum defines strategies for fetching data from the database:

public enum FetchType { 
	LAZY, 
	EAGER
};
					

The EAGER strategy is a requirement on the persistence provider runtime that data must be eagerly fetched. The LAZY strategy is a hint to the persistence provider runtime that data should be fetched lazily when it is first accessed. The implementation is permitted to eagerly fetch data for which the LAZY strategy hint has been specified. In particular, lazy fetching might ONLY be available for Basic mappings for which property-based access is used.

The optional element is a hint as to whether the value of the field or property may be null. It is disregarded for primitive types, which are considered non-optional.

Examples:

@Basic
protected String name;
					
@Basic(fetch=LAZY)
protected String getName() {
	return name;
}
					

Example:

@Entity
public class Subscription {

	@Id private long id;
	@Version private int version;

	private Date startDate; // defaults to @Basic
	private double payment; // defaults to @Basic

	...
}
					
@Entity(name="Lifetime")
public class LifetimeSubscription extends Subscription {

	@Basic(fetch=FetchType.LAZY)
	private boolean getEliteClub() { ... }
	public void setEliteClub(boolean elite) { ... }

	...
}
					

The same metadata declarations in XML:


<entity-mappings>
	<entity class="Subscription">
		<attributes>
			<id name="id"/>
			<basic name="payment"/>
			<basic name="startDate"/>
			<version name="version"/>
			...
		</attributes>
	</entity>

	<entity class="LifetimeSubscription" name="Lifetime" access="PROPERTY">
		<attributes>
			<basic name="eliteClub" fetch="LAZY"/>
			...
		</attributes>
	</entity>

</entity-mappings>

					

Lob Annotation

A @Lob annotation specifies that a persistent property or field should be persisted as a large object to a database-supported large object type. Portable applications should use the @Lob annotation when mapping to a database LOB type. The @Lob annotation may be used in conjunction with the @Basic annotation. A @Lob may be either a binary or character type. The LOB type is inferred from the type of the persistent field or property, and except for string and character-based types defaults to BLOB.

@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface Lob {
}
					

Adding the @Lob marker annotation to a basic field or property signals that the data is to be stored as a LOB (Large OBject). If the field holds string or character data, it will map to a CLOB (Character Large OBject) database column. If the field holds any other data type, it will be stored as binary data in a BLOB (Binary Large OBject) column. The implementation will serialize the Java value if needed.

The equivalent XML element is lob, which has no children or attributes.

Example 1:

@Lob @Basic(fetch=EAGER)
@Column(name="REPORT")
protected String report;
					

Example 2:

@Lob @Basic(fetch=LAZY)
@Column(name="EMP_PIC", columnDefinition="BLOB NOT NULL")
public byte[] getPic() {
	return pic;
}
					

Example 3:

@Entity
public class Contract {

	@Lob
	private String terms;

	...
}
					

The same metadata expressed in XML:


<entity-mappings>

	<entity class="Contract">
		<attributes>
			<basic name="terms">
				<lob/>
			</basic>
			...
		</attributes>
	</entity>

</entity-mappings>
					
					

Temporal Annotation

The @Temporal annotation MUST be specified for persistent fields or properties of type java.util.Date and java.util.Calendar. It may ONLY be specified for fields or properties of these types.

The @Temporal annotation may be used in conjunction with the @Basic annotation.

The TemporalType enum defines the mapping for these temporal types.

public enum TemporalType {
	DATE, // equivalent to java.sql.Date
	TIME, // equivalent to java.sql.Time
	TIMESTAMP // equivalent to java.sql.Timestamp
}
					

@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface Temporal {
	TemporalType value();
}
					

Example:

@Temporal(DATE)
protected java.util.Date endDate;
					

The @Temporal annotation determines how the implementation handles your basic java.util.Date and java.util.Calendar fields at the JDBC level. The @Temporal annotation's value is a constant from the TemporalType enum. Available values are:

If the @Temporal annotation is omitted, the implementation will treat the data as a TIMESTAMP.

The corresponding XML element is temporal, whose text value must be one of: TIME, DATE, or TIMESTAMP.

Example:

@Entity 
public class Employee {

	...
	@Temporal(DATE)    
	protected java.util.Date startDate;
	...

}
					

The same metadata expressed in XML:


<entity-mappings>
	<entity class="Employee">
		<attributes>
			...
			<basic name="startDate"/>
				<temporal>DATE</temporal>
			</basic>
			...
		</attributes>
	</entity>
</entity-mappings>
					
					

Enumerated Annotation

An @Enumerated annotation specifies that a persistent property or field should be persisted as a enumerated type. The @Enumerated annotation may be used in conjunction with the @Basic annotation.

An enum can be mapped as either a string or an integer. The EnumType enum defines the mapping for enumerated types.

public enum EnumType {
	ORDINAL,
	STRING
}
					

The corresponding XML element is enumerated. Its embedded text must be one of STRING or ORIDINAL.

If the enumerated type is not specified or the @Enumerated annotation is not used, the enumerated type is assumed to be ORDINAL:

@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface Enumerated {
	EnumType value() default ORDINAL;
}
					

Example:

public enum EmployeeStatus {FULL_TIME, PART_TIME, CONTRACT}
					
public enum SalaryRate {JUNIOR, SENIOR, MANAGER, EXECUTIVE}
					
@Entity public class Employee {
	...
	public EmployeeStatus getStatus() {...}

	@Enumerated(STRING)
	public SalaryRate getPayScale() {...}
	...
}
					

If the status property is mapped to a column of integer type, and the payscale property to a column of varchar type, an instance that has a status of PART_TIME and a pay rate of JUNIOR will be stored with STATUS set to 1 and PAYSCALE set to "JUNIOR".

@Entity
public class Employee {

	...
	@Enumerated (EnumType.STRING)
	public EmployeeType getEmployeeType() { 
		return employeeType; 
	}
	...
}
					
					

The same metadata expressed in XML:


<entity-mappings>
	<entity class="Employee" access="PROPERTY">
		<attributes>
			...
			<basic name="employeeType">
				<enumerated>STRING</enumerated>
			</basic>
			...
		</attributes>
	</entity>
</entity-mappings>
					
					

Transient Annotation

The @Transient annotation is used to annotate a property or field of an entity class, mapped superclass, or embeddable class. It specifies that the property or field is NOT persistent.

By default, a JPA persistence provider assumes that ALL the fields of an entity are persistent.

Use the @Transient annotation to specify a field or property of an entity that is not persistent, for example, a field or property that is used at run time but that is not part of the entity's state.

A JPA persistence provider will not persist (or create database schema) for a property or field annotated as @Transient.

This annotation can be used with @Entity, @MappedSuperclass, and @Embeddable.

This annotation has no attributes:

@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface Transient {}
					

The equivalent XML element is transient. It has a single attribute:

Example:

@Entity
public class Magazine {

	...
	@Transient 
	private byte[] data;
	...
}
					


<entity class="Magazine">
	<attributes>
		...	
		<transient name="data"/>
		...
	</attributes>
</entity>

					

Professional hosting     Belorussian informational portal         Free SCWCD 1.4 Study Guide     Free SCDJWS 1.4 Study Guide     SCDJWS 1.4 Quiz     Free IBM Certified Associate Developer Study Guide     IBM Test 000-287. Enterprise Application Development with IBM WebSphere Studio, V5.0 Study Guide     Free Mock Exam Engine