Jump to: navigation, search

Difference between revisions of "EclipseLink/Examples/MOXy/JPA/CompoundPrimaryKeys"

< EclipseLink‎ | Examples‎ | MOXy‎ | JPA
(Target Object)
 
(7 intermediate revisions by 2 users not shown)
Line 14: Line 14:
 
         @JoinColumn(name="E_COUNTRY", referencedColumnName = "COUNTRY")
 
         @JoinColumn(name="E_COUNTRY", referencedColumnName = "COUNTRY")
 
     })
 
     })
    @XmlIDREF
+
 
 
     private Employee contact;
 
     private Employee contact;
  
Line 27: Line 27:
 
     @Id
 
     @Id
 
     @Column(name="E_ID")
 
     @Column(name="E_ID")
    @XmlID
 
 
     private BigDecimal eId;
 
     private BigDecimal eId;
  
 
     @Id
 
     @Id
    @XmlID
 
 
     private String country;
 
     private String country;
  
 
     @OneToMany(mappedBy="contact")
 
     @OneToMany(mappedBy="contact")
    @XmlInverseReference(mappedBy="contact")
 
 
     private List<PhoneNumber> contactNumber;
 
     private List<PhoneNumber> contactNumber;
  
Line 64: Line 61:
 
=== Target Object ===
 
=== Target Object ===
  
As we require support beyond the JAXB spec, we will make use the EclipseLink extension @XmlCustomizer.  Also since the relationship is bidirectional, we will use the EclipseLink extension @XmlInverseReference.
+
As we require support beyond the JAXB spec, we will make use of the EclipseLink extension @XmlKey.  Also since the relationship is bidirectional, we will use the EclipseLink extension @XmlInverseReference.
  
 
<source lang="java">
 
<source lang="java">
 
@Entity
 
@Entity
 
@IdClass(EmployeeId.class)
 
@IdClass(EmployeeId.class)
@XmlCustomizer(EmployeeCustomizer.class)
 
 
public class Employee {
 
public class Employee {
  
Line 78: Line 74:
  
 
     @Id
 
     @Id
     @XmlID
+
     @XmlKey
 
     private String country;
 
     private String country;
  
Line 87: Line 83:
 
}
 
}
 
</source>
 
</source>
 
If we want the content of the EmployeeId class to be embedded in the complex type corresponding to the Employee class then we can change the XPath on the mapping for the "id" property to be self or ".".
 
 
Then we must specify the XPath to the XML nodes which represent the ID.
 
 
<source lang="java">
 
import org.eclipse.persistence.config.DescriptorCustomizer;
 
import org.eclipse.persistence.descriptors.ClassDescriptor;
 
import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping;
 
 
public class EmployeeCustomizer implements DescriptorCustomizer {
 
 
    public void customize(ClassDescriptor descriptor) throws Exception {
 
        XMLCompositeObjectMapping idMapping =
 
            (XMLCompositeObjectMapping) descriptor.getMappingForAttributeName("id");
 
        idMapping.setXPath(".");
 
 
        descriptor.addPrimaryKeyFieldName("eId/text()");
 
        descriptor.addPrimaryKeyFieldName("country/text()");
 
    }
 
 
}</source>
 
  
 
=== Source Object ===
 
=== Source Object ===
  
If the target object had a single ID then we would use @XmlIDREF.  Since the target object has a compound key, we will mark the field @XmlTransient, and use the EclipseLink extension @XmlCustomizer to set up the mapping.
+
If the target object had a single ID then we would use @XmlIDREF.  Since the target object has a compound key, we will use the EclipseLink extension @XmlJoinNodes to set up the mapping.
  
 
<source lang="java">
 
<source lang="java">
 
@Entity
 
@Entity
@XmlCustomizer(PhoneNumberCustomizer.class)
 
 
public class PhoneNumber {
 
public class PhoneNumber {
  
Line 124: Line 97:
 
         @JoinColumn(name="E_COUNTRY", referencedColumnName = "COUNTRY")
 
