I am having a problem with Hibernate inheritance. I have been trying to find out what is causing the Exception. The Exception I get is
Caused by: java.lang.ClassCastException: org.hibernate.mapping.SingleTableSubclass cannot be cast to org.hibernate.mapping.RootClass.
The full Exception can be found at the end of this post.
public interface PersistentObjectKey {
public String getPromotionId();
public Integer getVersion();
}
// Promo
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "promotion")
public abstract class Promo implements PersistentObjectKey{
@Id
@Column(name="promotionId")
@GeneratedValue(strategy=GenerationType.AUTO)
protected String promotionId;
@OneToMany(mappedBy="promo", cascade = CascadeType.ALL, fetch=FetchType.LAZY)
@NotNull
protected Set<Product> product = new HashSet<Product>();
@Embedded
@NotNull
protected Attribute attribute;
@Embedded
@NotNull
protected Duration duration;
@Embedded
@AttributeOverrides({
@AttributeOverride(name="imageTitle", column=@Column(nullable=true)),
@AttributeOverride(name="imageFileName", column=@Column(nullable=true)),
@AttributeOverride(name="imageUrl", column=@Column(nullable=true))
})
private Image promoImage;
@Embedded
@Column(nullable=true)
protected TermsAndConditions termsAndConditions;
protected Promo(){
}
public static class PromoBuilder{
private Set<Product> product;
private Attribute attributes;
private Duration duration;
private TermsAndConditions termsAndConditions;
private Image promoImage;
public PromoBuilder(Set<Product> product, Attribute attributes, Duration duration){
this.product = product;
this.attributes = attributes;
this.duration = duration;
}
public PromoBuilder termsAndConditions(TermsAndConditions termsAndConditions){
this.termsAndConditions = termsAndConditions;
return this;
}
public PromoBuilder promoImage(Image promoImage){
this.promoImage = promoImage;
return this;
}
public Promo build(){
return null;
}
}
protected Promo(PromoBuilder promoBuilder){
this.product = promoBuilder.product;
this.attribute = promoBuilder.attributes;
this.duration = promoBuilder.duration;
this.termsAndConditions = promoBuilder.termsAndConditions;
this.promoImage = promoBuilder.promoImage;
}
protected PromoBuilder newBuilder(){
return new PromoBuilder(getProduct(), getAttribute(), getDuration());
}
protected PromoBuilder decorate(PromoBuilder builder){
return builder.termsAndConditions(getTermsAndConditions());
}
public PromoBuilder toBuilder(){
return decorate(newBuilder());
}
public String getPromotionId() {
return promotionId;
}
public Integer getVersion() {
return 10;
}
public Set<Product> getProduct() {
return product;
}
public void setProduct(Set<Product> product) {
this.product = product;
}
public Attribute getAttribute() {
return attribute;
}
public void setAttribute(Attribute attribute) {
this.attribute = attribute;
}
public Duration getDuration() {
return duration;
}
public void setDuration(Duration duration) {
this.duration = duration;
}
public Image getPromoImage() {
return promoImage;
}
public void setPromoImage(Image promoImage) {
this.promoImage = promoImage;
}
public TermsAndConditions getTermsAndConditions() {
return termsAndConditions;
}
public void setTermsAndConditions(TermsAndConditions termsAndConditions) {
this.termsAndConditions = termsAndConditions;
}
public boolean equals(Object o){
if(this == o){
return true;
}
if(o == null || !(o instanceof PersistentObjectKey)){
return false;
}
PersistentObjectKey other = (PersistentObjectKey)o;
// if the id is missing, return false
if(this.promotionId == null){
return false;
}
return this.promotionId.equals(other.getPromotionId());
}
public int hashCode(){
if(promotionId != null){
return promotionId.hashCode();
}else{
return super.hashCode();
}
}
public String toString() {
return this.getClass().getName()
+ "[id=" + promotionId + "]";
}
}
// Coupon
@Entity
@Table(name = "coupon")
@PrimaryKeyJoinColumn(name="couponId", referencedColumnName="promotionId")
public class Coupon extends Promo{
@Column(name="onlineCode", nullable=true)
@Pattern(regexp="[a-zA-Z0-9]+", message="LATER")
private String onlineCode = "";
@Column(name="offlineCode",nullable=true)
private String offlineCode = "";
protected Coupon(){}
private Coupon(CouponBuilder couponBuilder){
super(couponBuilder);
this.onlineCode= couponBuilder.onlineCode;
this.offlineCode = couponBuilder.offlineCode;
}
public class CouponBuilder extends Promo.PromoBuilder{
private String onlineCode = "";
private String offlineCode = "";
public CouponBuilder(Set<Product> product, Attribute attributes, Duration duration){
super(product, attributes, duration);
}
public CouponBuilder onlineCode(String onlineCode){
this.onlineCode = onlineCode;
return this;
}
public CouponBuilder offlineCode(String offlineCode){
this.offlineCode = offlineCode;
return this;
}
@Override
public CouponBuilder termsAndConditions(TermsAndConditions termsAndConditions){
return (CouponBuilder) super.termsAndConditions(termsAndConditions);
}
@Override
public CouponBuilder promoImage(Image promoImage){
return (CouponBuilder)super.promoImage(promoImage);
}
public Coupon build(){
switch(attribute.getPromoUsage()){
case ONLINE:
if(this.onlineCode.equalsIgnoreCase("")){
throw new IllegalArgumentException("You must enter online coupon code");
}
case OFFLINE:
if(this.offlineCode.equalsIgnoreCase("")){
throw new IllegalArgumentException("You must enter instore coupon code");
}
case ONLINE_AND_OFFLINE:
if(this.onlineCode.equalsIgnoreCase("") || this.offlineCode.equalsIgnoreCase("")){
throw new IllegalArgumentException("You must enter online and instore code");
}
}
return new Coupon(this);
}
}
// GETTERS AND SETTERS
public String getOnlineCode() {
return onlineCode;
}
public void setOnlineCode(String onlineCode) throws IllegalArgumentException{
if(onlineCode.equals("")){
throw new IllegalArgumentException("code cannot be empty");
}
this.onlineCode = onlineCode;
}
public String getOfflineCode() {
return offlineCode;
}
public void setOfflineCode(String offlineCode) throws IllegalArgumentException{
if(offlineCode.equals("")){
throw new IllegalArgumentException("code cannot be empty");
}
this.offlineCode = offlineCode;
}
}
// Product
@Entity
@Table(name="product")
public class Product {
@Id
@Column(name="productId")
private String productId = IdGenerator.createId();
@Column(name="productName", nullable=false)
@NotNull
private String name;
@OneToOne(cascade=CascadeType.ALL)
@JoinColumn(name="categoryId", nullable=false)
@NotNull
private Category category;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="promotionId", nullable=true)
@JsonBackReference
private Promo promo;
@Column(name="price", nullable=true)
private double price;
@Column(name="discountPercentage", nullable=false)
private int discountPercentage;
@ElementCollection
@CollectionTable(
name="image",
joinColumns = @JoinColumn(name="productId"))
private Set<Image> images = new HashSet<Image>();
public Product(){
}
private Product(ProductBuilder productBuilder) {
this.name = productBuilder.name;
this.category = productBuilder.category;
this.price = productBuilder.price;
this.discountPercentage = productBuilder.discountPercentage;
this.images = productBuilder.images;
}
public static class ProductBuilder{
private String name;
private Category category;
private double price = 0f;
private int discountPercentage = 0;
@OneToMany
private Set<Image> images = new HashSet<>();
public ProductBuilder(String name, Category category){
this.name = name;
this.category = category;
}
public ProductBuilder price(double price){
this.price = price;
return this;
}
public ProductBuilder discountPercentage(int discountPercentage){
this.discountPercentage = discountPercentage;
return this;
}
public ProductBuilder images(Set<Image> images){
this.images = images;
return this;
}
public Product build(){
return new Product(this);
}
}
// GETTERS AND SETTERS
public String getProductId() {
return productId;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public double getDiscountPercentage() {
return discountPercentage;
}
public void setDiscountPercentage(int discountPercentage) throws IllegalArgumentException{
if(discountPercentage <= 0){
throw new IllegalArgumentException("Discount percentage cannot be zero or negative");
}
this.discountPercentage = discountPercentage;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
public Set<Image> getImages() {
return images;
}
public void setImages(Set<Image> images) {
this.images = images;
}
@Override
public boolean equals(Object o){
if(this == o){
return true;
}
if(o == null || !(getClass() == o.getClass())){
return false;
}
Product other = new Product();
return Objects.equals(name, other.name) && Objects.equals(category,other.category) &&
Objects.equals(price, other.price) && Objects.equals(discountPercentage, other.discountPercentage) &&
Objects.equals(images, other.images);
}
public int hashCode(){
if(productId != null){
return productId.hashCode();
}else{
return super.hashCode();
}
}
}
// Attributes
@Embeddable
public class Attribute {
@Column(name="shortDescription", nullable=false)
@NotNull
protected String shortDescription;
@Column(name="detailDescription", nullable=true)
protected String detailDescription;
@Column(name="promoUsage", nullable=false)
@NotNull
@Enumerated(EnumType.STRING)
private PromoUsage promoUsage;
@Column(name="destinationUrl", nullable=true)
protected String destinationUrl;
public Attribute(){}
private Attribute(AttributesBuilder attributesBuilder){
this.shortDescription = attributesBuilder.shortDescription;
this.destinationUrl = attributesBuilder.destinationUrl;
this.promoUsage = attributesBuilder.promoUsageType;
this.detailDescription = attributesBuilder.detailDescription;
}
public static class AttributesBuilder{
private String shortDescription;
private String detailDescription;
private PromoUsage promoUsageType;
private String destinationUrl;
//Builder constructor
public AttributesBuilder(String shortDescription, PromoUsage promoUsageType){
this.shortDescription = shortDescription;
this.promoUsageType = promoUsageType;
}
public AttributesBuilder detailDescription(String detailDescription){
this.detailDescription = detailDescription;
return this;
}
public AttributesBuilder destinationUrl(String destinationurl){
this.destinationUrl = destinationurl;
return this;
}
public Attribute build()throws IllegalArgumentException{
if(this.promoUsageType == PromoUsage.ONLINE || this.promoUsageType == PromoUsage.ONLINE_AND_OFFLINE){
if(destinationUrl.equals("")){
throw new IllegalArgumentException("destination Url must not be empty");
}
}
if(this.shortDescription == null || this.shortDescription.equals("")){
throw new IllegalArgumentException("Please provide a short description for the promo");
}
return new Attribute(this);
}
}
public String getShortDescription() {
return shortDescription;
}
public void setShortDescription(String shortDescription) {
this.shortDescription = shortDescription;
}
public String getDetailDescription() {
return detailDescription;
}
public void setDetailDescription(String detailDescription) {
this.detailDescription = detailDescription;
}
public PromoUsage getPromoUsage() {
return promoUsage;
}
public void setPromoUsage(PromoUsage promoUsage) {
this.promoUsage = promoUsage;
}
public String getDestinationUrl() {
return destinationUrl;
}
public void setDestinationUrl(String destinationUrl) {
this.destinationUrl = destinationUrl;
}
public boolean equals(Object o){
return false;
}
public int hashCode(){
return 1;
}
}
// Duration
@Embeddable
public class Duration {
@Column(name="startDate", nullable=false)
@NotNull
@JsonFormat(pattern = "dd-MM-YYYY")
private Date startDate;
@Column(name="expirationDate", nullable=false)
@NotNull
@JsonFormat(pattern = "dd-MM-YYYY")
private Date expirationDate;
public Duration(){
}
public Duration(Date startDate, Date expirationDate){
this.startDate = startDate;
this.expirationDate = expirationDate;
}
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public Date getExpirationDate() {
return expirationDate;
}
public void setExpirationDate(Date expirationDate) {
this.expirationDate = expirationDate;
}
public boolean equals(Object o){
return false;
}
public int hashCode(){
return 1;
}
}
// Category
@Entity
@Table(name="category")
public class Category {
@Id
@Column(name="categoryId")
private String categoryId = IdGenerator.createId();
@Column(nullable=false, unique=true)
@Size(min=2, max=60, message="LATER")
private String categoryName;
public Category() {
}
public String getCategoryId() {
return categoryId;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
}
// Image
@Entity
public class Image extends MediaFile{
public Image(){}
public Image(String title, String fileName, String url) {
super(title, fileName, url);
}
}
public enum PromoUsage {
ONLINE, OFFLINE, ONLINE_AND_OFFLINE;
}
// The exception: (because of character limit on Stack Overflow I can only post part of it)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [com/grabone/utility/GrabOneConfiguration.class]: Invocation of init method failed; nested exception is java.lang.ClassCastException: org.hibernate.mapping.SingleTableSubclass cannot be cast to org.hibernate.mapping.RootClass
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
... 28 common frames omitted
Caused by: java.lang.ClassCastException: org.hibernate.mapping.SingleTableSubclass cannot be cast to org.hibernate.mapping.RootClass
at org.hibernate.cfg.annotations.PropertyBinder.bind(PropertyBinder.java:208) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.cfg.annotations.PropertyBinder.makePropertyValueAndBind(PropertyBinder.java:199) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:2225) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.cfg.AnnotationBinder.fillComponent(AnnotationBinder.java:2635) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.cfg.AnnotationBinder.fillComponent(AnnotationBinder.java:2522) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.cfg.AnnotationBinder.bindComponent(AnnotationBinder.java:2470) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:2185) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:911) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:738) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.boot.model.source.internal.annotations.AnnotationMetadataSourceProcessorImpl.processEntityHierarchies(AnnotationMetadataSourceProcessorImpl.java:245) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess$1.processEntityHierarchies(MetadataBuildingProcess.java:222) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:265) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:847) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:874) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60) ~[spring-orm-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:353) ~[spring-orm-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:370) ~[spring-orm-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:359) ~[spring-orm-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624) ~[spring-beans-4.3.7.RELEASE.jar:4.3.7.RELEASE]
... 38 common frames omitted