EJB3: Mapping Persistent Objects Example 3

by admin ~ October 21, 2008


Example 3: @EmbeddedId

This example shows the use of @javax.persistence.EmbeddedId to map a primary key class to the database and also the use of @javax.persistence.Transient annotation.


Client.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.titan.clients;
 
import com.titan.travelagent.TravelAgentRemote;
import com.titan.domain.*;
import javax.naming.InitialContext;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
 
public class Client {
	public static void main(String[] args) {
		try {
			Context jndiContext = getInitialContext();
			Object ref = jndiContext
					.lookup("TitanCruises/TravelAgentBean/remote");
			TravelAgentRemote dao = (TravelAgentRemote) ref;
 
			CustomerPK pk = new CustomerPK("Burke", 9999999);
			Customer cust = new Customer();
			cust.setPk(pk);
			cust.setFirstName("Bill");
 
			dao.createCustomer(cust);
 
			cust = dao.findCustomer("Burke", 9999999);
			System.out.println(cust.getFirstName());
			System.out.println(cust.getLastName());
			System.out.println(cust.getSsn());
		} catch (javax.naming.NamingException ne) {
			ne.printStackTrace();
		}
	}
 
	public static Context getInitialContext()
			throws javax.naming.NamingException {
		return new javax.naming.InitialContext();
	}
}

jndi.properties

1
2
3
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=127.0.0.1:1099

TravelAgentRemote.java

1
2
3
4
5
6
7
8
9
10
package com.titan.travelagent;
 
import javax.ejb.Remote;
import com.titan.domain.Customer;
 
@Remote
public interface TravelAgentRemote {
	public void createCustomer(Customer cust);
	public Customer findCustomer(String lastName, long ssn);
}

TravelAgentBean.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.titan.travelagent;
 
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
 
import com.titan.domain.Customer;
import com.titan.domain.CustomerPK;
 
@Stateless
public class TravelAgentBean implements TravelAgentRemote {
	@PersistenceContext(unitName = "titan")
	private EntityManager manager;
 
	public void createCustomer(Customer cust) {
		manager.persist(cust);
	}
 
	public Customer findCustomer(String lastName, long ssn) {
		CustomerPK pk = new CustomerPK(lastName, ssn);
		return manager.find(Customer.class, pk);
	}
}

Customer.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.titan.domain;
 
import javax.persistence.*;
 
@Entity
public class Customer implements java.io.Serializable {
   private String firstName;
   private CustomerPK pk;
 
   public String getFirstName() { return firstName; }
   public void setFirstName(String firstName) { this.firstName = firstName; }
 
   @EmbeddedId
   @AttributeOverrides({
       @AttributeOverride(name="lastName", column=@Column(name="LAST_NAME")),
       @AttributeOverride(name="ssn", column=@Column(name="SSN"))
   })
   public CustomerPK getPk() { return pk; }
   public void setPk(CustomerPK pk) { this.pk = pk; }
 
   @Transient
   public String getLastName() { return pk.getLastName(); }
 
   @Transient
   public long getSsn() { return pk.getSsn(); }
}

CustomerPK.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.titan.domain;
 
import javax.persistence.*;
 
@Embeddable
public class CustomerPK implements java.io.Serializable {
	private String lastName;
 
	private long ssn;
 
	public CustomerPK() {}
 
	public CustomerPK(String lastName, long ssn) {
		this.lastName = lastName;
		this.ssn = ssn;
	}
 
	@Column(name = "CUSTOMER_LAST_NAME")
	public String getLastName() {
		return this.lastName;
	}
 
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
 
	@Column(name = "CUSTOMER_SSN")
	public long getSsn() {
		return ssn;
	}
 
	public void setSsn(long ssn) {
		this.ssn = ssn;
	}
 
	public boolean equals(Object obj) {
		if (obj == this)
			return true;
		if (!(obj instanceof CustomerPK))
			return false;
		CustomerPK pk = (CustomerPK) obj;
		if (!lastName.equals(pk.lastName))
			return false;
		if (ssn != pk.ssn)
			return false;
		return true;
	}
 
	public int hashCode() {
		return lastName.hashCode() + (int) ssn;
	}
}