         @JoinColumn(name="E_COUNTRY", referencedColumnName = "COUNTRY")
 
     })
 
     })
     @XmlTransient
+
     @XmlJoinNodes( {
 +
        @XmlJoinNode(xmlPath="contact/id/text()", referencedXmlPath="id/text()"),
 +
        @XmlJoinNode(xmlPath="contact/country/text()", referencedXmlPath="country/text()")
 +
    })
 
     private Employee contact;
 
     private Employee contact;
 
}
 
</source>
 
 
An XMLObjectReferenceMapping will be created.  The mapping will include multiple key mappings.
 
 
<source lang="java">
 
import org.eclipse.persistence.config.DescriptorCustomizer;
 
import org.eclipse.persistence.descriptors.ClassDescriptor;
 
import org.eclipse.persistence.oxm.mappings.XMLObjectReferenceMapping;
 
 
public class PhoneNumberCustomizer implements DescriptorCustomizer {
 
 
    public void customize(ClassDescriptor descriptor) throws Exception {
 
        XMLObjectReferenceMapping contactMapping = new XMLObjectReferenceMapping();
 
        contactMapping.setAttributeName("contact");
 
        contactMapping.setReferenceClass(Employee.class);
 
        contactMapping.addSourceToTargetKeyFieldAssociation("contact/@eID", "eId/text()");
 
        contactMapping.addSourceToTargetKeyFieldAssociation("contact/@country", "country/text()");
 
        descriptor.addMapping(contactMapping);
 
    }
 
  
 
}
 
}
 
</source>
 
</source>

Latest revision as of 15:34, 16 March 2011

Overview

This example demonstrates how to derive an XML representation from a set of JPA entities using JAXB when a JPA entity has compound primary keys.

JPA Entities

@Entity
public class PhoneNumber {
 
    @ManyToOne
    @JoinColumns({
        @JoinColumn(name="E_ID", referencedColumnName = "E_ID"),
        @JoinColumn(name="E_COUNTRY", referencedColumnName = "COUNTRY")
    })
 
    private Employee contact;
 
}
@Entity
@IdClass(EmployeeId.class)
public class Employee {
 
    @Id
    @Column(name="E_ID")
    private BigDecimal eId;
 
    @Id
    private String country;
 
    @OneToMany(mappedBy="contact")
    private List<PhoneNumber> contactNumber;
 
}
public class EmployeeId {
 
    private BigDecimal eId;
    private String country;
 
}

JAXB Bindings

For this example the XML acessor type will be set to FIELD for all the model classes. This can be set as a package level JAXB annotation.

@XmlAccessorType(XmlAccessType.FIELD)
package com.example.model;
 
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;

Target Object

As we require support beyond the JAXB spec, we will make use of the EclipseLink extension @XmlKey. Also since the relationship is bidirectional, we will use the EclipseLink extension @XmlInverseReference.

@Entity
@IdClass(EmployeeId.class)
public class Employee {
 
    @Id
    @Column(name="E_ID")
    @XmlID
    private BigDecimal eId;
 
    @Id
    @XmlKey
    private String country;
 
    @OneToMany(mappedBy="contact")
    @XmlInverseReference(mappedBy="contact")
    private List<PhoneNumber> contactNumber;
 
}

Source Object

If the target object had a single ID then we would use @XmlIDREF. Since the target object has a compound key, we will use the EclipseLink extension @XmlJoinNodes to set up the mapping.

@Entity
public class PhoneNumber {
 
    @ManyToOne
    @JoinColumns({
        @JoinColumn(name="E_ID", referencedColumnName = "E_ID"),
        @JoinColumn(name="E_COUNTRY", referencedColumnName = "COUNTRY")
    })
    @XmlJoinNodes( {
        @XmlJoinNode(xmlPath="contact/id/text()", referencedXmlPath="id/text()"),
        @XmlJoinNode(xmlPath="contact/country/text()", referencedXmlPath="country/text()")
    })
    private Employee contact;
 
}