Reputation: 930
I want to use Spring-boot-data
to persist OptaPlanner's domain object in DB, and according to the guide, I've done the hibernate mapping task and everything looks fine except for Score object.
The score object can be persisted in DB as BLOB column if without any special configuration, but if based on the guide (17.2.1.1. JPA and Hibernate: Persisting a Score), it always throws an exception as follows:
java.lang.AbstractMethodError: org.optaplanner.persistence.jpa.impl.score.buildin.hardmediumsoft.HardMediumSoftScoreHibernateType.replace(Ljava/lang/Object;Ljava/lang/Object;Lorg/hibernate/engine/spi/SharedSessionContractImplementor;Ljava/lang/Object;)Ljava/lang/Object;
at org.hibernate.type.CompositeCustomType.replace(CompositeCustomType.java:178)
at org.hibernate.type.AbstractType.replace(AbstractType.java:144)
at org.hibernate.type.TypeHelper.replace(TypeHelper.java:194)
at org.hibernate.event.internal.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:431)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:233)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:301)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:170)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:69)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:884)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:870)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:305)
at com.sun.proxy.$Proxy86.merge(Unknown Source)
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:493)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:377)
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:641)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:605)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:590)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy93.save(Unknown Source)
at cc.tonny.optaplanner.exercise.springbootcloudbalance.CommandLineAppStartupRunner.run(CommandLineAppStartupRunner.java:64)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:818)
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:802)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:341)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1277)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1265)
at cc.tonny.optaplanner.exercise.springbootcloudbalance.SpringbootCloudbalanceApplication.main(SpringbootCloudbalanceApplication.java:10)
Please check the code at https://github.com/tonny1983/springboot-cloudbalance
Upvotes: 0
Views: 117
Reputation: 27312
Use OptaPlanner 7.18.0.Final
or later, that supports Hibernate 5.3+
Upvotes: 0
Reputation: 930
Finally, I got it works in spring-boot-jpa
v2.x with hibernate
v5.2.x, and I'll state the patch as follows:
Create a new class which extends org.optaplanner.persistence.jpa.impl.score.AbstractScoreHibernateType
and implement all methods defined in the org.hibernate.usertype.CompositeUserType
(you can copy all the code from AbstractScoreHibernateType
but just change the parameter's type from org.hibernate.engine.spi.SessionImplementor
to org.hibernate.engine.spi.SharedSessionContractImplementor
)
Create a new *SoftScoreHibernateType
class which extends the one created in step 1, and add its construction method just like origin *SoftScoreHibernateType
class
In my case, getPropertyValue
method throws java.lang.ArrayIndexOutOfBoundsException
because levelNumbers
array only holds three items -- hard score, medium score and soft score, but the propertyIndex
is from 1 to 3. So, I overrides the method just change the last line to return levelNumbers[propertyIndex
- 1
];
That's all for my case.
Upvotes: 1