2

I'm using hibernate with generics to implement some feature. Here I have two entities Country and CountryTrans. CountryTrans represent different translations (different name) for Country. I'm using Spring Boot for this project.

I have a top level class that contains the Id.

@MappedSuperclass
public abstract class AbstractEntity {

    private Long id;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getId() {
        return id;
    }

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

Then MultiLingualObject generic class that contains the type of translation.

@MappedSuperclass
public abstract class MultiLigualObject<TYPE extends TranslationObject>
        extends AbstractEntity {

    protected List<TYPE> transInfo = new ArrayList<>();

    public abstract List<TYPE> getTransInfo();

    public void setTransInfo(List<TYPE> transInfo) {
        this.transInfo = transInfo;
    }
}

TranslationObject class is representing the entity translation.

@MappedSuperclass
public abstract class TranslationObject extends AbstractEntity {

    private String langCode;

    @Column(name = "lang_code")
    public String getLangCode() {
        return langCode;
    }

    public void setLangCode(String langCode) {
        this.langCode = langCode;
    }
}

Finally the Country class..

@Entity
@Table(name = "country")
public class Country extends MultiLigualObject<CountryTrans> {

    private String countryCode;
    private String alternateCode;

    @Column(name = "country_code", nullable = false, length = 2)
    public String getCountryCode() {
        return this.countryCode;
    }

    public void setCountryCode(String countryCode) {
        this.countryCode = countryCode;
    }

    @Column(name = "alternate_code", length = 3)
    public String getAlternateCode() {
        return this.alternateCode;
    }

    public void setAlternateCode(String alternateCode) {
        this.alternateCode = alternateCode;
    }

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "country")
    @Override
    public List<CountryTrans> getTransInfo() {
        return this.transInfo;
    }
}

And CountryTrans class.

@Entity
@Table(name = "country_trans")
public class CountryTrans extends TranslationObject {

    private String name;

    private Country country;

    @Column(nullable = false)
    public String getName() {
        return name;
    }

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

    @ManyToOne
    @JoinColumn(name = "country_id")
    public Country getCountry() {
        return country;
    }

    public void setCountry(Country country) {
        this.country = country;
    }
}

In order to test this I wrote a simple test case.

    @Test
    public void testCountry() throws Exception {
        Country country = countryRepository.findByCountryCode("AD");

    }

When I run this test case it gives following exception.

Caused by: javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.persistenceException(EntityManagerFactoryBuilderImpl.java:1249)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.access$600(EntityManagerFactoryBuilderImpl.java:120)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:860)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850)
    at org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl.withTccl(ClassLoaderServiceImpl.java:425)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:849)
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60)
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:343)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
    ... 43 more
Caused by: org.hibernate.MappingException: Could not determine type for: java.util.List, at table: country, for columns: [org.hibernate.mapping.Column(trans_info)]
    at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:349)
    at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:322)
    at org.hibernate.mapping.Property.isValid(Property.java:241)
    at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:496)
    at org.hibernate.mapping.RootClass.validate(RootClass.java:270)
    at org.hibernate.cfg.Configuration.validate(Configuration.java:1360)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1851)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:857)
    ... 51 more

Some basic search gives this is an issue with field level access vs property access. But in here I implemented this in a property level access. But not sure why it is failing. Any idea ?

Update

Adding CountryRepository

@Repository
public interface CountryRepository extends JpaRepository<Country, Long> {

    Country findByCountryCode(String countryCode);

}

Update - SQL Script

CREATE TABLE country (
  id bigint(20) NOT NULL AUTO_INCREMENT,
  alternate_code varchar(3) DEFAULT NULL,
  country_code varchar(2) NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE country_trans (
  id bigint(20) NOT NULL AUTO_INCREMENT,
  lang_code varchar(255) DEFAULT NULL,
  country_id bigint(20) DEFAULT NULL,
  name varchar(255) DEFAULT NULL,
  PRIMARY KEY (id),
  CONSTRAINT FK_COUNTRY_TRAN_ID FOREIGN KEY (country_id) REFERENCES country (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
2
  • You have a column in your Country table called trans_info? I believe it is trying to map that to your Country entity class but unable to figure out where it goes... Does that seem correct? Commented Jan 6, 2016 at 16:54
  • @DavidR no. I don't have any column called trans_info in country table. Please check the updated answer. I added the scripts. Commented Jan 6, 2016 at 17:10

1 Answer 1

1

Hibernate (or JPA) will use all properties of the class, unless you specifically mark them with @Transient. It is trying to figure out what column in the db transInfo maps to. The default is to look for a column in the Table with the same name as the parameter (transInfo) and is unable to find it. You can fix this by telling it to ignore the parameter.

Example:

@Transient
private List<CountryTrans> transInfo;
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.