Kris Rice
Kris Rice

Reputation: 1161

Hibernate 6 error using `manyToOne` and `oneToMany` mapping - Why is this happening?

I have two entity classes defined. One called EncryptedFile and the other called Chat.

I have stripped out the code down to the root problem.

Chat:

package database.objects

@Entity
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Table(name = "chats")
class Chat extends DatabaseEntity {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "chat_id")
  var id: Int = _

  @OneToMany(mappedBy = "chat", cascade = Array(CascadeType.ALL), fetch = FetchType.LAZY)
  var files: java.util.List[EncryptedFile] = new java.util.ArrayList[EncryptedFile]()

}

EncryptedFile:

package database.objects

@Entity
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Table(name = "files")
class EncryptedFile extends DatabaseEntity {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "file_id")
  var id: Int = _

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "chat_id", referencedColumnName = "chat_id")
  var chat: Chat = _

}

And finally, my Hibernate config:

val jasyptConfig = new JasyptConfig()
  .addAnnotatedClass(classOf[Server])
  .addAnnotatedClass(classOf[Chat])
  .addAnnotatedClass(classOf[User])
  .addAnnotatedClass(classOf[EncryptedFile])
  .setProperty(JAKARTA_JDBC_URL, "jdbc:mysql://localhost:3306/hydra_data")
  .setProperty(JAKARTA_JDBC_USER, sqlUser)
  .setProperty(JAKARTA_JDBC_PASSWORD, sqlPass)
  // use Agroal connection pool
  .setProperty("hibernate.agroal.maxSize", "20")
  .setProperty("hibernate.hbm2ddl.auto", "update")
  .setProperty("hibernate.cache.use_second_level_cache", true)
  .setProperty("hibernate.cache.use_query_cache", true)
  .setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.jcache.JCacheRegionFactory")
  .setProperty("hibernate.javax.cache.provider", "org.ehcache.jsr107.EhcacheCachingProvider")
  .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect")

Not sure if relevant, but I'm using a custom build of Jasypt that I have ported for Hibernate 6. The JasyptConfig is this:

public class JasyptConfig extends Configuration {

    public JasyptConfig() {
        // register custom converters
        addAnnotatedClass(EncryptedBigDecimalAsString.class);
        addAnnotatedClass(EncryptedBigDecimal.class);
        addAnnotatedClass(EncryptedBigIntegerAsString.class);
        addAnnotatedClass(EncryptedBigInteger.class);
        addAnnotatedClass(EncryptedBinary.class);
        addAnnotatedClass(EncryptedBooleanAsString.class);
        addAnnotatedClass(EncryptedByteAsString.class);
        addAnnotatedClass(EncryptedCalendarAsString.class);
        addAnnotatedClass(EncryptedDateAsString.class);
        addAnnotatedClass(EncryptedDoubleAsString.class);
        addAnnotatedClass(EncryptedDoubleAsString.class);
        addAnnotatedClass(EncryptedFloatAsString.class);
        addAnnotatedClass(EncryptedIntegerAsString.class);
        addAnnotatedClass(EncryptedLongAsString.class);
        addAnnotatedClass(EncryptedShortAsString.class);
        addAnnotatedClass(EncryptedString.class);
    }
...
}

When I come to run my application, I get the following error:

Exception in thread "main" org.hibernate.AnnotationException: Collection 'database.objects.Chat.files' is declared with a raw type and has an explicit 'targetEntity'
    at org.hibernate.boot.model.internal.CollectionBinder.getElementType(CollectionBinder.java:1591)
    at org.hibernate.boot.model.internal.CollectionBinder.noAssociationTable(CollectionBinder.java:1650)
    at org.hibernate.boot.model.internal.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:1613)
    at org.hibernate.boot.model.internal.CollectionBinder$1.secondPass(CollectionBinder.java:1604)
    at org.hibernate.boot.model.internal.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:45)
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1842)
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1800)
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:334)
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:129)
    at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:449)
    at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:101)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:949)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:999)
    at database.Database.init(Database.scala:87)
    at database.DatabaseUtil$.getInstance(Database.scala:34)
    at core.Main$.main(Main.scala:38)
    at core.Main.main(Main.scala)

I can solve the error by explicitly declaring targetEntity as described here: Hibernate: Collection is declared with a raw type and has an explicit 'targetEntity'

What I would like to know is why this happens? The error specifically suggests that the problem is the rawType and the targetEntity being set, yet it only goes away when both are set.

Is there a reason, or is it just poor wording in the exception?

Note:

I have reworded this question to understand better why this error is happening, as the other solution does not explain this.

I'm not the kind of person to just take a solution at face value and go "yep, it works" and move on. I need to understand why it is that it works, especially when the error is suggesting it shouldn't work.

Please re-open the question.

Upvotes: 1

Views: 25

Answers (0)

Related Questions