I am trying to work with JPA inheritance in a tree structure in Java.
I have a concrete entity (Product
) that has two concrete children (ProductA
, ProductB
)
Product has a Set<Products>
(parents) , meant to contain any combination of ProductA
and ProductB
Product has a Set<Products>
(children), meant to contain any combination of ProductA
and ProductB
ProductA
and ProductB
have the inherited children/parents, and some other properties.
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="product_type", discriminatorType = DiscriminatorType.STRING)
@Table(name = "PRODUCT")
class Product //CANNOT be an interface, abstract, or static
{
@Id
UUID id;
@Column(name = "product_type", insertable = false, updatable = false)
String productType;
@ManyToMany
@JsonManagedReference("product_children")
Set<Product> children;
@ManyToMany
@JsonBackReference("product_children")
Set<Product> parents;
}
@Entity
class ProductA extends Product
{
String prodAProperty;
}
@Entity
class ProductB extends Product
{
String prodBProperty;
}
This is all working fine in-code, and things are moving along well. They serialize, deserialize, and go into the DB without an issue, pivot tables are created, everything is saved correctly.
The trouble comes in when taking them back out. Let's say, we have the following:
rootProduct (ProductA)
parents: null
prodAProp: I am product A
children:
child01 (ProductA)
prodAProp: I am product A
parents:
rootProduct
children:
child 03 (ProductB)
prodBProp: I am product B
parents:
child01 (ProductA)
children: null
child02 (ProductB)
childBProp: I am productB
parents:
rootProduct
children: null
When using the following:
@Repository
public interface ProductRepository
extends JpaRepository<Product, UUID> {
}
And running the following:
ProductRepository repo;
Product theProduct = repo.findById("UUID goes here");
What I end up with:
rootProduct (ProductA)
parents: null
prodAProp: I am product A
children:
child01 (ProductA)
prodAProp: I am product A
parents:
rootProduct
children:
child 03 (Product)
parents:
child01 (ProductA)
children: null
child02 (ProductB)
childBProp: I am productB
parents:
rootProduct
children: null
The difference is subtle, but the child-of-child (or any deeper down the tree) is not being cast into the sub-class, instead it is being set as base class. It also cannot be down-cast:
(ProductB) child03
gives the error: Cannot convert Product into ProductB
I have tried various inheritance strategies, such as:
@MappedSuperclass
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@Inheritance(strategy = InheritanceType.JOINED)
with various discriminator types
Thank you for your time in advance!