August 19, 2010

Creating a RESTful Web Service - Part 2/5 (Annotations)


Java Persistence Architecture (JPA) is the Java EE standard for mapping POJOs to a relational database. In this example we will use JPA to interact with our database data we set up in part 1.


JPA Entities

The following JPA entities can be created by hand, or the Eclipse Dali project can be used (http://www.eclipse.org/webtools/dali/). Dali has a useful feature where JPA entities can be generated from database tables.

Customer Entity

We want the customer, address, and phone number data to be treated as a unit.  When a customer is added/removed we want the corresponding address and phone numbers to be added/removed.  To accomplish this we will specify CascadeType.ALL on the address and phoneNumber relationships.

In addition to the database mappings, I've added a named query to the Customer entity.  This query will give us all customers from a particular city.

package org.example;

import java.io.Serializable;
import javax.persistence.*;
import java.util.Set;

@Entity
@NamedQuery(name = "findCustomersByCity", 
            query = "SELECT c " +
                    "FROM Customer c " +
                    "WHERE c.address.city = :city")
public class Customer implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    private long id;

    @Column(name="FIRST_NAME")
    private String firstName;

    @Column(name="LAST_NAME")
    private String lastName;

    @OneToOne(mappedBy="customer", cascade={CascadeType.ALL})
    private Address address;

    @OneToMany(mappedBy="customer", cascade={CascadeType.ALL})
    private Set<phonenumber> phoneNumbers;

    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return this.lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Address getAddress() {
        return this.address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }
    
    public Set<PhoneNumber> getPhoneNumbers() {
        return this.phoneNumbers;
    }

    public void setPhoneNumbers(Set<PhoneNumber> phoneNumbers) {
        this.phoneNumbers = phoneNumbers;
    }
    
}

Address Entity

package org.example;

import java.io.Serializable;
import javax.persistence.*;

@Entity
public class Address implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    private long id;

    private String city;

    private String street;

    @OneToOne
    @PrimaryKeyJoinColumn
    private Customer customer;

    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getCity() {
        return this.city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getStreet() {
        return this.street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

}

PhoneNumber Entity

package org.example;

import java.io.Serializable;
import javax.persistence.*;

@Entity
@Table(name="PHONE_NUMBER")
public class PhoneNumber implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id 
    private long id;
    
    private String num;
    
    private String type;

    @ManyToOne
    @JoinColumn(name="ID_CUSTOMER")
    private Customer customer;

    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getNum() {
        return this.num;
    }

    public void setNum(String num) {
        this.num = num;
    }

    public String getType() {
        return this.type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Customer getCustomer() {
        return this.customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }
    
}

META-INF/persistence.xml

For this example I will use the EclipseLink JPA implementation.  If you are using another JPA implementation the configuration willl vary slightly.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
    xmlns="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 http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
    <persistence-unit name="CustomerService" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>CustomerService</jta-data-source>
        <class>org.example.Customer</class>
        <class>org.example.Address</class>
        <class>org.example.PhoneNumber</class>
        <properties>
            <property name="eclipselink.target-database" value="Oracle" />
            <property name="eclipselink.logging.level" value="FINEST" />
            <property name="eclipselink.logging.level.ejb_or_metadata" value="WARNING" />
            <property name="eclipselink.logging.timestamp" value="false"/>
            <property name="eclipselink.logging.thread" value="false"/>
            <property name="eclipselink.logging.session" value="false"/>
            <property name="eclipselink.logging.exceptions" value="false"/> 
            <property name="eclipselink.target-server" value="SunAS9"/> 
        </properties>
    </persistence-unit>
</persistence>

Packaging/Deployment

Ultimately we will package all the META-INF/pesistence.xml and our JPA entities in a JAR file.   We will hold off actually creating the JAR until we apply the XML representation using JAXB in part 3.

Next Steps

In the next post we will examine how to use the Java Architecture for XML Binding (JAXB) to apply an XML representation on the JPA entities (POJOs).


Further Reading

If you enjoyed this post you may also be interested in:


2 comments:

  1. hi Blaise,
    could you please show me an example how to marshal Composite PK inline?
    For example:
    public class FreeUnit implements Serializable {
    private static final long serialVersionUID = 1L;
    @EmbeddedId
    protected FreeUnitPK freeUnitPK;
    }

    I would like to have the fields of PK inline in XML of FreeUnit.

    regards,
    Tinku

    ReplyDelete
  2. Hi Tinku,

    Below is a link on how to handle composite primary keys with EclipseLink JAXB (MOXy):

    - Mapping Composite Key Relationships

    The above strategy will also work when using @EmbeddedId.

    -Blaise

    ReplyDelete

Note: Only a member of this blog may post a comment.