April 17, 2012

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

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.  In the previous post we specified the mapping metadata as annotations.  This post will demonstrate how to specify the same metadata as XML.  One advantage of specifying the metadata as XML is that the domain objects will not have a dependency on the JPA APIs.  This is useful if we want to use the same domain classes on the client side.



META-INF/orm.xml 

JPA provides a standard XML representation of the metadata.  The metadata below is the same as was specified via annotations in the previous post.  If you name the XML metadata file orm.xml and place it in the META-INF directory then the JPA implementation will automatically apply it.  If you choose an alternate name or location then you will need to configure this in the persistence.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings 
    version="2.0" 
    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 http://java.sun.com/xml/ns/persistence/orm_2_0.xsd">
    <entity class="org.example.Customer">
         <named-query name="findCustomersByCity">
            <query>SELECT c FROM Customer c WHERE c.address.city = :city</query>
         </named-query>
         <attributes>
            <id name="id"/>
            <basic name="firstName">
                <column name="FIRST_NAME"/>
            </basic>
            <basic name="lastName">
                <column name="LAST_NAME"/>
            </basic>
            <one-to-many name="phoneNumbers" mapped-by="customer">
                <cascade>
                    <cascade-all/>
                </cascade>
            </one-to-many>
            <one-to-one name="address" mapped-by="customer">
                <cascade>
                    <cascade-all/>
                </cascade>
            </one-to-one>
         </attributes>
    </entity>
    <entity class="org.example.Address">
        <attributes>
            <id name="id"/>
            <one-to-one name="customer">
                <primary-key-join-column/>
            </one-to-one>
        </attributes>
    </entity>
    <entity class="org.example.PhoneNumber">
        <table name="PHONE_NUMBER"/>
        <attributes>
            <id name="id"/>
            <many-to-one name="customer">
                <join-column name="ID_CUSTOMER"/>
            </many-to-one>
        </attributes>
    </entity>
</entity-mappings>

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>
        <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> 

JPA Entities 

Below is our domain model.  Since the metadata is provided via an XML document we do not require any annotations.

Customer

package org.example;
 
import java.io.Serializable; 
import java.util.Set;
 
public class Customer implements Serializable {
    private static final long serialVersionUID = 1L;
 
    private long id;
 
    private String firstName;
 
    private String lastName;
 
    private Address address;
 
    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 

package org.example;
 
import java.io.Serializable;
 
public class Address implements Serializable {
    private static final long serialVersionUID = 1L;
 
    private long id;
 
    private String city;
 
    private String street;
 
    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 

package org.example;
 
import java.io.Serializable;
 
public class PhoneNumber implements Serializable {
    private static final long serialVersionUID = 1L;
 
    private long id;     
    private String num;
    private String type;
 
    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;
    }

}

Packaging/Deployment

Ultimately we will package the META-INF/pesistence.xml, META-INF/orm.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. This is very informative and it's going to help web designers like me. I work as part time designer at SEO companies and this would definitely help me advance with my craft.

    ReplyDelete