persitsing an interface type with JPA

Consider this scenario. You have several classes implementing the same interface and you’d like to persist this interface type within an entity. The JPA is not able to handle that, but there is a workaround!

Lets make an example: A Plate (entity) has the attribute of type Fruit (interface). The apple, orange and the banana implement Fruit.

Now it would be great, if we could simply call plate.setFruit(apple) for example. The problem is, that JPA cannot handle multitype attributes (yet) . Use the following workareoud to make this functionality working:

The entities used for the exampe are:

interface Fruit
{
	String getColor();
}

@Entity 
class Apple implements Fruit {

	@Id
	integer id;
	String color;

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

@Entity 
class Banana implements Fruit {

	@Id
	integer id;
	String color;

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

@Entity 
class Orange implements Fruit {

	@Id
	integer id;
	String color;

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

Now the trick is to create a class with references to all of the Fruit interface implementing classes, which is later embedded in the Plate class:

class FruitInterfaceInstances {

	@OneToOne(fetch = FetchType.LAZY)
	Apple apple;

	@OneToOne(fetch = FetchType.LAZY)
	Banana banana;

	@OneToOne(fetch = FetchType.LAZY)
	Orange orange;

	//all respective getters/setters

	public Fruit getFruit() {

		if (apple != null) {
			return apple;
		} else if (banana != null) {
			return banana;
		} else if (orange != null) {
			return orange;
		} 
		throw new RuntimeException("invalid Fruit found!");
	}

	public void setFruit(Fruit Fruit) {

		if (Fruit instanceof Apple) {
			apple = (Apple) Fruit;
		} else if (Fruit instanceof Banana) {
			banana = (Banana) Fruit;
		} else if (Fruit instanceof Orange) {
			orange = (Orange) Fruit;
		} 

		throw new RuntimeException("invalid Fruit found!");
	}
}

This class is then embedded in the Plate entity:

class Plate{

	//furhter atributes
	Object someAttrbute;
	...

	@Embedded
	FruitInterfaceInstances fruitInstance;

	public Fruit getFruit() {
		return fruit != null ? fruitInstance.getFruit() : null;
	}

	public void setFruit(Fruit fruit) {
		if (this.fruitInstance== null)
			this.fruitInstance = new FruitInterfaceInstances();
		this.fruitInstance.setFruit(fruit);

	}
}

Please consider this mapping possibility as bad practice, slow and hard/expensive to query!

Leave a comment

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.