singe3
singe3

Reputation: 2105

ClassCastException when using nested mappedBy with Hibernate

I have the following classes (simplified) :

Location

Represents a geographic zone

@Entity
@Table(name = "location")
public class Location extends DomainObject {

    @OneToMany(mappedBy = "lastPositionHistoric.location")
    private Set<Thing> things = new LinkedHashSet<>(0);

    public Location() {
    }

    public Set<Thing> getThings(){
        return things;
    }

    public void setThings(Set<Thing> things){
        this.things = things;
    }

}

Thing

Represents a moving asset

@Entity
@Table(name = "thing")
public class Thing extends DomainObject {

    @OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.REFRESH})
    @JoinColumn(name = "last_position_thing_historic_id")
    private ThingHistoric lastPositionHistoric;

    public Thing() {
    }

    public ThingHistoric getLastPositionHistoric() {
        return lastPositionHistoric;
    }

    public void setLastPositionHistoric(ThingHistoric lastPositionHistoric) {
        this.lastPositionHistoric = lastPositionHistoric;
    }

}

ThingHistoric

Represents a GPS history of a Thing (I have removed unrelevant GPS properties for the problem)

@Entity
@Table(name = "thing_historic")
public class ThingHistoric extends DomainObject {

    @ManyToOne(cascade = {CascadeType.REFRESH, CascadeType.MERGE}, fetch = FetchType.EAGER)
    @JoinColumn(name = "thing_id", nullable = false)
    @NotNull
    private Thing thing;

    @ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.REFRESH})
    @JoinColumn(name = "location_id")
    private Location location;

    public ThingHistoric() {

    }

    public Thing getThing() {
        return thing;
    }

    public ThingHistoric setThing(Thing thing) {
        this.thing = thing;
        return this;
    }

    public Location getLocation() {
        return location;
    }

    public ThingHistoric setLocation(Location location) {
        this.location = location;
        return this;
    }
}

Explanation

Each Thing moves in the real world and can be at a given time inside a location or in no location.

When a Thing is inside a location, the lastPositionHistoric object has its location value equal to the Location the thing is inside.

The issue

When I added the things field inside the Location class, Hibernate started to complain with the following error :

Caused by: java.lang.ClassCastException: org.hibernate.mapping.ManyToOne cannot be cast to org.hibernate.mapping.Component
    at org.hibernate.mapping.PersistentClass.getRecursiveProperty(PersistentClass.java:465)
    at org.hibernate.mapping.PersistentClass.getRecursiveProperty(PersistentClass.java:421)
    at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:763)
    at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:724)
    at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:54)
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1621)
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1589)
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:278)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:848)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:876)
    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)
    ... 52 more

I don't understand why because the mapping seems correct to me. The list of things inside a location should be all the things that have lastPositionHisotric.location equals to the given location, right ?

Is it a bug or does my mapping is definitely wrong ?

Upvotes: 1

Views: 1905

Answers (1)

Neil Stockton
Neil Stockton

Reputation: 11531

"." (dot) notation in mappedBy is to refer to fields within embedded attributes (see JPA spec 11.1.4.1 for example). It is not for use with entities! And I don't see anything embedded in your mappings. So yes your mapping is definitely wrong

The dot (".") notation syntax must be used in the mappedBy element to indicate the relationship attribute within the embedded attribute. The value of each identifier used with the dot notation is the name of the respective embedded field or property.

Upvotes: 2

Related Questions