persistence.xml

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<persistence:persistence version="1.0" xmlns:persistence="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_1_0.xsd ">
  <persistence:persistence-unit name="titan" transaction-type="JTA">
    <persistence:description>Chapter: 6</persistence:description>
    <persistence:jta-data-source>java:/TitanDB</persistence:jta-data-source>
    <persistence:properties>
    	<persistence:property name="hibernate.hbm2ddl.auto" value="create"/>
    </persistence:properties>
  </persistence:persistence-unit>
</persistence:persistence>

application.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE application PUBLIC
	"-//Sun Microsystems, Inc.//DTD J2EE Application 1.3//EN"
	"http://java.sun.com/dtd/application_1_3.dtd">
<application>
	<display-name>TitanCruisesExample</display-name>
	<module>
		<ejb>TravelAgentBean.jar</ejb>
	</module>
	<module>
		<ejb>Customer.jar</ejb>
	</module>
</application>

Data Source file : postgres-TitanDB-ds.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
  <local-tx-datasource>
    <jndi-name>TitanDB</jndi-name>
	<use-java-context>true</use-java-context>
    <connection-url>jdbc:postgresql://127.0.0.1:5432/ejb3db</connection-url>
    <driver-class>org.postgresql.Driver</driver-class>
    <user-name>ranjan</user-name>
    <password>ranjan</password>
      <metadata>
         <type-mapping>PostgreSQL 8.0</type-mapping>
      </metadata>
  </local-tx-datasource>
</datasources>

Building the application: build.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?xml version="1.0" encoding="UTF-8"?>
<project name="Packaging Generator" default="_packaging_generation_">
	<target name="_packaging_generation_" depends="TitanCruisesExample" />
	<target name="TitanCruisesExample" description="TitanCruises.ear" depends="TravelAgentBean">
		<jar destfile="TitanCruises.ear">
			<zipfileset dir="conf" prefix="META-INF">
				<include name="application.xml" />
			</zipfileset>
			<zipfileset dir="/home/ranjan/workspaceEJB3/TitanCruises6_3">
				<include name="TravelAgentBean.jar" />
				<include name="Customer.jar" />
			</zipfileset>
		</jar>
	</target>
	<target name="TravelAgentBean" description="TravelAgentBean.jar" depends="Customer">
		<jar destfile="TravelAgentBean.jar">
			<zipfileset dir="/home/ranjan/workspaceEJB3/TitanCruises6_3/bin/com/titan/travelagent" prefix="com/titan/travelagent">
				<include name="TravelAgentRemote.class"/>
				<include name="TravelAgentBean.class"/>
			</zipfileset>	
		</jar>
	</target>
	<target name="Customer" description="Customer.jar">
		<jar destfile="Customer.jar">
			<zipfileset dir="conf" prefix="META-INF">
				<include name="persistence.xml" />
			</zipfileset>
			<zipfileset dir="/home/ranjan/workspaceEJB3/TitanCruises6_3/bin/com/titan/domain" prefix="com/titan/domain"/>
		</jar>
	</target>
</project>

Packaging Structure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
TitanCruises.ear
  |
  |--- META-INF
  |     |
  |     |--- application.xml
  |     |
  |     |--- MENIFEST.MF
  |
  |--- Customer.jar
  |     |
  |     |--- META-INF 
  |     |     |
  |     |     |--- persistence.xml
  |     |     |    
  |     |     |--- MENIFEST.MF
  |     |
  |     |--- com
  |           |
  |           |--- titan
  |                  |
  |                  |--- domain
  |                         |
  |                         |--- Customer.class
  |                         |--- CustomerPK.class
  |
  |--- TravelAgentBean.jar
  |     |
  |     |--- META-INF 
  |     |     |
  |     |     |--- MENIFEST.MF
  |     |
  |     |--- com
  |            |
  |            |--- titan
  |                  |
  |                  |--- travelagent
  |                         |
  |                         |
  |                         |--- TravelAgentRemote.class
  |                         |
  |                         |--- TravelAgentBean.class

