chapter 7. the annotations...
TRANSCRIPT
1 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Chapter 7. The Annotations Alternative
Hibernate Annotations
2 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Hibernate Annotations …
Java Annotation
– is a way to add information about a piece of code (typically a class, field, or method)
• to help tools understand how the code is being used, or
• to enable automation that saves you work.
– Sun built full general-purpose annotation support right into Java 5.
Hibernate adopted Java 5's native annotations.– Convergent evolution went even farther than that.
– The power of using annotations to configure mapping for classes has such appeal that Hibernate's own tags strongly influenced the EJB 3 specification.
– They also were impressed by how useful Hibernate-style persistence could be outside a full-blown Java Enterprise Edition (EE) environment,
– so they defined the Java Persistence API (often referred to as the JPA) as a stand-alone component which can be used for persistence in a normal Java Standard Edition (SE) environment.
• javax.persistence.* from hibernate-entitymanager.jar
– As the specifications firmed up, Hibernate adapted to support them directly.
@Entity public class Artist {
@Id private Integer id; …
}
3 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Hibernate Annotations …
Example 7-1. Obtaining the Hibernate Annotations
build.gradle :…
dependencies {compile 'org.hibernate:hibernate-core:4.+'compile 'org.slf4j:slf4j-api:1.+'
runtime 'ch.qos.logback:logback-classic:1.+'runtime 'org.javassist:javassist:3.+'
runtime 'org.hsqldb:hsqldb:2.+'
testCompile 'junit:junit:4.+'testCompile 'org.hamcrest:hamcrest-library:1.+'
}…
4 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Hibernate Annotations
Example 7-4. Configuring Hibernate to work with annotations
hibernate.cfg.xml :
…<!-- Don't echo all executed SQL to stdout --><property name="show_sql">false</property>
<!-- disable batching so HSQLDB will propagate errors correctly. --><property name="jdbc.batch_size">0</property>
<!-- List all the annotated classes we're using --><mapping class="com.oreilly.hh.data.Album"/><mapping class="com.oreilly.hh.data.AlbumTrack"/><mapping class="com.oreilly.hh.data.Artist"/><mapping class="com.oreilly.hh.data.Track"/>
</session-factory></hibernate-configuration>…
5 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Entity
Entity Annotations
Person
id : Long
name : String
salary : int
birthdate : Date
import java.util.Date;import javax.persistence.*;
@Entity@Table(name=“PERSON”)class Person {
@Id@GeneratedValue@Column(name=“person_id”)Long id;
String name;int salary;
@Temporal(TemporalType.DATE)@Column(name="birth_date")private Date birthDate;
}
create table PERSON (person_id bigint not null primary key,name varchar,salary int,birth_date date
)
6 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Association and Mapping
Bidirectional Associations
7 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Association and Mapping
Bidirectional Many-to-One/One-to-Many Associations
Person
id
Address
id*
persons1
address
PersonAddress
@Entity@Table(name=“PERSON”)class Person {
@Id@GeneratedValueLong id;
@ManyToOne@JoinColumn(name=“address_id”)Address address;
}
@Entity@Table(name=“ADDRESS”)class Address {
@Id@GeneratedValueLong id;
@OneToMany(mappedBy=“address”)Set<Person> persons;
}
create table Address (id bigint not null primary key
)
create table Person (id bigint not null primary key,address_id bigint not null
)
8 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Association and Mapping
Bidirectional Many-to-Many Associations
Person
id
Address
id*
persons*
addresses
PersonAddress
create table PersonAddress ( person_id bigint not null,address_id bigint not null,primary key (person_id, address_id)
)
@Entityclass Person {
@Id@GeneratedValueLong id;
@ManyToMany@JoinTable(name=“PersonAddress”,joinColumns={@JoinColumn(name=“person_id”)},
inverseJoinColumns={@JoinColumn(name=“address_id”)})Set<Address> addresses;
}
@Entityclass Address {
@Id@GeneratedValueLong id;
@ManyToMany(mappedBy=“addresses”)Set<Person> persons;
}
create table Address (id bigint not null primary key
)
create table Person (id bigint not null primary key,
)
9 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Association and Mapping
Bidirectional One-to-One Associations on a Foreign Key
Person
id
Address
id1
person1
address
PersonAddress
@Entityclass Person {
@Id@GeneratedValueLong id;
@OneToOne@JoinColumn(name=“address_id”)Address address;
}
@Entityclass Address {
@Id@GeneratedValueLong id;
@OneToOne(mappedBy=“address”)Person person;
}
create table Address (id bigint not null primary key
)
create table Person (id bigint not null primary key,address_id bigint not null
)
10 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Association and Mapping
Bidirectional One-to-One Associations on a Primary Key
Person
id
Address
id1
person1
address
PersonAddress
create table Address (id bigint not null primary key
)
create table Person (id bigint not null primary key,
)
@Entityclass Person {
@Id@GeneratedValueLong id;
@OneToOne(mappedBy=“person”)Address address;
}
@Entityclass Address {
@Id@GeneratedValue(generator=“gen”)@GenericGenerator(name=“gen”, strategy=“foreign”,
parameters=@Parameter(name=“property”, value=“person”))Long id;
@OneToOne@PrimaryKeyJoinColumnPerson person;
}
11 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Association and Mapping
Unidirectional Associations
12 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Association and Mapping
Unidirectional Many-to-One Associations
create table Address (id bigint not null primary key
)
create table Person (id bigint not null primary key,address_id bigint not null
)
Person
id
Address
id*
persons1
address
PersonAddress
@Entity@Table(name=“PERSON”)class Person {
@Id@GeneratedValueLong id;
@ManyToOne@JoinColumn(name = “address_id”)Address address;
}
@Entity@Table(name=“ADDRESS”)class Address {
@Id@GeneratedValueLong id;
}
13 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Association and Mapping
Unidirectional One-to-Many Associations (unusual case)
Person
id
Address
id1
person*
addresses
PersonAddress
create table Address (id bigint not null primary key,person_id bigint not null
)
create table Person (id bigint not null primary key
)
@Entityclass Person {
@Id@GeneratedValueLong id;
@OneToMany@JoinColumn(name = “person_id”)Set<Address> addresses;
}
@Entityclass Address {
@Id@GeneratedValueLong id;
}
14 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Association and Mapping
Unidirectional Many-to-Many Associations
Person
id
Address
id*
persons*
addresses
PersonAddress
create table PersonAddress ( person_id bigint not null,address_id bigint not null,primary key (person_id, address_id)
)
create table Address (id bigint not null primary key
)
create table Person (id bigint not null primary key,
)
@Entityclass Person {
@Id@GeneratedValueLong id;
@ManyToMany@JoinTable(name=“PersonAddress”,joinColumns={@JoinColumn(name=“person_id”)},
inverseJoinColumns={@JoinColumn(name=“address_id”)})Set<Address> addresses;
}
@Entityclass Address {
@Id@GeneratedValueLong id;
}
15 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Association and Mapping
Unidirectional One-to-One Associations on a Foreign Key
Person
id
Address
id1
person1
address
PersonAddress
create table Address (id bigint not null primary key
)
create table Person (id bigint not null primary key,address_id bigint not null
)
@Entityclass Person {
@Id@GeneratedValueLong id;
@OneToOne@JoinColumn(name = “address_id”)Address address;
}
@Entityclass Address {
@Id@GeneratedValueLong id;
}
16 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Association and Mapping
Unidirectional One-to-One Associations on a Primary Key
Person
id
Address
id1
person1
address
PersonAddress
create table Address (id bigint not null primary key
)
create table Person (id bigint not null primary key,
)
@Entityclass Person {
@Id@GeneratedValueLong id;
@OneToOne(cascade = CascadeType.ALL)@PrimaryKeyJoinColumnAddress address;
}
@Entityclass Address {
@IdLong id;
}
17 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Association and Mapping Exercise
hibernate-369-mkyong-win
– 02-stock-quickstart-annotation
– 04-stock-onetomany-annotation
– 06-stock-manytomany-annotation
– 09-stock-onetoone-annotation
18 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Physical UML Class Diagram
19 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Physical UML Class Diagram with Annotations
20 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Annotating Model Objects …
Example 7-5. Annotating the Artist class
package com.oreilly.hh.data;
import java.util.*;import javax.persistence.*;import org.hibernate.annotations.Index;
@Entity @Table(name="ARTIST)@NamedQueries({
@NamedQuery(name="com.oreilly.hh.artistByName", query="from Artist as artist where upper(artist.name) = upper(:name)")
})public class Artist {
@Id @Column(name="ARTIST_ID")@GeneratedValue(strategy=GenerationType.AUTO)private Integer id;
@Column(name="NAME",nullable=false,unique=true) @Index(name="ARTIST_NAME",columnNames={"NAME"}) private String name;
…
JPA 2.1:javax.persistence.Index
Hibernate ORM:org.hibernate.annotations.Index(hbm2ddl.auto : 'create','create-drop')
21 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Annotating Model Objects …
Example 7-5. Annotating the Artist class
…
@ManyToMany@JoinTable(name="TRACK_ARTISTS",
joinColumns={@JoinColumn(name="TRACK_ID")},inverseJoinColumns={@JoinColumn(name="ARTIST_ID")})
@ManyToMany(mappedBy = "artists") // yckprivate Set<Track> tracks;
@ManyToOne@JoinColumn(name="actualArtist")private Artist actualArtist;
public Artist() {}
public Artist(String name, Set<Track> tracks, Artist actualArtist) {this.name = name;this.tracks = tracks;this.actualArtist = actualArtist;
}…// getters and setters// toString()
}
22 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Annotating Model Objects …
Example 7-6. Annotating the Track class
package com.oreilly.hh.data;
import java.sql.Time;import java.util.*;import javax.persistence.*;import org.hibernate.annotations.CollectionOfElements;import org.hibernate.annotations.Index;
@Entity@Table(name="TRACK")@NamedQueries({
@NamedQuery(name="com.oreilly.hh.tracksNoLongerThan",query="from Track as track where track.playTime <= :length")
})public class Track {
@Id@Column(name="TRACK_ID")@GeneratedValue(strategy=GenerationType.AUTO)private Integer id;
@Column(name="TITLE",nullable=false)@Index(name="TRACK_TITLE",columnNames={"TITLE"})private String title;
…
23 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Annotating Model Objects …
Example 7-6. Annotating the Track class
…
@Column(nullable=false)private String filePath;
@Temporal(TemporalType.TIME) private Date playTime;
@ManyToMany@JoinTable(name="TRACK_ARTISTS",
joinColumns={@JoinColumn(name="ARTIST_ID")},inverseJoinColumns={@JoinColumn(name="TRACK_ID")})
private Set<Artist> artists;
@Temporal(TemporalType.DATE) private Date added;
@CollectionOfElements@JoinTable(name="TRACK_COMMENTS",
joinColumns = @JoinColumn(name="TRACK_ID"))@Column(name="COMMENT")private Set<String> comments;
@Enumerated(EnumType.STRING) private SourceMedia sourceMedia;
…
@javax.persistence.EnumeratedEnumType.ORDINAL (default value) EnumType.STRING
SourceMediaType.java
24 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Annotating Model Objects …
Example 7-6. Annotating the Track class
… @Embedded @AttributeOverrides({
@AttributeOverride(name = "left", column = @Column(name = "VOL_LEFT")),@AttributeOverride(name = "right", column = @Column(name = "VOL_RIGHT"))
})StereoVolume volume;
public Track() {}
public Track(String title, String filePath) {this.title = title;this.filePath = filePath;
}
public Track(String title, String filePath, Time playTime,Set<Artist> artists, Date added, StereoVolume volume,SourceMedia sourceMedia, Set<String> comments) {
this.title = title;this.filePath = filePath;…
}
// getters, setters and toString()
}
@Embeddablepublic class StereoVolume implements Serializablle { … }
StereoVolumeType.java
25 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Annotating Model Objects …
Example 7-7. Annotating the Album class
package com.oreilly.hh.data;
import java.util.*;import javax.persistence.*;import org.hibernate.annotations.CollectionOfElements; import org.hibernate.annotations.Index; import org.hibernate.annotations.IndexColumn;
@Entity@Table(name="ALBUM")public class Album {
@Id@Column(name="ALBUM_ID")@GeneratedValue(strategy=GenerationType.AUTO)private Integer id;
@Column(name="TITLE",nullable=false)@Index(name="ALBUM_TITLE",columnNames={"TITLE"})private String title;
@Column(nullable=false)private Integer numDiscs;
…
26 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Annotating Model Objects …
Example 7-7. Annotating the Album class
… @ManyToMany(cascade=CascadeType.ALL)@JoinTable(name="ALBUM_ARTISTS", joinColumns=@JoinColumn(name="ARTIST_ID"),
inverseJoinColumns=@JoinColumn(name="ALBUM_ID"))private Set<Artist> artists;
@CollectionOfElements @ElementCollection // JPA 2.0@JoinTable(name="ALBUM_COMMENTS", joinColumns = @JoinColumn(name="ALBUM_ID"))@Column(name="COMMENT")private Set<String> comments;
@Temporal(TemporalType.DATE)private Date added;
@CollectionOfElements @ElementCollection@IndexColumn(name="LIST_POS") @JoinTable(name="ALBUM_TRACKS",
joinColumns = @JoinColumn(name="ALBUM_ID"))private List<AlbumTrack> tracks;
public Album() {}public Album(String title, int numDiscs, Set<Artist> artists,
Set<String> comments, List<AlbumTrack> tracks, Date added) {this.title = title;…
}// getters, setters and toString()
}
27 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Annotating Model Objects …
Example 7-8. Annotating the AlbumTrack class
package com.oreilly.hh.data;
import java.io.Serializable;import javax.persistence.*;
@Embeddable public class AlbumTrack {
@ManyToOne(cascade=CascadeType.ALL) @JoinColumn(name="TRACK_ID", nullable=false)private Track track;
private Integer disc; private Integer positionOnDisc;
public AlbumTrack() {}
public AlbumTrack(Track track, Integer disc, Integer positionOnDisc) {this.track = track;this.disc = disc;this.positionOnDisc = positionOnDisc;
}// getters, setters and toString()
}
28 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Annotating Model Objects …
Example 7-10. Tweaks to the test classes needed to work with annotations
Same Changes
– QueryTest.java
– QueryTest2.java
– AlbumTest.java
CreateTest.java :
package com.oreilly.hh;
import org.hibernate.*;import org.hibernate.cfg.AnnotationConfiguration;import org.hibernate.cfg.Configuration;
...
public static void main(String args[]) throws Exception {// Create a configuration based on the annotations in our model classes.Configuration config = new AnnotationConfiguration();Configuration config = new Configuration(); // >= Hibernate 3.6config.configure();
...
29 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Annotating Model Objects
Example 7-11. Running AlbumTest using annotations
gradle atest:
atest :[java] com.oreilly.hh.data.Album@27d19d [
title='Counterfeit e.p.‘tracks='[com.oreilly.hh.data.AlbumTrack@bf4c80 [track='com.oreilly.hh.data.Track@2e3919 [title='Compulsion' volume='Volume[left=100, right=100]' sourceMedia='CD' ]' ],com.oreilly.hh.data.AlbumTrack@3778cf [track='com.oreilly.hh.data.Track@f4d063 [title='In a Manner of Speaking' volume='Volume[left=100, right=100]' sourceMedia='CD' ]' ],com.oreilly.hh.data.AlbumTrack@dc696e [track='com.oreilly.hh.data.Track@a5dac0 [title='Smile in the Crowd' volume='Volume[left=100, right=100]' sourceMedia='CD' ]' ],com.oreilly.hh.data.AlbumTrack@8dbef1 [track='com.oreilly.hh.data.Track@c4b579 [title='Gone' volume='Volume[left=100, right=100]' sourceMedia='CD' ]' ],com.oreilly.hh.data.AlbumTrack@f2f761 [track='com.oreilly.hh.data.Track@8cd64 [title='Never Turn Your Back on Mother Earth' volume='Volume[left=100, right=100]' sourceMedia='CD' ]' ],com.oreilly.hh.data.AlbumTrack@4f1541 [track='com.oreilly.hh.data.Track@c042ba [title='Motherless Child' volume='Volume[left=100, right=100]' sourceMedia='CD' ]' ]]‘]
30 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
An Alternate Approach …
Annotations are clearly a viable way of mapping model classes
– though we lost the ability to cascade creation of Tracks during the creation of an Album
There's another approach we could have taken in the schema which would maintain that automatic cascade.
– Mapping AlbumTrack as a full-blown entity gives us places to put cascade annotations that Hibernate will honor all the way from the Album definition to the embedded Track reference.
– It also gives us a few new complications to think about, but some of those can be seen as opportunities.
• AlbumTrack as an entity will need an ID.
• AlbumTrack as an entity will need an album property.
31 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
An Alternate Approach …
Example 7-12. Annotating the AlbumTrack class as an entity
package com.oreilly.hh.data;
import java.io.Serializable;import javax.persistence.*;
@Entity @Table(name="ALBUM_TRACKS")public class AlbumTrack {
@Id @GeneratedValue(strategy=GenerationType.AUTO)private Integer id;
@ManyToOne@JoinColumn(name="ALBUM_ID", insertable=false, updatable=false, nullable=false)private Album album;
@ManyToOne(cascade=CascadeType.ALL) @JoinColumn(name="TRACK_ID", nullable=false)private Track track;
// getters, setters}
32 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
An Alternate Approach
Example 7-13. The AlbumTracks entity mapping in Album.java
...@OneToMany(cascade=CascadeType.ALL)@IndexColumn(name="LIST_POS")@JoinColumn(name="ALBUM_ID", nullable=false)private List<AlbumTrack> tracks;
...
33 / 33Prof. Youngchan KIM, Dept of Computer Engineering, Hanbat National University
Database Programming
Materials for Further Study
Hibernate Home
– http://www.hibernate.org/
Hibernate Manual
– Hibernate Getting Started Guide 3.6
• http://docs.jboss.org/hibernate/core/3.6/quickstart/en-US/html/
– Hibernate Reference Documentation 3.6
• http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/
• http://docs.jboss.org/hibernate/core/3.6/reference/en-US/pdf/hibernate_reference.pdf
– Hibernate Reference Documentation 4.3 and 5.0
Hibernate Tutorial
– http://www.mkyong.com/tutorials/hibernate-tutorials/