vladmihalcea / hypersistence-optimizer

Hypersistence Optimizer allows you to get the most out of JPA and Hibernate. By scanning your application configuration and mappings, Hypersistence Optimizer can tell you what changes you need to do to speed up your data access layer.
https://vladmihalcea.com/hypersistence-optimizer/
Apache License 2.0
306 stars 43 forks source link

Hibernate62MappingScanner throws ClassCastException when using OneToOne mapping referencing an IDENTITY column #210

Closed fubai closed 1 year ago

fubai commented 1 year ago

When I upgrade our project to SpringBoot 3.1.0,I got an exception here:

2023-06-17 21:27:35.950 19976 [main] ERROR Hypersistence Optimizer - The [org.hibernate.tuple.IdentifierProperty] encountered a problem when calling the [getIdentifierGenerator] method.
java.lang.ClassCastException: class org.hibernate.id.IdentityGenerator cannot be cast to class org.hibernate.id.IdentifierGenerator (org.hibernate.id.IdentityGenerator and org.hibernate.id.IdentifierGenerator are in unnamed module of loader 'app')
    at org.hibernate.tuple.IdentifierProperty.getIdentifierGenerator(IdentifierProperty.java:81)
    at org.hibernate.persister.entity.AbstractEntityPersister.getIdentifierGenerator(AbstractEntityPersister.java:3829)
    at io.hypersistence.optimizer.hibernate.scanner.Hibernate62MappingScanner.getToOneAssociationType(Hibernate62MappingScanner.java:746)
    at io.hypersistence.optimizer.hibernate.scanner.Hibernate62MappingScanner$9.execute(Hibernate62MappingScanner.java:512)
    at io.hypersistence.optimizer.core.action.ActionExecutor.execute(ActionExecutor.java:68)
    at io.hypersistence.optimizer.hibernate.scanner.Hibernate62MappingScanner.scanEntityBasedAssociationAttribute(Hibernate62MappingScanner.java:471)
    at io.hypersistence.optimizer.hibernate.scanner.Hibernate62MappingScanner$7.execute(Hibernate62MappingScanner.java:370)
    at io.hypersistence.optimizer.core.action.ActionExecutor.execute(ActionExecutor.java:68)
    at io.hypersistence.optimizer.hibernate.scanner.Hibernate62MappingScanner.scanEntityAttribute(Hibernate62MappingScanner.java:366)
    at io.hypersistence.optimizer.hibernate.scanner.Hibernate62MappingScanner$1.lambda$execute$0(Hibernate62MappingScanner.java:116)
    at java.base/java.util.concurrent.ConcurrentHashMap$ValueSpliterator.forEachRemaining(ConcurrentHashMap.java:3612)
    at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762)
    at io.hypersistence.optimizer.hibernate.scanner.Hibernate62MappingScanner$1.execute(Hibernate62MappingScanner.java:106)
    at io.hypersistence.optimizer.core.action.ActionExecutor.execute(ActionExecutor.java:68)
    at io.hypersistence.optimizer.hibernate.scanner.Hibernate62MappingScanner.scan(Hibernate62MappingScanner.java:103)
    at io.hypersistence.optimizer.HypersistenceOptimizer.init(HypersistenceOptimizer.java:91)
    at io.hypersistence.optimizer.HypersistenceOptimizer.<init>(HypersistenceOptimizer.java:68)
    at com.braincocloud.common.core.config.HypersistenceConfiguration.hypersistenceOptimizer(HypersistenceConfiguration.kt:29)
    at com.braincocloud.common.core.config.HypersistenceConfiguration$$SpringCGLIB$$0.CGLIB$hypersistenceOptimizer$0(<generated>)
    at com.braincocloud.common.core.config.HypersistenceConfiguration$$SpringCGLIB$$2.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331)
    at com.braincocloud.common.core.config.HypersistenceConfiguration$$SpringCGLIB$$0.hypersistenceOptimizer(<generated>)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:139)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:655)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:647)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1332)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1162)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:560)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:941)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:608)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:733)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:435)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1305)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1294)

The hibernate version is: 6.2.2.Final, and hypersistence-optimizer is 2.7.0-jakarta

The code below cause the exception, if i remove the mapping, the exception disappear.

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "lecturer_id", referencedColumnName = "id")
    var lecturer: CourseLecturer? = null
vladmihalcea commented 1 year ago

@fubai Thanks for opening the issue, but it's not possible to figure out the problem without the mapping for those two entities: CourseLecturer and the other one where this lecturer is defined.

Especially the @Id property in this entity where lecturer is defined is important.

fubai commented 1 year ago

Here is those two entities:

import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.FetchType
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
import jakarta.persistence.JoinColumn
import jakarta.persistence.OneToOne
import jakarta.persistence.Table

@Entity
@Table(name = "tb_course")
class Course(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long? = null,

    @Column(name = "name")
    var name: String? = null,

) {

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "lecturer_id", referencedColumnName = "id")
    var lecturer: CourseLecturer? = null
}
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
import jakarta.persistence.Table

@Entity
@Table(name = "tb_course_lecturer")
class CourseLecturer(

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long? = null,

    @Column(name = "name")
    var name: String? = null,
)

We are using kotlin, and we use the all-open plugin to make all entities open:

                <configuration>
                    <jvmTarget>${java.version}</jvmTarget>
                    <args>
                        <arg>-Xjsr305=strict</arg>
                    </args>
                    <compilerPlugins>
                        <plugin>all-open</plugin>
                        <plugin>spring</plugin>
                        <plugin>no-arg</plugin>
                        <plugin>jpa</plugin>
                    </compilerPlugins>
                    <pluginOptions>
                        <option>all-open:annotation=jakarta.persistence.Entity</option>
                        <option>all-open:annotation=jakarta.persistence.MappedSuperclass</option>
                        <option>all-open:annotation=jakarta.persistence.Embeddable</option>
                        <option>no-arg:annotation=com.fz.annotations.NoArg</option>
                    </pluginOptions>
                </configuration>
vladmihalcea commented 1 year ago

Thanks. I'll try to see if I can replicate it.

vladmihalcea commented 1 year ago

@fubai I managed to replicate the issue.

vladmihalcea commented 1 year ago

Fixed. I will release the 2.7.1 version next week.

vladmihalcea commented 1 year ago

@fubai The 2.7.1 version is released now, so you can try it out.

fubai commented 1 year ago

Great!