Server Console after successful deployment of the application

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
12:25:44,729 INFO  [JBossASKernel] Created KernelDeployment for: Customer.jar
12:25:44,734 INFO  [JBossASKernel] installing bean: persistence.units:ear=TitanCruises.ear,unitName=titan
12:25:44,734 INFO  [JBossASKernel]   with dependencies:
12:25:44,734 INFO  [JBossASKernel]   and demands:
12:25:44,735 INFO  [JBossASKernel]      jboss.jca:name=TitanDB,service=DataSourceBinding
12:25:44,735 INFO  [JBossASKernel]   and supplies:
12:25:44,735 INFO  [JBossASKernel]      persistence.units:unitName=titan
12:25:44,735 INFO  [JBossASKernel] Added bean(persistence.units:ear=TitanCruises.ear,unitName=titan) to KernelDeployment of: Customer.jar
12:25:44,824 INFO  [STDOUT] ======> Creating interceptor metadata bridge
12:25:45,487 INFO  [JBossASKernel] Created KernelDeployment for: TravelAgentBean.jar
12:25:45,488 INFO  [JBossASKernel] installing bean: jboss.j2ee:ear=TitanCruises.ear,jar=TravelAgentBean.jar,name=TravelAgentBean,service=EJB3
12:25:45,488 INFO  [JBossASKernel]   with dependencies:
12:25:45,488 INFO  [JBossASKernel]   and demands:
12:25:45,488 INFO  [JBossASKernel]      persistence.units:ear=TitanCruises.ear,unitName=titan
12:25:45,488 INFO  [JBossASKernel]      jboss.ejb:service=EJBTimerService
12:25:45,488 INFO  [JBossASKernel]   and supplies:
12:25:45,488 INFO  [JBossASKernel]      jndi:TitanCruises/TravelAgentBean/remote
12:25:45,488 INFO  [JBossASKernel]      jndi:TravelAgentBean
12:25:45,488 INFO  [JBossASKernel]      Class:com.titan.travelagent.TravelAgentRemote
12:25:45,488 INFO  [JBossASKernel]      jndi:TitanCruises/TravelAgentBean/remote-com.titan.travelagent.TravelAgentRemote
12:25:45,488 INFO  [JBossASKernel] Added bean(jboss.j2ee:ear=TitanCruises.ear,jar=TravelAgentBean.jar,name=TravelAgentBean,service=EJB3) to KernelDeployment of: TravelAgentBean.jar
12:25:45,563 INFO  [PersistenceUnitDeployment] Starting persistence unit persistence.units:ear=TitanCruises.ear,unitName=titan
12:25:45,718 INFO  [Version] Hibernate Annotations 3.4.0.CR1
12:25:45,753 INFO  [Environment] Hibernate 3.3.0.CR1
12:25:45,763 INFO  [Environment] hibernate.properties not found
12:25:45,786 INFO  [Environment] Bytecode provider name : javassist
12:25:45,804 INFO  [Environment] using JDK 1.4 java.sql.Timestamp handling
12:25:46,101 INFO  [Version] Hibernate Commons Annotations 3.1.0.CR1
12:25:46,108 INFO  [Version] Hibernate EntityManager 3.4.0.CR1
12:25:46,220 WARN  [Ejb3Configuration] Persistence provider caller does not implement the EJB3 spec correctly. PersistenceUnitInfo.getNewTempClassLoader() is null.
12:25:46,356 INFO  [AnnotationBinder] Binding entity from annotated class: com.titan.domain.Customer
12:25:46,451 INFO  [EntityBinder] Bind entity com.titan.domain.Customer on table Customer
12:25:46,557 INFO  [Version] Hibernate Validator 3.1.0.CR1
12:25:46,892 INFO  [ConnectionProviderFactory] Initializing connection provider: org.hibernate.ejb.connection.InjectedDataSourceConnectionProvider
12:25:46,897 INFO  [InjectedDataSourceConnectionProvider] Using provided datasource
12:25:47,688 INFO  [SettingsFactory] RDBMS: PostgreSQL, version: 8.1.11
12:25:47,688 INFO  [SettingsFactory] JDBC driver: PostgreSQL Native Driver, version: PostgreSQL 8.1 JDBC3 with SSL (build 412)
12:25:47,745 INFO  [Dialect] Using dialect: org.hibernate.dialect.PostgreSQLDialect
12:25:47,761 INFO  [TransactionFactoryFactory] Transaction strategy: org.hibernate.ejb.transaction.JoinableCMTTransactionFactory
12:25:47,768 INFO  [TransactionManagerLookupFactory] instantiating TransactionManagerLookup: org.hibernate.transaction.JBossTransactionManagerLookup
12:25:47,775 INFO  [TransactionManagerLookupFactory] instantiated TransactionManagerLookup
12:25:47,775 INFO  [SettingsFactory] Automatic flush during beforeCompletion(): disabled
12:25:47,775 INFO  [SettingsFactory] Automatic session close at end of transaction: disabled
12:25:47,775 INFO  [SettingsFactory] JDBC batch size: 15
12:25:47,775 INFO  [SettingsFactory] JDBC batch updates for versioned data: disabled
12:25:47,777 INFO  [SettingsFactory] Scrollable result sets: enabled
12:25:47,778 INFO  [SettingsFactory] JDBC3 getGeneratedKeys(): disabled
12:25:47,778 INFO  [SettingsFactory] Connection release mode: auto
12:25:47,780 INFO  [SettingsFactory] Default batch fetch size: 1
12:25:47,780 INFO  [SettingsFactory] Generate SQL with comments: disabled
12:25:47,780 INFO  [SettingsFactory] Order SQL updates by primary key: disabled
12:25:47,780 INFO  [SettingsFactory] Order SQL inserts for batching: disabled
12:25:47,780 INFO  [SettingsFactory] Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory
12:25:47,789 INFO  [ASTQueryTranslatorFactory] Using ASTQueryTranslatorFactory
12:25:47,789 INFO  [SettingsFactory] Query language substitutions: {}
12:25:47,789 INFO  [SettingsFactory] JPA-QL strict compliance: enabled
12:25:47,789 INFO  [SettingsFactory] Second-level cache: enabled
12:25:47,789 INFO  [SettingsFactory] Query cache: disabled
12:25:47,811 INFO  [SettingsFactory] Cache region factory : org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge
12:25:47,811 INFO  [RegionFactoryCacheProviderBridge] Cache provider: org.hibernate.cache.HashtableCacheProvider
12:25:47,816 INFO  [SettingsFactory] Optimize cache for minimal puts: disabled
12:25:47,816 INFO  [SettingsFactory] Cache region prefix: TitanCruises_ear,titan
12:25:47,816 INFO  [SettingsFactory] Structured second-level cache entries: disabled
12:25:47,838 INFO  [SettingsFactory] Statistics: disabled
12:25:47,838 INFO  [SettingsFactory] Deleted entity synthetic identifier rollback: disabled
12:25:47,838 INFO  [SettingsFactory] Default entity-mode: pojo
12:25:47,838 INFO  [SettingsFactory] Named query checking : enabled
12:25:47,944 INFO  [SessionFactoryImpl] building session factory
12:25:48,351 INFO  [SessionFactoryObjectFactory] Factory name: persistence.units:ear=TitanCruises.ear,unitName=titan
12:25:48,355 INFO  [NamingHelper] JNDI InitialContext properties:{java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory, java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces}
12:25:48,360 INFO  [SessionFactoryObjectFactory] Bound factory to JNDI name: persistence.units:ear=TitanCruises.ear,unitName=titan
12:25:48,360 WARN  [SessionFactoryObjectFactory] InitialContext did not implement EventContext
12:25:48,385 INFO  [SchemaExport] Running hbm2ddl schema export
12:25:48,388 INFO  [SchemaExport] exporting generated schema to database
12:25:48,444 INFO  [SchemaExport] schema export complete
12:25:48,445 INFO  [NamingHelper] JNDI InitialContext properties:{java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory, java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces}
12:25:48,752 INFO  [EJBContainer] STARTED EJB: com.titan.travelagent.TravelAgentBean ejbName: TravelAgentBean

Client’s Console after running the Client.java

1
2
3
Bill
Burke
9999999

References:

“Java Persistence with Hibernate” by Christian Bauer and Gavin King.
“Enterprise JavaBeans 3.0″ by Bill Burke & Richard Monson-Haefel
JBoss Documentations for EJB 3

Share This Post

Leave a Reply