Reputation: 802
I'm using OptaPlanner 9.37.0.Final
with quarkus 3.1.3.Final
and Kotlin 1.8.21
to solve a VRP.
When I run quarkusDev
, my current setup runs just fine, but when I run a @QuarkusTest
, I get the following ClassCastException
, hinting that something with class loading might be broken.
java.lang.ClassCastException: class com.cargonexx.vehiclerouting.domain.LoadJob$OptaPlanner$MemberAccessor$Field$arrivalTime cannot be cast to class org.optaplanner.core.impl.domain.common.accessor.MemberAccessor (com.cargonexx.vehiclerouting.domain.LoadJob$OptaPlanner$MemberAccessor$Field$arrivalTime is in unnamed module of loader 'OptaPlanner Gizmo SolutionCloner ClassLoader' @611d16c9; org.optaplanner.core.impl.domain.common.accessor.MemberAccessor is in unnamed module of loader io.quarkus.bootstrap.classloading.QuarkusClassLoader @319988b0)
at org.optaplanner.core.impl.domain.common.accessor.gizmo.GizmoMemberAccessorImplementor.createInstance(GizmoMemberAccessorImplementor.java:118)
at org.optaplanner.core.impl.domain.common.accessor.gizmo.GizmoMemberAccessorImplementor.createAccessorFor(GizmoMemberAccessorImplementor.java:112)
at org.optaplanner.core.impl.domain.common.accessor.gizmo.GizmoMemberAccessorFactory.buildGizmoMemberAccessor(GizmoMemberAccessorFactory.java:40)
at org.optaplanner.core.impl.domain.common.accessor.MemberAccessorFactory.buildMemberAccessor(MemberAccessorFactory.java:38)
at org.optaplanner.core.impl.domain.common.accessor.MemberAccessorFactory.lambda$buildAndCacheMemberAccessor$0(MemberAccessorFactory.java:125)
at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708)
at org.optaplanner.core.impl.domain.common.accessor.MemberAccessorFactory.buildAndCacheMemberAccessor(MemberAccessorFactory.java:124)
at org.optaplanner.core.impl.domain.entity.descriptor.EntityDescriptor.processPlanningVariableAnnotation(EntityDescriptor.java:239)
at org.optaplanner.core.impl.domain.entity.descriptor.EntityDescriptor.processAnnotations(EntityDescriptor.java:154)
at org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor.buildSolutionDescriptor(SolutionDescriptor.java:106)
at org.optaplanner.core.impl.solver.DefaultSolverFactory.buildSolutionDescriptor(DefaultSolverFactory.java:147)
at org.optaplanner.core.impl.solver.DefaultSolverFactory.<init>(DefaultSolverFactory.java:69)
at org.optaplanner.core.api.solver.SolverFactory.create(SolverFactory.java:106)
at org.optaplanner.quarkus.bean.DefaultOptaPlannerBeanProvider.solverFactory(DefaultOptaPlannerBeanProvider.java:46)
at org.optaplanner.quarkus.bean.DefaultOptaPlannerBeanProvider_ProducerMethod_solverFactory_3b1fa4ff0a3de7781ba3e1239701086bba97ef14_Bean.doCreate(Unknown Source)
at org.optaplanner.quarkus.bean.DefaultOptaPlannerBeanProvider_ProducerMethod_solverFactory_3b1fa4ff0a3de7781ba3e1239701086bba97ef14_Bean.create(Unknown Source)
at org.optaplanner.quarkus.bean.DefaultOptaPlannerBeanProvider_ProducerMethod_solverFactory_3b1fa4ff0a3de7781ba3e1239701086bba97ef14_Bean.get(Unknown Source)
at org.optaplanner.quarkus.bean.DefaultOptaPlannerBeanProvider_ProducerMethod_solverFactory_3b1fa4ff0a3de7781ba3e1239701086bba97ef14_Bean.get(Unknown Source)
at org.optaplanner.quarkus.bean.DefaultOptaPlannerBeanProvider_ProducerMethod_solverManager_d6636211e93ca3985f0495d972987bdadf803f37_Bean.doCreate(Unknown Source)
at org.optaplanner.quarkus.bean.DefaultOptaPlannerBeanProvider_ProducerMethod_solverManager_d6636211e93ca3985f0495d972987bdadf803f37_Bean.create(Unknown Source)
at org.optaplanner.quarkus.bean.DefaultOptaPlannerBeanProvider_ProducerMethod_solverManager_d6636211e93ca3985f0495d972987bdadf803f37_Bean.get(Unknown Source)
at org.optaplanner.quarkus.bean.DefaultOptaPlannerBeanProvider_ProducerMethod_solverManager_d6636211e93ca3985f0495d972987bdadf803f37_Bean.get(Unknown Source)
at com.cargonexx.vehiclerouting.rest.SolverResource_Bean.doCreate(Unknown Source)
at com.cargonexx.vehiclerouting.rest.SolverResource_Bean.create(Unknown Source)
at com.cargonexx.vehiclerouting.rest.SolverResource_Bean.create(Unknown Source)
at io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:113)
at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:37)
at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:34)
at io.quarkus.arc.impl.LazyValue.get(LazyValue.java:26)
at io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69)
at io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:34)
at com.cargonexx.vehiclerouting.rest.SolverResource_Bean.get(Unknown Source)
at com.cargonexx.vehiclerouting.rest.SolverResource_Bean.get(Unknown Source)
at io.quarkus.arc.impl.ArcContainerImpl.beanInstanceHandle(ArcContainerImpl.java:499)
at io.quarkus.arc.impl.ArcContainerImpl.beanInstanceHandle(ArcContainerImpl.java:479)
at io.quarkus.arc.impl.ArcContainerImpl.beanInstanceHandle(ArcContainerImpl.java:512)
at io.quarkus.arc.impl.ArcContainerImpl$2.get(ArcContainerImpl.java:287)
at io.quarkus.arc.impl.ArcContainerImpl$2.get(ArcContainerImpl.java:284)
at io.quarkus.arc.runtime.BeanContainerImpl$1.create(BeanContainerImpl.java:46)
at io.quarkus.resteasy.reactive.common.runtime.ArcBeanFactory.createInstance(ArcBeanFactory.java:27)
at org.jboss.resteasy.reactive.server.handlers.InstanceHandler.handle(InstanceHandler.java:26)
at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:139)
at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:145)
at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:576)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:833)
I have a PlanningEntity
along the lines of:
@PlanningEntity
class LoadJob {
@PlanningId lateinit var id: String
@InverseRelationShadowVariable(sourceVariableName = "tour") //
var vehicle: Vehicle? = null
@PreviousElementShadowVariable(sourceVariableName = "tour") //
var previousLoadJob: LoadJob? = null
@NextElementShadowVariable(sourceVariableName = "tour") //
var nextLoadJob: LoadJob? = null
@JvmField
@ShadowVariable(
variableListenerClass = ArrivalTimeUpdateListener::class,
sourceVariableName = "vehicle"
)
@ShadowVariable(
variableListenerClass = ArrivalTimeUpdateListener::class,
sourceVariableName = "previousLoadJob"
)
var arrivalTime: LocalDateTime? = null
}
which is used in the PlanningListVariable
in the Vehicle
class:
@PlanningEntity
class Vehicle {
@PlanningId lateinit var planningId: String
@PlanningListVariable lateinit var tour: MutableList<LoadJob>
}
Both are part of the PlanningSolution
@PlanningSolution
class TourPlan {
lateinit var id: String
@PlanningEntityCollectionProperty //
lateinit var vehicles: List<Vehicle>
@ValueRangeProvider
@ProblemFactCollectionProperty //
lateinit var loadJobs: List<LoadJob>
@PlanningScore //
var score: HardMediumSoftLongScore? = null
@ConstraintConfigurationProvider
var constraintConfiguration: TourPlanConstraintConfiguration = TourPlanConstraintConfiguration()
constructor() // required for optaplanner
}
Has anybody else run into an issue like that? Are there any known workarounds or fixes for this issue?
I have been working for almost a month with this setup now, but in the long run it might not be feasible to just don't run any QuarkusTest
s as they are broken with the current setup.
Notes
REFLECTION
instead of GIZMO
for optaplanner domain access, I don't have this issue. However, since reflection is slower, as the optaplanner documentation also mentions, I'd like to be able to use GIZMO
for the performance gain and not have to use diverging configurations for tests and regular buildsUpvotes: 0
Views: 241
Reputation: 5702
I believe that this issue was fixed in Timefold 1.0.0. (The issue description helpfully also contains a workaround, which you already found yourself.) Please check that version and, if your case is still not fixed, kindly file an issue, ideally with a reproducer.
Whether OptaPlanner will fix this issue and when, I do not know.
Upvotes: 3