Question

Suppose I have the following simple Customer/Order implementation:

A record of customers defined by a Customer class. Each customer can have multiple orders defined by an Order class.

Drawing on the explanation of Transparent Indirection from here and Container Policies from here my understanding of these concepts EclipseLink is as follows:

Transparent Indirection allows me to say

Customer customer = Customer.getCustomerById(1);
Set<Order> orders = customer.getOrders();

Two points to note are:

  1. Indirection allows lazy loading of attributes so a customer's orders are only fetched from the DB on line 2, not line 1.
  2. I can treat the orders of a customer as a Set (or Collection or List or Map) of objects of type Order.

The Container Policy tells to EclipseLink which actual class should be used for the Set and it should therefore implement Set in the example above.

That is my understanding of Transparent Indirection and Container Policies in EclipseLink.

I am seeing the following error when I try to access the database:

Exception [EclipseLink-148] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DescriptorException Exception Description: The container policy [CollectionContainerPolicy(class org.eclipse.persistence.indirection.IndirectSet)] is not compatible with transparent indirection. Mapping: org.eclipse.persistence.mappings.OneToManyMapping[orders] Descriptor: RelationalDescriptor(my.model.Customer --> [DatabaseTable(Customer)])

I'm sure I have an error in my code somewhere which I am trying to debug but I didn't specify the CollectionContainerPolicy mentioned in the error so I assume org.eclipse.persistence.indirection.IndirectSet is the default. But if I'm using the default policy then I'm not sure what the cause of this error may be or which policy I should be using.

For now, I'd just like to know if my understanding of Transparent Indirection and Container Policies as I mentioned above is correct.

If it is correct I'm probably missing something relatively small in my code (an invocation or configuration option etc.) but if I'm not understanding the concepts then clearly I need to do more research first.

Customer model

package my.model;

import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;


/**
 * The persistent class for the customer database table.
 *
 */
@Entity
@Table(name=Customer.TBL_NAME)
@NamedQueries({
    @NamedQuery(name=Customer.QRY_BY_NAME,query="Select object(a) from Customer a where " +
            "a.name=:" + Customer.PRM_NAME),
    @NamedQuery(name=Customer.QRY_ALL, query="select object(a) from Customer a")
})
public class Customer implements Serializable {
    private static final long serialVersionUID = 1L;

    // Table specific onstants
    public static final String TBL_NAME = "Customer";
    public static final String QRY_BY_NAME = TBL_NAME + ".byName";
    public static final String QRY_ALL = TBL_NAME + ".all";
    public static final String PRM_NAME = "name";

    private int id;
    private String name;
    private Set<Order> orders;

    public Customer() {
    }


    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    public int getId() {
        return this.id;
    }

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


    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }


    //bi-directional many-to-one association to Order
    @OneToMany(mappedBy="customer")
    public Set<Order> getOrders() {
        return this.orders;
    }

    public void setOrders(Set<Order> orders) {
        this.orders = orders;
    }

}

Order model

package my.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;


/**
 * The persistent class for the order database table.
 *
 */
@Entity
@Table(name=Order.TBL_NAME)
public class Order implements Serializable {
    private static final long serialVersionUID = 1L;

    // Table constants
    public static final String TBL_NAME = "Order";

    private int id;
    private Customer customer;

    public Order() {
    }


    @Id
    public int getId() {
        return this.id;
    }

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


    //bi-directional many-to-one association to Customer
    @ManyToOne
    public Customer getCustomer() {
        return this.customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }
}
Was it helpful?

Solution

Your understanding is correct, but shouldn't be needed as this isn't something you need to configure when using JPA. EclipseLink will determine the collection policy and implementation to use based on the type of the property and the lazy/eager setting, and it seems to be doing so correctly. The exception is thrown in error, probably due to classloader issues so that the classloader used for init isn't the one used to validate against, but I don't know how that could happen. You will need to look at the environment this is running in as the exception itself is just a symptom

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top