[{ALLOW view All}]
[{ALLOW edit Authenticated}]
!Mapping a many-to-many join table with extra column(s) using JPA
As of 23.02.2010

There seams to be only following two blogs in the web where this is described:

[boris.kirzner.info/blog/archives/2008/07/19|http://boris.kirzner.info/blog/archives/2008/07/19/hibernate-annotations-the-many-to-many-association-with-composite-key/]

[sieze.wordpress.com/2009/09/04|http://sieze.wordpress.com/2009/09/04/mapping-a-many-to-many-join-table-with-extra-column-using-jpa/]

But this solution does not work with EclipseLink, because obvioulsy 
EclipseLink does only allow simple Java types as primary key fields in the Embeddable class.

I am still a newby in JPA and had some difficulties to solve it,
so I tried to use some tools:

!Database Tools
Though owned by Oracle now, I still use MySql. My choice for
designing tables and relations\\
is [MySql Workbench|http://www.mysql.de/products/workbench/]. You can easily syncronize your model with the database (Menu > Database).\\
So I "Reverse Engineer..." my few database tables so far into a new model,
changed it and "Synchronize Model..." back to the database.\\
To validate what happens on the database
I used additionally [Squirrel|http://squirrel-sql.sourceforge.net/] for SQL.

!Eclipse
In Eclipse you can create a "JPA Project". This comes from a project 
called [Dali|http://www.eclipse.org/webtools/dali/] and is
part of the WTP (Web Tools Plattform). 

You can update Eclipse with following update source:\\
__http://download.eclipse.org/webtools/updates/__

Please make sure to use the latest Dali update, otherwise it will not create the additional properties in the join table (see below)!

When you created a JPA Project, you can find \\
__Context Menu > New > Entities From Table__

Then a wizard comes up, where you can select your table and adjust 
your mappings. Then Eclipse created all entity classes with
all annotations. Perfect stuff - now I don't need to rack my brain about this!\\
The nice thing is that you can test various models and see how this would look with JPA.

I tried also the model from the links above and this came out.\\
"color", "isAdmin" and "name" are the (stupid) additional properties\\
in ProductItem.

!Item
[{Java2HtmlPlugin 

package ebel;

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


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

	@Id
	@SequenceGenerator(name="ITEM_ITEMID_GENERATOR" )
	@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="ITEM_ITEMID_GENERATOR")
	@Column(name="item_id")
	private int itemId;

	private String name;

	//bi-directional many-to-one association to ProductItem
	@OneToMany(mappedBy="item")
	private List<ProductItem> productItems;

    public Item() {
    }

	public int getItemId() {
		return this.itemId;
	}

	public void setItemId(int itemId) {
		this.itemId = itemId;
	}

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

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

	public List<ProductItem> getProductItems() {
		return this.productItems;
	}

	public void setProductItems(List<ProductItem> productItems) {
		this.productItems = productItems;
	}
	
}
}]

!Product
[{Java2HtmlPlugin 

package ebel;

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


/**
 * The persistent class for the product database table.
 * 
 */
@Entity
@Table(name="product")
public class Product implements Serializable {
	private static final long serialVersionUID = 1L;
	private int productId;
	private String name;
	private List<ProductItem> productItems;

    public Product() {
    }


	@Id
	@SequenceGenerator(name="PRODUCT_PRODUCTID_GENERATOR" )
	@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="PRODUCT_PRODUCTID_GENERATOR")
	@Column(name="product_id")
	public int getProductId() {
		return this.productId;
	}

	public void setProductId(int productId) {
		this.productId = productId;
	}


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

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


	//bi-directional many-to-one association to ProductItem
	@OneToMany(mappedBy="product")
	public List<ProductItem> getProductItems() {
		return this.productItems;
	}

	public void setProductItems(List<ProductItem> productItems) {
		this.productItems = productItems;
	}
	
}
}]

!ProductItem
[{Java2HtmlPlugin 

package ebel;

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


/**
 * The persistent class for the product_item database table.
 * 
 */
@Entity
@Table(name="product_item")
public class ProductItem implements Serializable {
	private static final long serialVersionUID = 1L;
	private ProductItemPK id;
	private String color;
	private byte isAdmin;
	private String name;
	private Item item;
	private Product product;

    public ProductItem() {
    }


	@EmbeddedId
	public ProductItemPK getId() {
		return this.id;
	}

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

	public String getColor() {
		return this.color;
	}

	public void setColor(String color) {
		this.color = color;
	}


	public byte getIsAdmin() {
		return this.isAdmin;
	}

	public void setIsAdmin(byte isAdmin) {
		this.isAdmin = isAdmin;
	}


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

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


	//bi-directional many-to-one association to Item
    @ManyToOne
	@JoinColumn(name="item_id")
	public Item getItem() {
		return this.item;
	}

	public void setItem(Item item) {
		this.item = item;
	}
	

	//bi-directional many-to-one association to Product
    @ManyToOne
	@JoinColumn(name="product_id")
	public Product getProduct() {
		return this.product;
	}

	public void setProduct(Product product) {
		this.product = product;
	}
	
}
}]


!ProductItemPk
[{Java2HtmlPlugin 

package ebel;

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

/**
 * The primary key class for the product_item database table.
 * 
 */
@Embeddable
public class ProductItemPK implements Serializable {
	//default serial version id, required for serializable classes.
	private static final long serialVersionUID = 1L;
	private int itemId;
	private int productId;

    public ProductItemPK() {
    }

	@Column(name="item_id")
	public int getItemId() {
		return this.itemId;
	}
	public void setItemId(int itemId) {
		this.itemId = itemId;
	}

	@Column(name="product_id")
	public int getProductId() {
		return this.productId;
	}
	public void setProductId(int productId) {
		this.productId = productId;
	}

	public boolean equals(Object other) {
		if (this == other) {
			return true;
		}
		if (!(other instanceof ProductItemPK)) {
			return false;
		}
		ProductItemPK castOther = (ProductItemPK)other;
		return 
			(this.itemId == castOther.itemId)
			&& (this.productId == castOther.productId);

    }
    
	public int hashCode() {
		final int prime = 31;
		int hash = 17;
		hash = hash * prime + this.itemId;
		hash = hash * prime + this.productId;
		
		return hash;
    }
}
}]