diff --git a/.mvn/maven.config b/.mvn/maven.config index d989e3ebb9e..04b9cea7770 100644 --- a/.mvn/maven.config +++ b/.mvn/maven.config @@ -1,5 +1,4 @@ -ntp --B # timefold-solver-model-parent configures maven plugins required for Timefold models, but failing the build # of that module itself. This way, we disable the plugin execution, while it remains active by default for models. -Dai.timefold.sdk.model.processing.disabled \ No newline at end of file diff --git a/build/build-parent/pom.xml b/build/build-parent/pom.xml index ee40e292486..033b5a0d3df 100644 --- a/build/build-parent/pom.xml +++ b/build/build-parent/pom.xml @@ -664,7 +664,6 @@ true true - true diff --git a/core/src/build/revapi-differences.json b/core/src/build/revapi-differences.json index 6441d68975f..caa59d0ea5a 100644 --- a/core/src/build/revapi-differences.json +++ b/core/src/build/revapi-differences.json @@ -3,6 +3,48 @@ "extension": "revapi.differences", "configuration": { "differences": [ + { + "ignore": true, + "code": "java.field.typeChanged", + "old": "field ai.timefold.solver.core.config.heuristic.selector.move.MoveSelectorConfig>.comparatorClass", + "new": "field ai.timefold.solver.core.config.heuristic.selector.move.MoveSelectorConfig>.comparatorClass", + "justification": "Internal protected fields; safe." + }, + { + "ignore": true, + "code": "java.field.typeChanged", + "old": "field ai.timefold.solver.core.config.heuristic.selector.move.MoveSelectorConfig>.comparatorFactoryClass", + "new": "field ai.timefold.solver.core.config.heuristic.selector.move.MoveSelectorConfig>.comparatorFactoryClass", + "justification": "Internal protected fields; safe." + }, + { + "ignore": true, + "code": "java.field.typeChanged", + "old": "field ai.timefold.solver.core.config.heuristic.selector.move.MoveSelectorConfig>.filterClass", + "new": "field ai.timefold.solver.core.config.heuristic.selector.move.MoveSelectorConfig>.filterClass", + "justification": "Internal protected fields; safe." + }, + { + "ignore": true, + "code": "java.field.typeChanged", + "old": "field ai.timefold.solver.core.config.heuristic.selector.move.MoveSelectorConfig>.probabilityWeightFactoryClass", + "new": "field ai.timefold.solver.core.config.heuristic.selector.move.MoveSelectorConfig>.probabilityWeightFactoryClass", + "justification": "Internal protected fields; safe." + }, + { + "ignore": true, + "code": "java.field.typeChanged", + "old": "field ai.timefold.solver.core.config.heuristic.selector.move.MoveSelectorConfig>.sorterClass", + "new": "field ai.timefold.solver.core.config.heuristic.selector.move.MoveSelectorConfig>.sorterClass", + "justification": "Internal protected fields; safe." + }, + { + "ignore": true, + "code": "java.field.typeChanged", + "old": "field ai.timefold.solver.core.config.heuristic.selector.move.generic.AbstractPillarMoveSelectorConfig>.subPillarSequenceComparatorClass", + "new": "field ai.timefold.solver.core.config.heuristic.selector.move.generic.AbstractPillarMoveSelectorConfig>.subPillarSequenceComparatorClass", + "justification": "Internal protected fields; safe." + } ] } } diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/stream/test/MultiConstraintAssertion.java b/core/src/main/java/ai/timefold/solver/core/api/score/stream/test/MultiConstraintAssertion.java index 8fa4afeae61..c042e5a8054 100644 --- a/core/src/main/java/ai/timefold/solver/core/api/score/stream/test/MultiConstraintAssertion.java +++ b/core/src/main/java/ai/timefold/solver/core/api/score/stream/test/MultiConstraintAssertion.java @@ -3,9 +3,10 @@ import ai.timefold.solver.core.api.score.Score; import ai.timefold.solver.core.api.score.stream.ConstraintProvider; -import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; +@NullMarked public interface MultiConstraintAssertion { /** @@ -14,7 +15,7 @@ public interface MultiConstraintAssertion { * @param score total score calculated for the given set of facts * @throws AssertionError when the expected score does not match the calculated score */ - default void scores(@NonNull Score score) { + default void scores(Score score) { scores(score, null); } @@ -25,7 +26,7 @@ default void scores(@NonNull Score score) { * @param message description of the scenario being asserted * @throws AssertionError when the expected score does not match the calculated score */ - void scores(@NonNull Score score, @Nullable String message); + void scores(Score score, @Nullable String message); /** * Returns the {@link Score} produced by all constraints in the {@link ConstraintProvider} for the given set of facts. @@ -39,16 +40,15 @@ default void scores(@NonNull Score score) { * {@snippet : * HardSoftScore scoreA = constraintVerifier.verifyThat() * .givenSolution(solutionA) - * .score(); + * .getScore(); * HardSoftScore scoreB = constraintVerifier.verifyThat() * .givenSolution(solutionB) - * .score(); + * .getScore(); * assertThat(scoreA).isGreaterThan(scoreB); * } * * @return the score produced by all constraints for the given facts, never null */ - @NonNull - > S score(); + > S getScore(); } diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/stream/test/SingleConstraintAssertion.java b/core/src/main/java/ai/timefold/solver/core/api/score/stream/test/SingleConstraintAssertion.java index 1bbe7efbe77..b5b9b44f6ca 100644 --- a/core/src/main/java/ai/timefold/solver/core/api/score/stream/test/SingleConstraintAssertion.java +++ b/core/src/main/java/ai/timefold/solver/core/api/score/stream/test/SingleConstraintAssertion.java @@ -7,9 +7,10 @@ import ai.timefold.solver.core.api.score.stream.Constraint; import ai.timefold.solver.core.api.score.stream.ConstraintJustification; -import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; +@NullMarked public interface SingleConstraintAssertion { /** @@ -19,9 +20,8 @@ public interface SingleConstraintAssertion { * @param message description of the scenario being asserted * @throws AssertionError when the expected penalty is not observed */ - @NonNull SingleConstraintAssertion justifiesWith(@Nullable String message, - @NonNull ConstraintJustification @NonNull... justifications); + ConstraintJustification... justifications); /** * Asserts that the {@link Constraint} being tested, given a set of facts, results in a given @@ -30,7 +30,7 @@ SingleConstraintAssertion justifiesWith(@Nullable String message, * @param justifications the expected justifications. * @throws AssertionError when the expected penalty is not observed */ - default @NonNull SingleConstraintAssertion justifiesWith(@NonNull ConstraintJustification @NonNull... justifications) { + default SingleConstraintAssertion justifiesWith(ConstraintJustification... justifications) { return justifiesWith(null, justifications); } @@ -41,9 +41,8 @@ SingleConstraintAssertion justifiesWith(@Nullable String message, * @param message description of the scenario being asserted * @throws AssertionError when the expected penalty is not observed */ - @NonNull SingleConstraintAssertion justifiesWithExactly(@Nullable String message, - @NonNull ConstraintJustification @NonNull... justifications); + ConstraintJustification... justifications); /** * Asserts that the {@link Constraint} being tested, given a set of facts, results in a given @@ -52,8 +51,8 @@ SingleConstraintAssertion justifiesWithExactly(@Nullable String message, * @param justifications the expected justifications. * @throws AssertionError when the expected penalty is not observed */ - default @NonNull SingleConstraintAssertion - justifiesWithExactly(@NonNull ConstraintJustification @NonNull... justifications) { + default SingleConstraintAssertion + justifiesWithExactly(ConstraintJustification... justifications) { return justifiesWithExactly(null, justifications); } @@ -126,7 +125,7 @@ default void penalizesBy(long matchWeightTotal) { * @param matchWeightTotal at least 0, expected sum of match weights of matches of the constraint. * @throws AssertionError when the expected penalty is not observed */ - default void penalizesBy(@NonNull BigDecimal matchWeightTotal) { + default void penalizesBy(BigDecimal matchWeightTotal) { penalizesBy(null, matchWeightTotal); } @@ -137,7 +136,7 @@ default void penalizesBy(@NonNull BigDecimal matchWeightTotal) { * @param matchWeightTotal at least 0, expected sum of match weights of matches of the constraint. * @throws AssertionError when the expected penalty is not observed */ - void penalizesBy(@Nullable String message, @NonNull BigDecimal matchWeightTotal); + void penalizesBy(@Nullable String message, BigDecimal matchWeightTotal); /** * Asserts that the {@link Constraint} being tested, given a set of facts, results in a given number of penalties. @@ -232,7 +231,7 @@ default void rewardsWith(long matchWeightTotal) { * @param matchWeightTotal at least 0, expected sum of match weights of matches of the constraint. * @throws AssertionError when the expected reward is not observed */ - default void rewardsWith(@NonNull BigDecimal matchWeightTotal) { + default void rewardsWith(BigDecimal matchWeightTotal) { rewardsWith(null, matchWeightTotal); } @@ -243,7 +242,7 @@ default void rewardsWith(@NonNull BigDecimal matchWeightTotal) { * @param matchWeightTotal at least 0, expected sum of match weights of matches of the constraint. * @throws AssertionError when the expected reward is not observed */ - void rewardsWith(@Nullable String message, @NonNull BigDecimal matchWeightTotal); + void rewardsWith(@Nullable String message, BigDecimal matchWeightTotal); /** * Asserts that the {@link Constraint} being tested, given a set of facts, results in a given number of rewards. @@ -341,7 +340,7 @@ default void penalizesByMoreThan(long matchWeightTotal) { * @param matchWeightTotal at least 0, expected sum of match weights of matches of the constraint. * @throws AssertionError when the expected penalty is not observed */ - default void penalizesByMoreThan(@NonNull BigDecimal matchWeightTotal) { + default void penalizesByMoreThan(BigDecimal matchWeightTotal) { penalizesByMoreThan(null, matchWeightTotal); } @@ -352,7 +351,7 @@ default void penalizesByMoreThan(@NonNull BigDecimal matchWeightTotal) { * @param matchWeightTotal at least 0, expected sum of match weights of matches of the constraint. * @throws AssertionError when the expected penalty is not observed */ - void penalizesByMoreThan(@Nullable String message, @NonNull BigDecimal matchWeightTotal); + void penalizesByMoreThan(@Nullable String message, BigDecimal matchWeightTotal); /** * Asserts that the {@link Constraint} being tested, given a set of facts, @@ -431,7 +430,7 @@ default void rewardsWithMoreThan(long matchWeightTotal) { * @param matchWeightTotal at least 0, expected sum of match weights of matches of the constraint. * @throws AssertionError when the expected reward is not observed */ - default void rewardsWithMoreThan(@NonNull BigDecimal matchWeightTotal) { + default void rewardsWithMoreThan(BigDecimal matchWeightTotal) { rewardsWithMoreThan(null, matchWeightTotal); } @@ -442,7 +441,7 @@ default void rewardsWithMoreThan(@NonNull BigDecimal matchWeightTotal) { * @param matchWeightTotal at least 0, expected sum of match weights of matches of the constraint. * @throws AssertionError when the expected reward is not observed */ - void rewardsWithMoreThan(@Nullable String message, @NonNull BigDecimal matchWeightTotal); + void rewardsWithMoreThan(@Nullable String message, BigDecimal matchWeightTotal); /** * Asserts that the {@link Constraint} being tested, given a set of facts, @@ -522,7 +521,7 @@ default void penalizesByLessThan(long matchWeightTotal) { * @param matchWeightTotal at least 1, expected sum of match weights of matches of the constraint. * @throws AssertionError when the expected penalty is not observed */ - default void penalizesByLessThan(@NonNull BigDecimal matchWeightTotal) { + default void penalizesByLessThan(BigDecimal matchWeightTotal) { penalizesByLessThan(null, matchWeightTotal); } @@ -533,7 +532,7 @@ default void penalizesByLessThan(@NonNull BigDecimal matchWeightTotal) { * @param matchWeightTotal at least 1, expected sum of match weights of matches of the constraint. * @throws AssertionError when the expected penalty is not observed */ - void penalizesByLessThan(@Nullable String message, @NonNull BigDecimal matchWeightTotal); + void penalizesByLessThan(@Nullable String message, BigDecimal matchWeightTotal); /** * Asserts that the {@link Constraint} being tested, given a set of facts, @@ -612,7 +611,7 @@ default void rewardsWithLessThan(long matchWeightTotal) { * @param matchWeightTotal at least 1, expected sum of match weights of matches of the constraint. * @throws AssertionError when the expected reward is not observed */ - default void rewardsWithLessThan(@NonNull BigDecimal matchWeightTotal) { + default void rewardsWithLessThan(BigDecimal matchWeightTotal) { rewardsWithLessThan(null, matchWeightTotal); } @@ -623,7 +622,7 @@ default void rewardsWithLessThan(@NonNull BigDecimal matchWeightTotal) { * @param matchWeightTotal at least 1, expected sum of match weights of matches of the constraint. * @throws AssertionError when the expected reward is not observed */ - void rewardsWithLessThan(@Nullable String message, @NonNull BigDecimal matchWeightTotal); + void rewardsWithLessThan(@Nullable String message, BigDecimal matchWeightTotal); /** * Asserts that the {@link Constraint} being tested, given a set of facts, @@ -662,22 +661,21 @@ default void rewardsLessThan(long times) { * {@snippet : * HardSoftScore scoreA = constraintVerifier.verifyThat(MyConstraints::roomConflict) * .given(entity1, entity2) - * .score(); + * .getScore(); * HardSoftScore scoreB = constraintVerifier.verifyThat(MyConstraints::roomConflict) * .given(entity3, entity4) - * .score(); + * .getScore(); * assertThat(scoreA).isLessThan(scoreB); * } * * @return the score produced by this single constraint for the given facts, never null */ - @NonNull - > S score(); + > S getScore(); /** * Returns the match weight total of the {@link Constraint} being tested for the given set of facts. *

- * Unlike {@link #score()}, which returns the full score (match weight × constraint weight), + * Unlike {@link #getScore()}, which returns the full score (match weight × constraint weight), * this method returns only the match weight — the same number you would pass * to assertion methods like {@link #penalizesBy(int)} or {@link #rewardsWith(int)}. *

@@ -687,19 +685,18 @@ default void rewardsLessThan(long times) { * Usage example: * * {@snippet : - * Number impactA = constraintVerifier.verifyThat(MyConstraints::roomConflict) + * var impactA = constraintVerifier.verifyThat(MyConstraints::roomConflict) * .given(entity1, entity2) - * .impact(); - * Number impactB = constraintVerifier.verifyThat(MyConstraints::roomConflict) + * .getImpact(); + * var impactB = constraintVerifier.verifyThat(MyConstraints::roomConflict) * .given(entity3, entity4) - * .impact(); + * .getImpact(); * assertThat(impactA.intValue()).isGreaterThan(impactB.intValue()); * } * * @return the match weight total produced by this single constraint, never null. * Positive for rewards, negative for penalties, zero when there is no impact. */ - @NonNull - Number impact(); + Number getImpact(); } diff --git a/core/src/main/java/ai/timefold/solver/core/config/constructionheuristic/placer/QueuedValuePlacerConfig.java b/core/src/main/java/ai/timefold/solver/core/config/constructionheuristic/placer/QueuedValuePlacerConfig.java index b2d5703158e..6899b2644f3 100644 --- a/core/src/main/java/ai/timefold/solver/core/config/constructionheuristic/placer/QueuedValuePlacerConfig.java +++ b/core/src/main/java/ai/timefold/solver/core/config/constructionheuristic/placer/QueuedValuePlacerConfig.java @@ -30,7 +30,7 @@ public final class QueuedValuePlacerConfig extends EntityPlacerConfig entityClass = null; + private String entityClass = null; @XmlElement(name = "valueSelector") private ValueSelectorConfig valueSelectorConfig = null; @@ -50,11 +50,11 @@ public final class QueuedValuePlacerConfig extends EntityPlacerConfig getEntityClass() { - return entityClass; + return ConfigUtils.resolveClass(entityClass, "entityClass", this); } public void setEntityClass(@Nullable Class entityClass) { - this.entityClass = entityClass; + this.entityClass = entityClass == null ? null : entityClass.getName(); } public @Nullable ValueSelectorConfig getValueSelectorConfig() { @@ -78,7 +78,7 @@ public void setMoveSelectorConfig(@Nullable MoveSelectorConfig moveSelectorConfi // ************************************************************************ public @NonNull QueuedValuePlacerConfig withEntityClass(@NonNull Class entityClass) { - this.setEntityClass(entityClass); + this.entityClass = entityClass.getName(); return this; } @@ -98,7 +98,7 @@ public void setMoveSelectorConfig(@Nullable MoveSelectorConfig moveSelectorConfi @Override public @NonNull QueuedValuePlacerConfig inherit(@NonNull QueuedValuePlacerConfig inheritedConfig) { - entityClass = ConfigUtils.inheritOverwritableProperty(entityClass, inheritedConfig.getEntityClass()); + entityClass = ConfigUtils.inheritOverwritableProperty(entityClass, inheritedConfig.entityClass); valueSelectorConfig = ConfigUtils.inheritConfig(valueSelectorConfig, inheritedConfig.getValueSelectorConfig()); setMoveSelectorConfig( ConfigUtils.inheritOverwritableProperty(getMoveSelectorConfig(), inheritedConfig.getMoveSelectorConfig())); @@ -112,7 +112,7 @@ public void setMoveSelectorConfig(@Nullable MoveSelectorConfig moveSelectorConfi @Override public void visitReferencedClasses(@NonNull Consumer> classVisitor) { - classVisitor.accept(entityClass); + classVisitor.accept(getEntityClass()); if (valueSelectorConfig != null) { valueSelectorConfig.visitReferencedClasses(classVisitor); } diff --git a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/common/nearby/NearbySelectionConfig.java b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/common/nearby/NearbySelectionConfig.java index d92d4ff475b..ba6a8930744 100644 --- a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/common/nearby/NearbySelectionConfig.java +++ b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/common/nearby/NearbySelectionConfig.java @@ -44,7 +44,7 @@ public final class NearbySelectionConfig extends SelectorConfig nearbyDistanceMeterClass = null; + private String nearbyDistanceMeterClass = null; private NearbySelectionDistributionType nearbySelectionDistributionType = null; @@ -85,11 +85,11 @@ public void setOriginValueSelectorConfig(@Nullable ValueSelectorConfig originVal } public @Nullable Class getNearbyDistanceMeterClass() { - return nearbyDistanceMeterClass; + return ConfigUtils.resolveClass(nearbyDistanceMeterClass, "nearbyDistanceMeterClass", this); } public void setNearbyDistanceMeterClass(@Nullable Class nearbyDistanceMeterClass) { - this.nearbyDistanceMeterClass = nearbyDistanceMeterClass; + this.nearbyDistanceMeterClass = nearbyDistanceMeterClass == null ? null : nearbyDistanceMeterClass.getName(); } public @Nullable NearbySelectionDistributionType getNearbySelectionDistributionType() { @@ -189,7 +189,7 @@ public void setBetaDistributionBeta(@Nullable Double betaDistributionBeta) { public @NonNull NearbySelectionConfig withNearbyDistanceMeterClass(@NonNull Class nearbyDistanceMeterClass) { - this.setNearbyDistanceMeterClass(nearbyDistanceMeterClass); + this.nearbyDistanceMeterClass = nearbyDistanceMeterClass.getName(); return this; } @@ -316,7 +316,7 @@ has a resolvedCacheType (%s) that is cached.""" originValueSelectorConfig = ConfigUtils.inheritConfig(originValueSelectorConfig, inheritedConfig.getOriginValueSelectorConfig()); nearbyDistanceMeterClass = ConfigUtils.inheritOverwritableProperty(nearbyDistanceMeterClass, - inheritedConfig.getNearbyDistanceMeterClass()); + inheritedConfig.nearbyDistanceMeterClass); nearbySelectionDistributionType = ConfigUtils.inheritOverwritableProperty(nearbySelectionDistributionType, inheritedConfig.getNearbySelectionDistributionType()); blockDistributionSizeMinimum = ConfigUtils.inheritOverwritableProperty(blockDistributionSizeMinimum, @@ -355,7 +355,7 @@ public void visitReferencedClasses(@NonNull Consumer> classVisitor) { if (originValueSelectorConfig != null) { originValueSelectorConfig.visitReferencedClasses(classVisitor); } - classVisitor.accept(nearbyDistanceMeterClass); + classVisitor.accept(getNearbyDistanceMeterClass()); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/entity/EntitySelectorConfig.java b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/entity/EntitySelectorConfig.java index 4de7462968b..ea9b3298f0a 100644 --- a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/entity/EntitySelectorConfig.java +++ b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/entity/EntitySelectorConfig.java @@ -55,7 +55,7 @@ public static EntitySelectorConfig newMimicSelectorConfig(String mimicSelectorRe private String mimicSelectorRef = null; @Nullable - private Class entityClass = null; + private String entityClass = null; @Nullable private SelectionCacheType cacheType = null; @Nullable @@ -66,21 +66,21 @@ public static EntitySelectorConfig newMimicSelectorConfig(String mimicSelectorRe private NearbySelectionConfig nearbySelectionConfig = null; @Nullable - private Class filterClass = null; + private String filterClass = null; @Nullable private EntitySorterManner sorterManner = null; @Nullable - private Class comparatorClass = null; + private String comparatorClass = null; @Nullable - private Class comparatorFactoryClass = null; + private String comparatorFactoryClass = null; @Nullable private SelectionSorterOrder sorterOrder = null; @Nullable - private Class sorterClass = null; + private String sorterClass = null; @Nullable - private Class probabilityWeightFactoryClass = null; + private String probabilityWeightFactoryClass = null; @Nullable private Long selectedCountLimit = null; @@ -88,8 +88,8 @@ public static EntitySelectorConfig newMimicSelectorConfig(String mimicSelectorRe public EntitySelectorConfig() { } - public EntitySelectorConfig(Class entityClass) { - this.entityClass = entityClass; + public EntitySelectorConfig(@Nullable Class entityClass) { + this.entityClass = entityClass == null ? null : entityClass.getName(); } public EntitySelectorConfig(@Nullable EntitySelectorConfig inheritedConfig) { @@ -115,11 +115,11 @@ public void setMimicSelectorRef(@Nullable String mimicSelectorRef) { } public @Nullable Class getEntityClass() { - return entityClass; + return ConfigUtils.resolveClass(entityClass, "entityClass", this); } public void setEntityClass(@Nullable Class entityClass) { - this.entityClass = entityClass; + this.entityClass = entityClass == null ? null : entityClass.getName(); } public @Nullable SelectionCacheType getCacheType() { @@ -147,11 +147,11 @@ public void setNearbySelectionConfig(@Nullable NearbySelectionConfig nearbySelec } public @Nullable Class getFilterClass() { - return filterClass; + return ConfigUtils.resolveClass(filterClass, "filterClass", this); } public void setFilterClass(@Nullable Class filterClass) { - this.filterClass = filterClass; + this.filterClass = filterClass == null ? null : filterClass.getName(); } public @Nullable EntitySorterManner getSorterManner() { @@ -163,19 +163,19 @@ public void setSorterManner(@Nullable EntitySorterManner sorterManner) { } public @Nullable Class getComparatorClass() { - return comparatorClass; + return ConfigUtils.resolveClass(comparatorClass, "comparatorClass", this); } public void setComparatorClass(@Nullable Class comparatorClass) { - this.comparatorClass = comparatorClass; + this.comparatorClass = comparatorClass == null ? null : comparatorClass.getName(); } public @Nullable Class getComparatorFactoryClass() { - return comparatorFactoryClass; + return ConfigUtils.resolveClass(comparatorFactoryClass, "comparatorFactoryClass", this); } public void setComparatorFactoryClass(@Nullable Class comparatorFactoryClass) { - this.comparatorFactoryClass = comparatorFactoryClass; + this.comparatorFactoryClass = comparatorFactoryClass == null ? null : comparatorFactoryClass.getName(); } public @Nullable SelectionSorterOrder getSorterOrder() { @@ -187,20 +187,21 @@ public void setSorterOrder(@Nullable SelectionSorterOrder sorterOrder) { } public @Nullable Class getSorterClass() { - return sorterClass; + return ConfigUtils.resolveClass(sorterClass, "sorterClass", this); } public void setSorterClass(@Nullable Class sorterClass) { - this.sorterClass = sorterClass; + this.sorterClass = sorterClass == null ? null : sorterClass.getName(); } public @Nullable Class getProbabilityWeightFactoryClass() { - return probabilityWeightFactoryClass; + return ConfigUtils.resolveClass(probabilityWeightFactoryClass, "probabilityWeightFactoryClass", this); } public void setProbabilityWeightFactoryClass( @Nullable Class probabilityWeightFactoryClass) { - this.probabilityWeightFactoryClass = probabilityWeightFactoryClass; + this.probabilityWeightFactoryClass = + probabilityWeightFactoryClass == null ? null : probabilityWeightFactoryClass.getName(); } public @Nullable Long getSelectedCountLimit() { @@ -226,7 +227,7 @@ public EntitySelectorConfig withMimicSelectorRef(String mimicSelectorRef) { } public EntitySelectorConfig withEntityClass(Class entityClass) { - this.setEntityClass(entityClass); + this.entityClass = entityClass.getName(); return this; } @@ -246,7 +247,7 @@ public EntitySelectorConfig withNearbySelectionConfig(NearbySelectionConfig near } public EntitySelectorConfig withFilterClass(Class filterClass) { - this.setFilterClass(filterClass); + this.filterClass = filterClass.getName(); return this; } @@ -256,13 +257,12 @@ public EntitySelectorConfig withSorterManner(EntitySorterManner sorterManner) { } public EntitySelectorConfig withComparatorClass(Class comparatorClass) { - this.setComparatorClass(comparatorClass); + this.comparatorClass = comparatorClass.getName(); return this; } - public EntitySelectorConfig - withComparatorFactoryClass(Class comparatorFactoryClass) { - this.setComparatorFactoryClass(comparatorFactoryClass); + public EntitySelectorConfig withComparatorFactoryClass(Class comparatorFactoryClass) { + this.comparatorFactoryClass = comparatorFactoryClass.getName(); return this; } @@ -272,13 +272,13 @@ public EntitySelectorConfig withSorterOrder(SelectionSorterOrder sorterOrder) { } public EntitySelectorConfig withSorterClass(Class sorterClass) { - this.setSorterClass(sorterClass); + this.sorterClass = sorterClass.getName(); return this; } public EntitySelectorConfig withProbabilityWeightFactoryClass(Class factoryClass) { - this.setProbabilityWeightFactoryClass(factoryClass); + this.probabilityWeightFactoryClass = factoryClass.getName(); return this; } @@ -297,24 +297,24 @@ public EntitySelectorConfig inherit(EntitySelectorConfig inheritedConfig) { mimicSelectorRef = ConfigUtils.inheritOverwritableProperty(mimicSelectorRef, inheritedConfig.getMimicSelectorRef()); entityClass = ConfigUtils.inheritOverwritableProperty(entityClass, - inheritedConfig.getEntityClass()); + inheritedConfig.entityClass); nearbySelectionConfig = ConfigUtils.inheritConfig(nearbySelectionConfig, inheritedConfig.getNearbySelectionConfig()); cacheType = ConfigUtils.inheritOverwritableProperty(cacheType, inheritedConfig.getCacheType()); selectionOrder = ConfigUtils.inheritOverwritableProperty(selectionOrder, inheritedConfig.getSelectionOrder()); filterClass = ConfigUtils.inheritOverwritableProperty( - filterClass, inheritedConfig.getFilterClass()); + filterClass, inheritedConfig.filterClass); sorterManner = ConfigUtils.inheritOverwritableProperty( sorterManner, inheritedConfig.getSorterManner()); comparatorClass = ConfigUtils.inheritOverwritableProperty( - comparatorClass, inheritedConfig.getComparatorClass()); + comparatorClass, inheritedConfig.comparatorClass); comparatorFactoryClass = ConfigUtils.inheritOverwritableProperty( - comparatorFactoryClass, inheritedConfig.getComparatorFactoryClass()); + comparatorFactoryClass, inheritedConfig.comparatorFactoryClass); sorterOrder = ConfigUtils.inheritOverwritableProperty( sorterOrder, inheritedConfig.getSorterOrder()); sorterClass = ConfigUtils.inheritOverwritableProperty( - sorterClass, inheritedConfig.getSorterClass()); + sorterClass, inheritedConfig.sorterClass); probabilityWeightFactoryClass = ConfigUtils.inheritOverwritableProperty( - probabilityWeightFactoryClass, inheritedConfig.getProbabilityWeightFactoryClass()); + probabilityWeightFactoryClass, inheritedConfig.probabilityWeightFactoryClass); selectedCountLimit = ConfigUtils.inheritOverwritableProperty( selectedCountLimit, inheritedConfig.getSelectedCountLimit()); return this; @@ -327,15 +327,15 @@ public EntitySelectorConfig copyConfig() { @Override public void visitReferencedClasses(Consumer> classVisitor) { - classVisitor.accept(entityClass); + classVisitor.accept(getEntityClass()); if (nearbySelectionConfig != null) { nearbySelectionConfig.visitReferencedClasses(classVisitor); } - classVisitor.accept(filterClass); - classVisitor.accept(comparatorClass); - classVisitor.accept(comparatorFactoryClass); - classVisitor.accept(sorterClass); - classVisitor.accept(probabilityWeightFactoryClass); + classVisitor.accept(getFilterClass()); + classVisitor.accept(getComparatorClass()); + classVisitor.accept(getComparatorFactoryClass()); + classVisitor.accept(getSorterClass()); + classVisitor.accept(getProbabilityWeightFactoryClass()); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/MoveSelectorConfig.java b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/MoveSelectorConfig.java index cc3a0cae656..332c073abf4 100644 --- a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/MoveSelectorConfig.java +++ b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/MoveSelectorConfig.java @@ -77,19 +77,19 @@ public abstract class MoveSelectorConfig filterClass = null; + protected String filterClass = null; @Nullable - protected Class comparatorClass = null; + protected String comparatorClass = null; @Nullable - protected Class comparatorFactoryClass = null; + protected String comparatorFactoryClass = null; @Nullable protected SelectionSorterOrder sorterOrder = null; @Nullable - protected Class sorterClass = null; + protected String sorterClass = null; @Nullable - protected Class probabilityWeightFactoryClass = null; + protected String probabilityWeightFactoryClass = null; @Nullable protected Long selectedCountLimit = null; @@ -118,27 +118,27 @@ public void setSelectionOrder(@Nullable SelectionOrder selectionOrder) { } public @Nullable Class getFilterClass() { - return filterClass; + return ConfigUtils.resolveClass(filterClass, "filterClass", this); } public void setFilterClass(@Nullable Class filterClass) { - this.filterClass = filterClass; + this.filterClass = filterClass == null ? null : filterClass.getName(); } public @Nullable Class getComparatorClass() { - return comparatorClass; + return ConfigUtils.resolveClass(comparatorClass, "comparatorClass", this); } public void setComparatorClass(@Nullable Class comparatorClass) { - this.comparatorClass = comparatorClass; + this.comparatorClass = comparatorClass == null ? null : comparatorClass.getName(); } public @Nullable Class getComparatorFactoryClass() { - return comparatorFactoryClass; + return ConfigUtils.resolveClass(comparatorFactoryClass, "comparatorFactoryClass", this); } public void setComparatorFactoryClass(@Nullable Class comparatorFactoryClass) { - this.comparatorFactoryClass = comparatorFactoryClass; + this.comparatorFactoryClass = comparatorFactoryClass == null ? null : comparatorFactoryClass.getName(); } public @Nullable SelectionSorterOrder getSorterOrder() { @@ -150,20 +150,21 @@ public void setSorterOrder(@Nullable SelectionSorterOrder sorterOrder) { } public @Nullable Class getSorterClass() { - return sorterClass; + return ConfigUtils.resolveClass(sorterClass, "sorterClass", this); } public void setSorterClass(@Nullable Class sorterClass) { - this.sorterClass = sorterClass; + this.sorterClass = sorterClass == null ? null : sorterClass.getName(); } public @Nullable Class getProbabilityWeightFactoryClass() { - return probabilityWeightFactoryClass; + return ConfigUtils.resolveClass(probabilityWeightFactoryClass, "probabilityWeightFactoryClass", this); } public void setProbabilityWeightFactoryClass( @Nullable Class probabilityWeightFactoryClass) { - this.probabilityWeightFactoryClass = probabilityWeightFactoryClass; + this.probabilityWeightFactoryClass = probabilityWeightFactoryClass == null ? null + : probabilityWeightFactoryClass.getName(); } public @Nullable Long getSelectedCountLimit() { @@ -197,18 +198,18 @@ public Config_ withSelectionOrder(SelectionOrder selectionOrder) { } public Config_ withFilterClass(Class filterClass) { - this.filterClass = filterClass; + this.filterClass = filterClass.getName(); return (Config_) this; } public Config_ withComparatorClass(Class comparatorClass) { - this.setComparatorClass(comparatorClass); + this.comparatorClass = comparatorClass.getName(); return (Config_) this; } public Config_ withComparatorFactoryClass(Class comparatorFactoryClass) { - this.setComparatorFactoryClass(comparatorFactoryClass); + this.comparatorFactoryClass = comparatorFactoryClass.getName(); return (Config_) this; } @@ -218,13 +219,13 @@ public Config_ withSorterOrder(SelectionSorterOrder sorterOrder) { } public Config_ withSorterClass(Class sorterClass) { - this.sorterClass = sorterClass; + this.sorterClass = sorterClass.getName(); return (Config_) this; } public Config_ withProbabilityWeightFactoryClass( Class probabilityWeightFactoryClass) { - this.probabilityWeightFactoryClass = probabilityWeightFactoryClass; + this.probabilityWeightFactoryClass = probabilityWeightFactoryClass.getName(); return (Config_) this; } @@ -261,27 +262,24 @@ public void inheritFolded(MoveSelectorConfig foldedConfig) { } protected void visitCommonReferencedClasses(Consumer> classVisitor) { - classVisitor.accept(filterClass); - classVisitor.accept(comparatorClass); - classVisitor.accept(comparatorFactoryClass); - classVisitor.accept(sorterClass); - classVisitor.accept(probabilityWeightFactoryClass); + classVisitor.accept(getFilterClass()); + classVisitor.accept(getComparatorClass()); + classVisitor.accept(getComparatorFactoryClass()); + classVisitor.accept(getSorterClass()); + classVisitor.accept(getProbabilityWeightFactoryClass()); } private void inheritCommon(MoveSelectorConfig inheritedConfig) { cacheType = ConfigUtils.inheritOverwritableProperty(cacheType, inheritedConfig.getCacheType()); selectionOrder = ConfigUtils.inheritOverwritableProperty(selectionOrder, inheritedConfig.getSelectionOrder()); - filterClass = ConfigUtils.inheritOverwritableProperty(filterClass, inheritedConfig.getFilterClass()); - comparatorClass = ConfigUtils.inheritOverwritableProperty( - comparatorClass, inheritedConfig.getComparatorClass()); + filterClass = ConfigUtils.inheritOverwritableProperty(filterClass, inheritedConfig.filterClass); + comparatorClass = ConfigUtils.inheritOverwritableProperty(comparatorClass, inheritedConfig.comparatorClass); comparatorFactoryClass = ConfigUtils.inheritOverwritableProperty( - comparatorFactoryClass, inheritedConfig.getComparatorFactoryClass()); - sorterOrder = ConfigUtils.inheritOverwritableProperty( - sorterOrder, inheritedConfig.getSorterOrder()); - sorterClass = ConfigUtils.inheritOverwritableProperty( - sorterClass, inheritedConfig.getSorterClass()); + comparatorFactoryClass, inheritedConfig.comparatorFactoryClass); + sorterOrder = ConfigUtils.inheritOverwritableProperty(sorterOrder, inheritedConfig.getSorterOrder()); + sorterClass = ConfigUtils.inheritOverwritableProperty(sorterClass, inheritedConfig.sorterClass); probabilityWeightFactoryClass = ConfigUtils.inheritOverwritableProperty( - probabilityWeightFactoryClass, inheritedConfig.getProbabilityWeightFactoryClass()); + probabilityWeightFactoryClass, inheritedConfig.probabilityWeightFactoryClass); selectedCountLimit = ConfigUtils.inheritOverwritableProperty( selectedCountLimit, inheritedConfig.getSelectedCountLimit()); diff --git a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/composite/UnionMoveSelectorConfig.java b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/composite/UnionMoveSelectorConfig.java index c3cfba4b5c6..7d76c53baed 100644 --- a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/composite/UnionMoveSelectorConfig.java +++ b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/composite/UnionMoveSelectorConfig.java @@ -71,7 +71,7 @@ public final class UnionMoveSelectorConfig }) private List moveSelectorConfigList = null; - private Class selectorProbabilityWeightFactoryClass = null; + private String selectorProbabilityWeightFactoryClass = null; // ************************************************************************ // Constructors and simple getters/setters @@ -93,12 +93,13 @@ public void setMoveSelectorList(@Nullable List<@NonNull MoveSelectorConfig> move } public @Nullable Class getSelectorProbabilityWeightFactoryClass() { - return selectorProbabilityWeightFactoryClass; + return ConfigUtils.resolveClass(selectorProbabilityWeightFactoryClass, "selectorProbabilityWeightFactoryClass", this); } public void setSelectorProbabilityWeightFactoryClass( @Nullable Class selectorProbabilityWeightFactoryClass) { - this.selectorProbabilityWeightFactoryClass = selectorProbabilityWeightFactoryClass; + this.selectorProbabilityWeightFactoryClass = selectorProbabilityWeightFactoryClass == null ? null + : selectorProbabilityWeightFactoryClass.getName(); } // ************************************************************************ @@ -118,7 +119,7 @@ public void setSelectorProbabilityWeightFactoryClass( public @NonNull UnionMoveSelectorConfig withSelectorProbabilityWeightFactoryClass( @NonNull Class selectorProbabilityWeightFactoryClass) { - this.selectorProbabilityWeightFactoryClass = selectorProbabilityWeightFactoryClass; + this.selectorProbabilityWeightFactoryClass = selectorProbabilityWeightFactoryClass.getName(); return this; } @@ -139,7 +140,7 @@ public void extractLeafMoveSelectorConfigsIntoList(@NonNull List<@NonNull MoveSe moveSelectorConfigList = ConfigUtils.inheritMergeableListConfig(moveSelectorConfigList, inheritedConfig.getMoveSelectorList()); selectorProbabilityWeightFactoryClass = ConfigUtils.inheritOverwritableProperty( - selectorProbabilityWeightFactoryClass, inheritedConfig.getSelectorProbabilityWeightFactoryClass()); + selectorProbabilityWeightFactoryClass, inheritedConfig.selectorProbabilityWeightFactoryClass); return this; } @@ -154,7 +155,7 @@ public void visitReferencedClasses(@NonNull Consumer> classVisitor) { if (moveSelectorConfigList != null) { moveSelectorConfigList.forEach(ms -> ms.visitReferencedClasses(classVisitor)); } - classVisitor.accept(selectorProbabilityWeightFactoryClass); + classVisitor.accept(getSelectorProbabilityWeightFactoryClass()); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/factory/MoveIteratorFactoryConfig.java b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/factory/MoveIteratorFactoryConfig.java index 20466934232..633f9fcc377 100644 --- a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/factory/MoveIteratorFactoryConfig.java +++ b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/factory/MoveIteratorFactoryConfig.java @@ -22,18 +22,18 @@ public final class MoveIteratorFactoryConfig extends MoveSelectorConfig moveIteratorFactoryClass = null; + private String moveIteratorFactoryClass = null; @XmlJavaTypeAdapter(JaxbCustomPropertiesAdapter.class) @Nullable private Map moveIteratorFactoryCustomProperties = null; public @Nullable Class getMoveIteratorFactoryClass() { - return moveIteratorFactoryClass; + return ConfigUtils.resolveClass(moveIteratorFactoryClass, "moveIteratorFactoryClass", this); } public void setMoveIteratorFactoryClass(@Nullable Class moveIteratorFactoryClass) { - this.moveIteratorFactoryClass = moveIteratorFactoryClass; + this.moveIteratorFactoryClass = moveIteratorFactoryClass == null ? null : moveIteratorFactoryClass.getName(); } public @Nullable Map getMoveIteratorFactoryCustomProperties() { @@ -50,7 +50,7 @@ public void setMoveIteratorFactoryCustomProperties(@Nullable Map public @NonNull MoveIteratorFactoryConfig withMoveIteratorFactoryClass(@NonNull Class moveIteratorFactoryClass) { - this.setMoveIteratorFactoryClass(moveIteratorFactoryClass); + this.moveIteratorFactoryClass = moveIteratorFactoryClass.getName(); return this; } @@ -64,7 +64,7 @@ public void setMoveIteratorFactoryCustomProperties(@Nullable Map public @NonNull MoveIteratorFactoryConfig inherit(@NonNull MoveIteratorFactoryConfig inheritedConfig) { super.inherit(inheritedConfig); moveIteratorFactoryClass = ConfigUtils.inheritOverwritableProperty( - moveIteratorFactoryClass, inheritedConfig.getMoveIteratorFactoryClass()); + moveIteratorFactoryClass, inheritedConfig.moveIteratorFactoryClass); moveIteratorFactoryCustomProperties = ConfigUtils.inheritMergeableMapProperty( moveIteratorFactoryCustomProperties, inheritedConfig.getMoveIteratorFactoryCustomProperties()); return this; @@ -78,7 +78,7 @@ public void setMoveIteratorFactoryCustomProperties(@Nullable Map @Override public void visitReferencedClasses(@NonNull Consumer> classVisitor) { visitCommonReferencedClasses(classVisitor); - classVisitor.accept(moveIteratorFactoryClass); + classVisitor.accept(getMoveIteratorFactoryClass()); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/factory/MoveListFactoryConfig.java b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/factory/MoveListFactoryConfig.java index 8f1973dc367..63246477ee1 100644 --- a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/factory/MoveListFactoryConfig.java +++ b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/factory/MoveListFactoryConfig.java @@ -22,17 +22,17 @@ public final class MoveListFactoryConfig extends MoveSelectorConfig moveListFactoryClass = null; + private String moveListFactoryClass = null; @XmlJavaTypeAdapter(JaxbCustomPropertiesAdapter.class) private Map moveListFactoryCustomProperties = null; public @Nullable Class getMoveListFactoryClass() { - return moveListFactoryClass; + return ConfigUtils.resolveClass(moveListFactoryClass, "moveListFactoryClass", this); } public void setMoveListFactoryClass(@Nullable Class moveListFactoryClass) { - this.moveListFactoryClass = moveListFactoryClass; + this.moveListFactoryClass = moveListFactoryClass == null ? null : moveListFactoryClass.getName(); } public @Nullable Map getMoveListFactoryCustomProperties() { @@ -49,7 +49,7 @@ public void setMoveListFactoryCustomProperties(@Nullable Map mov public @NonNull MoveListFactoryConfig withMoveListFactoryClass(@NonNull Class moveListFactoryClass) { - this.setMoveListFactoryClass(moveListFactoryClass); + this.moveListFactoryClass = moveListFactoryClass.getName(); return this; } @@ -67,7 +67,7 @@ public void setMoveListFactoryCustomProperties(@Nullable Map mov public @NonNull MoveListFactoryConfig inherit(@NonNull MoveListFactoryConfig inheritedConfig) { super.inherit(inheritedConfig); moveListFactoryClass = ConfigUtils.inheritOverwritableProperty( - moveListFactoryClass, inheritedConfig.getMoveListFactoryClass()); + moveListFactoryClass, inheritedConfig.moveListFactoryClass); moveListFactoryCustomProperties = ConfigUtils.inheritMergeableMapProperty( moveListFactoryCustomProperties, inheritedConfig.getMoveListFactoryCustomProperties()); return this; @@ -81,7 +81,7 @@ public void setMoveListFactoryCustomProperties(@Nullable Map mov @Override public void visitReferencedClasses(@NonNull Consumer> classVisitor) { visitCommonReferencedClasses(classVisitor); - classVisitor.accept(moveListFactoryClass); + classVisitor.accept(getMoveListFactoryClass()); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/generic/AbstractPillarMoveSelectorConfig.java b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/generic/AbstractPillarMoveSelectorConfig.java index 335ccd72b0d..1e7fdfd7fef 100644 --- a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/generic/AbstractPillarMoveSelectorConfig.java +++ b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/generic/AbstractPillarMoveSelectorConfig.java @@ -22,7 +22,7 @@ public abstract class AbstractPillarMoveSelectorConfig { protected SubPillarType subPillarType = null; - protected Class subPillarSequenceComparatorClass = null; + protected String subPillarSequenceComparatorClass = null; @XmlElement(name = "pillarSelector") protected PillarSelectorConfig pillarSelectorConfig = null; @@ -35,12 +35,13 @@ public void setSubPillarType(final @Nullable SubPillarType subPillarType) { } public @Nullable Class getSubPillarSequenceComparatorClass() { - return subPillarSequenceComparatorClass; + return ConfigUtils.resolveClass(subPillarSequenceComparatorClass, "subPillarSequenceComparatorClass", this); } public void setSubPillarSequenceComparatorClass(final @Nullable Class subPillarSequenceComparatorClass) { - this.subPillarSequenceComparatorClass = subPillarSequenceComparatorClass; + this.subPillarSequenceComparatorClass = + subPillarSequenceComparatorClass == null ? null : subPillarSequenceComparatorClass.getName(); } public @Nullable PillarSelectorConfig getPillarSelectorConfig() { @@ -62,7 +63,7 @@ public void setPillarSelectorConfig(@Nullable PillarSelectorConfig pillarSelecto public @NonNull Config_ withSubPillarSequenceComparatorClass(@NonNull Class subPillarSequenceComparatorClass) { - this.setSubPillarSequenceComparatorClass(subPillarSequenceComparatorClass); + this.subPillarSequenceComparatorClass = subPillarSequenceComparatorClass.getName(); return (Config_) this; } @@ -76,7 +77,7 @@ public void setPillarSelectorConfig(@Nullable PillarSelectorConfig pillarSelecto super.inherit(inheritedConfig); subPillarType = ConfigUtils.inheritOverwritableProperty(subPillarType, inheritedConfig.getSubPillarType()); subPillarSequenceComparatorClass = ConfigUtils.inheritOverwritableProperty(subPillarSequenceComparatorClass, - inheritedConfig.getSubPillarSequenceComparatorClass()); + inheritedConfig.subPillarSequenceComparatorClass); pillarSelectorConfig = ConfigUtils.inheritConfig(pillarSelectorConfig, inheritedConfig.getPillarSelectorConfig()); return (Config_) this; } @@ -84,7 +85,7 @@ public void setPillarSelectorConfig(@Nullable PillarSelectorConfig pillarSelecto @Override protected void visitCommonReferencedClasses(@NonNull Consumer> classVisitor) { super.visitCommonReferencedClasses(classVisitor); - classVisitor.accept(subPillarSequenceComparatorClass); + classVisitor.accept(getSubPillarSequenceComparatorClass()); if (pillarSelectorConfig != null) { pillarSelectorConfig.visitReferencedClasses(classVisitor); } diff --git a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/generic/MultistageMoveSelectorConfig.java b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/generic/MultistageMoveSelectorConfig.java index 150281fb821..9f2129437af 100644 --- a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/generic/MultistageMoveSelectorConfig.java +++ b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/generic/MultistageMoveSelectorConfig.java @@ -8,6 +8,7 @@ import ai.timefold.solver.core.config.util.ConfigUtils; import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; @XmlType(propOrder = { "stageProviderClass", @@ -17,30 +18,29 @@ public final class MultistageMoveSelectorConfig extends MoveSelectorConfig { public static final String XML_ELEMENT_NAME = "multistageMoveSelector"; - private Class stageProviderClass; + private String stageProviderClass; - private Class entityClass = null; + private String entityClass = null; private String variableName = null; // ************************** // Getters/Setters // ************************** - public Class getStageProviderClass() { - return stageProviderClass; + public @Nullable Class getStageProviderClass() { + return ConfigUtils.resolveClass(stageProviderClass, "stageProviderClass", this); } - public void setStageProviderClass( - Class stageProviderClass) { - this.stageProviderClass = stageProviderClass; + public void setStageProviderClass(Class stageProviderClass) { + this.stageProviderClass = stageProviderClass == null ? null : stageProviderClass.getName(); } - public Class getEntityClass() { - return entityClass; + public @Nullable Class getEntityClass() { + return ConfigUtils.resolveClass(entityClass, "entityClass", this); } public void setEntityClass(Class entityClass) { - this.entityClass = entityClass; + this.entityClass = entityClass == null ? null : entityClass.getName(); } public String getVariableName() { @@ -57,12 +57,12 @@ public void setVariableName(String variableName) { public @NonNull MultistageMoveSelectorConfig withStageProviderClass( @NonNull Class stageProviderClass) { - this.setStageProviderClass(stageProviderClass); + this.stageProviderClass = stageProviderClass.getName(); return this; } public @NonNull MultistageMoveSelectorConfig withEntityClass(@NonNull Class entityClass) { - this.setEntityClass(entityClass); + this.entityClass = entityClass.getName(); return this; } @@ -87,7 +87,7 @@ public boolean hasNearbySelectionConfig() { @Override public void visitReferencedClasses(@NonNull Consumer> classVisitor) { - classVisitor.accept(stageProviderClass); + classVisitor.accept(getStageProviderClass()); } @Override @@ -96,9 +96,9 @@ public void visitReferencedClasses(@NonNull Consumer> classVisitor) { super.inherit(inheritedConfig); stageProviderClass = ConfigUtils.inheritOverwritableProperty(stageProviderClass, - inheritedConfig.getStageProviderClass()); + inheritedConfig.stageProviderClass); entityClass = - ConfigUtils.inheritOverwritableProperty(entityClass, inheritedConfig.getEntityClass()); + ConfigUtils.inheritOverwritableProperty(entityClass, inheritedConfig.entityClass); variableName = ConfigUtils.inheritOverwritableProperty(variableName, inheritedConfig.getVariableName()); return this; diff --git a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/generic/list/ListMultistageMoveSelectorConfig.java b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/generic/list/ListMultistageMoveSelectorConfig.java index d6f1e61545a..11fe5837ebb 100644 --- a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/generic/list/ListMultistageMoveSelectorConfig.java +++ b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/generic/list/ListMultistageMoveSelectorConfig.java @@ -8,6 +8,7 @@ import ai.timefold.solver.core.config.util.ConfigUtils; import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.Nullable; @XmlType(propOrder = { "stageProviderClass" @@ -15,19 +16,18 @@ public final class ListMultistageMoveSelectorConfig extends MoveSelectorConfig { public static final String XML_ELEMENT_NAME = "listMultistageMoveSelector"; - private Class stageProviderClass; + private String stageProviderClass; // ************************** // Getters/Setters // ************************** - public Class getStageProviderClass() { - return stageProviderClass; + public @Nullable Class getStageProviderClass() { + return ConfigUtils.resolveClass(stageProviderClass, "stageProviderClass", this); } - public void setStageProviderClass( - Class stageProviderClass) { - this.stageProviderClass = stageProviderClass; + public void setStageProviderClass(Class stageProviderClass) { + this.stageProviderClass = stageProviderClass == null ? null : stageProviderClass.getName(); } // ************************** @@ -36,7 +36,7 @@ public void setStageProviderClass( public @NonNull ListMultistageMoveSelectorConfig withStageProviderClass( @NonNull Class stageProviderClass) { - this.setStageProviderClass(stageProviderClass); + this.stageProviderClass = stageProviderClass.getName(); return this; } @@ -56,7 +56,7 @@ public boolean hasNearbySelectionConfig() { @Override public void visitReferencedClasses(@NonNull Consumer> classVisitor) { - classVisitor.accept(stageProviderClass); + classVisitor.accept(getStageProviderClass()); } @Override @@ -65,7 +65,7 @@ public void visitReferencedClasses(@NonNull Consumer> classVisitor) { super.inherit(inheritedConfig); stageProviderClass = ConfigUtils.inheritOverwritableProperty(stageProviderClass, - inheritedConfig.getStageProviderClass()); + inheritedConfig.stageProviderClass); return this; } } diff --git a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/value/ValueSelectorConfig.java b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/value/ValueSelectorConfig.java index 7bca8979033..72893962dd7 100644 --- a/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/value/ValueSelectorConfig.java +++ b/core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/value/ValueSelectorConfig.java @@ -51,7 +51,7 @@ public final class ValueSelectorConfig extends SelectorConfig downcastEntityClass = null; + private String downcastEntityClass = null; @XmlAttribute @Nullable private String variableName = null; @@ -66,21 +66,21 @@ public final class ValueSelectorConfig extends SelectorConfig filterClass = null; + private String filterClass = null; @Nullable private ValueSorterManner sorterManner = null; @Nullable - private Class comparatorClass = null; + private String comparatorClass = null; @Nullable - private Class comparatorFactoryClass = null; + private String comparatorFactoryClass = null; @Nullable private SelectionSorterOrder sorterOrder = null; @Nullable - private Class sorterClass = null; + private String sorterClass = null; @Nullable - private Class probabilityWeightFactoryClass = null; + private String probabilityWeightFactoryClass = null; @Nullable private Long selectedCountLimit = null; @@ -115,11 +115,11 @@ public void setMimicSelectorRef(@Nullable String mimicSelectorRef) { } public @Nullable Class getDowncastEntityClass() { - return downcastEntityClass; + return ConfigUtils.resolveClass(downcastEntityClass, "downcastEntityClass", this); } public void setDowncastEntityClass(@Nullable Class downcastEntityClass) { - this.downcastEntityClass = downcastEntityClass; + this.downcastEntityClass = downcastEntityClass == null ? null : downcastEntityClass.getName(); } public @Nullable String getVariableName() { @@ -155,11 +155,11 @@ public void setNearbySelectionConfig(@Nullable NearbySelectionConfig nearbySelec } public @Nullable Class getFilterClass() { - return filterClass; + return ConfigUtils.resolveClass(filterClass, "filterClass", this); } public void setFilterClass(@Nullable Class filterClass) { - this.filterClass = filterClass; + this.filterClass = filterClass == null ? null : filterClass.getName(); } public @Nullable ValueSorterManner getSorterManner() { @@ -171,19 +171,19 @@ public void setSorterManner(@Nullable ValueSorterManner sorterManner) { } public @Nullable Class getComparatorClass() { - return comparatorClass; + return ConfigUtils.resolveClass(comparatorClass, "comparatorClass", this); } public void setComparatorClass(@Nullable Class comparatorClass) { - this.comparatorClass = comparatorClass; + this.comparatorClass = comparatorClass == null ? null : comparatorClass.getName(); } public @Nullable Class getComparatorFactoryClass() { - return comparatorFactoryClass; + return ConfigUtils.resolveClass(comparatorFactoryClass, "comparatorFactoryClass", this); } public void setComparatorFactoryClass(@Nullable Class comparatorFactoryClass) { - this.comparatorFactoryClass = comparatorFactoryClass; + this.comparatorFactoryClass = comparatorFactoryClass == null ? null : comparatorFactoryClass.getName(); } public @Nullable SelectionSorterOrder getSorterOrder() { @@ -195,20 +195,21 @@ public void setSorterOrder(@Nullable SelectionSorterOrder sorterOrder) { } public @Nullable Class getSorterClass() { - return sorterClass; + return ConfigUtils.resolveClass(sorterClass, "sorterClass", this); } public void setSorterClass(@Nullable Class sorterClass) { - this.sorterClass = sorterClass; + this.sorterClass = sorterClass == null ? null : sorterClass.getName(); } public @Nullable Class getProbabilityWeightFactoryClass() { - return probabilityWeightFactoryClass; + return ConfigUtils.resolveClass(probabilityWeightFactoryClass, "probabilityWeightFactoryClass", this); } public void setProbabilityWeightFactoryClass( @Nullable Class probabilityWeightFactoryClass) { - this.probabilityWeightFactoryClass = probabilityWeightFactoryClass; + this.probabilityWeightFactoryClass = + probabilityWeightFactoryClass == null ? null : probabilityWeightFactoryClass.getName(); } public @Nullable Long getSelectedCountLimit() { @@ -234,7 +235,7 @@ public ValueSelectorConfig withMimicSelectorRef(String mimicSelectorRef) { } public ValueSelectorConfig withDowncastEntityClass(Class entityClass) { - this.setDowncastEntityClass(entityClass); + this.downcastEntityClass = entityClass.getName(); return this; } @@ -259,7 +260,7 @@ public ValueSelectorConfig withNearbySelectionConfig(NearbySelectionConfig nearb } public ValueSelectorConfig withFilterClass(Class filterClass) { - this.setFilterClass(filterClass); + this.filterClass = filterClass.getName(); return this; } @@ -269,13 +270,12 @@ public ValueSelectorConfig withSorterManner(ValueSorterManner sorterManner) { } public ValueSelectorConfig withComparatorClass(Class comparatorClass) { - this.setComparatorClass(comparatorClass); + this.comparatorClass = comparatorClass.getName(); return this; } - public ValueSelectorConfig - withComparatorFactoryClass(Class comparatorFactoryClass) { - this.setComparatorFactoryClass(comparatorFactoryClass); + public ValueSelectorConfig withComparatorFactoryClass(Class comparatorFactoryClass) { + this.comparatorFactoryClass = comparatorFactoryClass.getName(); return this; } @@ -285,13 +285,13 @@ public ValueSelectorConfig withSorterOrder(SelectionSorterOrder sorterOrder) { } public ValueSelectorConfig withSorterClass(Class sorterClass) { - this.setSorterClass(sorterClass); + this.sorterClass = sorterClass.getName(); return this; } public ValueSelectorConfig withProbabilityWeightFactoryClass(Class factoryClass) { - this.setProbabilityWeightFactoryClass(factoryClass); + this.probabilityWeightFactoryClass = factoryClass.getName(); return this; } @@ -310,24 +310,24 @@ public ValueSelectorConfig inherit(ValueSelectorConfig inheritedConfig) { mimicSelectorRef = ConfigUtils.inheritOverwritableProperty(mimicSelectorRef, inheritedConfig.getMimicSelectorRef()); downcastEntityClass = ConfigUtils.inheritOverwritableProperty(downcastEntityClass, - inheritedConfig.getDowncastEntityClass()); + inheritedConfig.downcastEntityClass); variableName = ConfigUtils.inheritOverwritableProperty(variableName, inheritedConfig.getVariableName()); nearbySelectionConfig = ConfigUtils.inheritConfig(nearbySelectionConfig, inheritedConfig.getNearbySelectionConfig()); - filterClass = ConfigUtils.inheritOverwritableProperty(filterClass, inheritedConfig.getFilterClass()); + filterClass = ConfigUtils.inheritOverwritableProperty(filterClass, inheritedConfig.filterClass); cacheType = ConfigUtils.inheritOverwritableProperty(cacheType, inheritedConfig.getCacheType()); selectionOrder = ConfigUtils.inheritOverwritableProperty(selectionOrder, inheritedConfig.getSelectionOrder()); sorterManner = ConfigUtils.inheritOverwritableProperty( sorterManner, inheritedConfig.getSorterManner()); comparatorClass = ConfigUtils.inheritOverwritableProperty( - comparatorClass, inheritedConfig.getComparatorClass()); + comparatorClass, inheritedConfig.comparatorClass); comparatorFactoryClass = ConfigUtils.inheritOverwritableProperty( - comparatorFactoryClass, inheritedConfig.getComparatorFactoryClass()); + comparatorFactoryClass, inheritedConfig.comparatorFactoryClass); sorterOrder = ConfigUtils.inheritOverwritableProperty( sorterOrder, inheritedConfig.getSorterOrder()); sorterClass = ConfigUtils.inheritOverwritableProperty( - sorterClass, inheritedConfig.getSorterClass()); + sorterClass, inheritedConfig.sorterClass); probabilityWeightFactoryClass = ConfigUtils.inheritOverwritableProperty( - probabilityWeightFactoryClass, inheritedConfig.getProbabilityWeightFactoryClass()); + probabilityWeightFactoryClass, inheritedConfig.probabilityWeightFactoryClass); selectedCountLimit = ConfigUtils.inheritOverwritableProperty( selectedCountLimit, inheritedConfig.getSelectedCountLimit()); return this; @@ -340,15 +340,15 @@ public ValueSelectorConfig copyConfig() { @Override public void visitReferencedClasses(Consumer> classVisitor) { - classVisitor.accept(downcastEntityClass); + classVisitor.accept(getDowncastEntityClass()); if (nearbySelectionConfig != null) { nearbySelectionConfig.visitReferencedClasses(classVisitor); } - classVisitor.accept(filterClass); - classVisitor.accept(comparatorClass); - classVisitor.accept(comparatorFactoryClass); - classVisitor.accept(sorterClass); - classVisitor.accept(probabilityWeightFactoryClass); + classVisitor.accept(getFilterClass()); + classVisitor.accept(getComparatorClass()); + classVisitor.accept(getComparatorFactoryClass()); + classVisitor.accept(getSorterClass()); + classVisitor.accept(getProbabilityWeightFactoryClass()); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/config/localsearch/LocalSearchPhaseConfig.java b/core/src/main/java/ai/timefold/solver/core/config/localsearch/LocalSearchPhaseConfig.java index 5e1aea0440d..1dcad0c1371 100644 --- a/core/src/main/java/ai/timefold/solver/core/config/localsearch/LocalSearchPhaseConfig.java +++ b/core/src/main/java/ai/timefold/solver/core/config/localsearch/LocalSearchPhaseConfig.java @@ -74,7 +74,7 @@ public final class LocalSearchPhaseConfig extends PhaseConfig neighborhoodProviderClass = null; + private String neighborhoodProviderClass = null; @XmlElement(name = "acceptor") private LocalSearchAcceptorConfig acceptorConfig = null; @XmlElement(name = "forager") @@ -110,7 +110,7 @@ public void setMoveSelectorConfig(@Nullable MoveSelectorConfig moveSelectorConfi */ @SuppressWarnings("unchecked") public @Nullable Class> getNeighborhoodProviderClass() { - return (Class>) neighborhoodProviderClass; + return ConfigUtils.resolveClass(neighborhoodProviderClass, "neighborhoodProviderClass", this); } /** @@ -118,7 +118,7 @@ public void setMoveSelectorConfig(@Nullable MoveSelectorConfig moveSelectorConfi */ @SuppressWarnings("rawtypes") public void setNeighborhoodProviderClass(@Nullable Class neighborhoodProviderClass) { - this.neighborhoodProviderClass = neighborhoodProviderClass; + this.neighborhoodProviderClass = neighborhoodProviderClass == null ? null : neighborhoodProviderClass.getName(); } public @Nullable LocalSearchAcceptorConfig getAcceptorConfig() { @@ -156,7 +156,7 @@ public void setForagerConfig(@Nullable LocalSearchForagerConfig foragerConfig) { */ public @NonNull LocalSearchPhaseConfig withMoveProviderClass(@NonNull Class> moveProviderClass) { - this.neighborhoodProviderClass = moveProviderClass; + this.neighborhoodProviderClass = moveProviderClass.getName(); return this; } @@ -177,8 +177,8 @@ public void setForagerConfig(@Nullable LocalSearchForagerConfig foragerConfig) { inheritedConfig.getLocalSearchType()); setMoveSelectorConfig(ConfigUtils.inheritOverwritableProperty( getMoveSelectorConfig(), inheritedConfig.getMoveSelectorConfig())); - setNeighborhoodProviderClass(ConfigUtils.inheritOverwritableProperty(getNeighborhoodProviderClass(), - inheritedConfig.getNeighborhoodProviderClass())); + neighborhoodProviderClass = ConfigUtils.inheritOverwritableProperty(neighborhoodProviderClass, + inheritedConfig.neighborhoodProviderClass); acceptorConfig = ConfigUtils.inheritConfig(acceptorConfig, inheritedConfig.getAcceptorConfig()); foragerConfig = ConfigUtils.inheritConfig(foragerConfig, inheritedConfig.getForagerConfig()); return this; @@ -198,7 +198,7 @@ public void visitReferencedClasses(@NonNull Consumer> classVisitor) { moveSelectorConfig.visitReferencedClasses(classVisitor); } if (neighborhoodProviderClass != null) { - classVisitor.accept(neighborhoodProviderClass); + classVisitor.accept(getNeighborhoodProviderClass()); } if (acceptorConfig != null) { acceptorConfig.visitReferencedClasses(classVisitor); diff --git a/core/src/main/java/ai/timefold/solver/core/config/partitionedsearch/PartitionedSearchPhaseConfig.java b/core/src/main/java/ai/timefold/solver/core/config/partitionedsearch/PartitionedSearchPhaseConfig.java index 71e70b15d48..6a53bd231a3 100644 --- a/core/src/main/java/ai/timefold/solver/core/config/partitionedsearch/PartitionedSearchPhaseConfig.java +++ b/core/src/main/java/ai/timefold/solver/core/config/partitionedsearch/PartitionedSearchPhaseConfig.java @@ -37,7 +37,7 @@ public final class PartitionedSearchPhaseConfig extends PhaseConfig> solutionPartitionerClass = null; + private String solutionPartitionerClass = null; @XmlJavaTypeAdapter(JaxbCustomPropertiesAdapter.class) private Map solutionPartitionerCustomProperties = null; @@ -58,11 +58,11 @@ public final class PartitionedSearchPhaseConfig extends PhaseConfig> getSolutionPartitionerClass() { - return solutionPartitionerClass; + return ConfigUtils.resolveClass(solutionPartitionerClass, "solutionPartitionerClass", this); } public void setSolutionPartitionerClass(@Nullable Class> solutionPartitionerClass) { - this.solutionPartitionerClass = solutionPartitionerClass; + this.solutionPartitionerClass = solutionPartitionerClass == null ? null : solutionPartitionerClass.getName(); } public @Nullable Map getSolutionPartitionerCustomProperties() { @@ -119,7 +119,7 @@ public void setPhaseConfigList(@Nullable List<@NonNull PhaseConfig> phaseConfigL public @NonNull PartitionedSearchPhaseConfig withSolutionPartitionerClass( @NonNull Class> solutionPartitionerClass) { - this.setSolutionPartitionerClass(solutionPartitionerClass); + this.solutionPartitionerClass = solutionPartitionerClass.getName(); return this; } @@ -148,7 +148,7 @@ public void setPhaseConfigList(@Nullable List<@NonNull PhaseConfig> phaseConfigL public @NonNull PartitionedSearchPhaseConfig inherit(@NonNull PartitionedSearchPhaseConfig inheritedConfig) { super.inherit(inheritedConfig); solutionPartitionerClass = ConfigUtils.inheritOverwritableProperty(solutionPartitionerClass, - inheritedConfig.getSolutionPartitionerClass()); + inheritedConfig.solutionPartitionerClass); solutionPartitionerCustomProperties = ConfigUtils.inheritMergeableMapProperty( solutionPartitionerCustomProperties, inheritedConfig.getSolutionPartitionerCustomProperties()); runnablePartThreadLimit = ConfigUtils.inheritOverwritableProperty(runnablePartThreadLimit, @@ -168,7 +168,7 @@ public void visitReferencedClasses(@NonNull Consumer> classVisitor) { if (terminationConfig != null) { terminationConfig.visitReferencedClasses(classVisitor); } - classVisitor.accept(solutionPartitionerClass); + classVisitor.accept(getSolutionPartitionerClass()); if (phaseConfigList != null) { phaseConfigList.forEach(pc -> pc.visitReferencedClasses(classVisitor)); } diff --git a/core/src/main/java/ai/timefold/solver/core/config/phase/custom/CustomPhaseConfig.java b/core/src/main/java/ai/timefold/solver/core/config/phase/custom/CustomPhaseConfig.java index 0b2062fbd2b..e9ba02129d6 100644 --- a/core/src/main/java/ai/timefold/solver/core/config/phase/custom/CustomPhaseConfig.java +++ b/core/src/main/java/ai/timefold/solver/core/config/phase/custom/CustomPhaseConfig.java @@ -1,7 +1,6 @@ package ai.timefold.solver.core.config.phase.custom; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; @@ -34,7 +33,7 @@ public final class CustomPhaseConfig extends PhaseConfig { @XmlElement(name = "customPhaseCommandClass") @Nullable - private List> customPhaseCommandClassList = null; + private List customPhaseCommandClassList = null; @XmlJavaTypeAdapter(JaxbCustomPropertiesAdapter.class) @Nullable @@ -49,11 +48,15 @@ public final class CustomPhaseConfig extends PhaseConfig { // ************************************************************************ public @Nullable List> getCustomPhaseCommandClassList() { - return customPhaseCommandClassList; + if (customPhaseCommandClassList == null) { + return null; + } + return ConfigUtils.resolveClasses(customPhaseCommandClassList, "customPhaseCommandClass", this); } public void setCustomPhaseCommandClassList(@Nullable List> customPhaseCommandClassList) { - this.customPhaseCommandClassList = customPhaseCommandClassList; + this.customPhaseCommandClassList = customPhaseCommandClassList == null ? null + : customPhaseCommandClassList.stream().map(Class::getName).toList(); } public @Nullable Map getCustomProperties() { @@ -77,7 +80,7 @@ public void setCustomPhaseCommandList(@Nullable List cus // ************************************************************************ public CustomPhaseConfig withCustomPhaseCommandClassList(List> customPhaseCommandClassList) { - this.customPhaseCommandClassList = customPhaseCommandClassList; + this.customPhaseCommandClassList = customPhaseCommandClassList.stream().map(Class::getName).toList(); return this; } @@ -87,11 +90,10 @@ public CustomPhaseConfig withCustomProperties(Map customProperti } public CustomPhaseConfig withCustomPhaseCommandList(List customPhaseCommandList) { - boolean hasNullCommand = Objects.requireNonNullElse(customPhaseCommandList, Collections.emptyList()) - .stream().anyMatch(Objects::isNull); + var hasNullCommand = customPhaseCommandList.stream().anyMatch(Objects::isNull); if (hasNullCommand) { - throw new IllegalArgumentException( - "Custom phase commands (" + customPhaseCommandList + ") must not contain a null element."); + throw new IllegalArgumentException("Custom phase commands (%s) must not contain a null element." + .formatted(customPhaseCommandList)); } this.customPhaseCommandList = List.copyOf(customPhaseCommandList); return this; @@ -106,7 +108,7 @@ public CustomPhaseConfig withCustomPhaseCommands(PhaseCommand> classVisitor) { terminationConfig.visitReferencedClasses(classVisitor); } if (customPhaseCommandClassList != null) { - customPhaseCommandClassList.forEach(classVisitor); + getCustomPhaseCommandClassList().forEach(classVisitor); } } diff --git a/core/src/main/java/ai/timefold/solver/core/config/score/director/ScoreDirectorFactoryConfig.java b/core/src/main/java/ai/timefold/solver/core/config/score/director/ScoreDirectorFactoryConfig.java index 1fcb443c2ec..8d897b4e638 100644 --- a/core/src/main/java/ai/timefold/solver/core/config/score/director/ScoreDirectorFactoryConfig.java +++ b/core/src/main/java/ai/timefold/solver/core/config/score/director/ScoreDirectorFactoryConfig.java @@ -31,12 +31,12 @@ }) public final class ScoreDirectorFactoryConfig extends AbstractConfig { - private Class easyScoreCalculatorClass = null; + private String easyScoreCalculatorClass = null; @XmlJavaTypeAdapter(JaxbCustomPropertiesAdapter.class) private Map easyScoreCalculatorCustomProperties = null; - private Class constraintProviderClass = null; + private String constraintProviderClass = null; @XmlJavaTypeAdapter(JaxbCustomPropertiesAdapter.class) private Map constraintProviderCustomProperties = null; @@ -44,7 +44,7 @@ public final class ScoreDirectorFactoryConfig extends AbstractConfig incrementalScoreCalculatorClass = null; + private String incrementalScoreCalculatorClass = null; @XmlJavaTypeAdapter(JaxbCustomPropertiesAdapter.class) private Map incrementalScoreCalculatorCustomProperties = null; @@ -60,11 +60,11 @@ public final class ScoreDirectorFactoryConfig extends AbstractConfig getEasyScoreCalculatorClass() { - return easyScoreCalculatorClass; + return ConfigUtils.resolveClass(easyScoreCalculatorClass, "easyScoreCalculatorClass", this); } public void setEasyScoreCalculatorClass(@Nullable Class easyScoreCalculatorClass) { - this.easyScoreCalculatorClass = easyScoreCalculatorClass; + this.easyScoreCalculatorClass = easyScoreCalculatorClass == null ? null : easyScoreCalculatorClass.getName(); } public @Nullable Map<@NonNull String, @NonNull String> getEasyScoreCalculatorCustomProperties() { @@ -77,11 +77,11 @@ public void setEasyScoreCalculatorCustomProperties( } public @Nullable Class getConstraintProviderClass() { - return constraintProviderClass; + return ConfigUtils.resolveClass(constraintProviderClass, "constraintProviderClass", this); } public void setConstraintProviderClass(@Nullable Class constraintProviderClass) { - this.constraintProviderClass = constraintProviderClass; + this.constraintProviderClass = constraintProviderClass == null ? null : constraintProviderClass.getName(); } public @Nullable Map<@NonNull String, @NonNull String> getConstraintProviderCustomProperties() { @@ -111,12 +111,13 @@ public void setConstraintStreamProfilingEnabled(Boolean constraintStreamProfilin } public @Nullable Class getIncrementalScoreCalculatorClass() { - return incrementalScoreCalculatorClass; + return ConfigUtils.resolveClass(incrementalScoreCalculatorClass, "incrementalScoreCalculatorClass", this); } public void setIncrementalScoreCalculatorClass( @Nullable Class incrementalScoreCalculatorClass) { - this.incrementalScoreCalculatorClass = incrementalScoreCalculatorClass; + this.incrementalScoreCalculatorClass = + incrementalScoreCalculatorClass == null ? null : incrementalScoreCalculatorClass.getName(); } public @Nullable Map<@NonNull String, @NonNull String> getIncrementalScoreCalculatorCustomProperties() { @@ -150,7 +151,7 @@ public void setAssertionScoreDirectorFactory(@Nullable ScoreDirectorFactoryConfi public @NonNull ScoreDirectorFactoryConfig withEasyScoreCalculatorClass(@NonNull Class easyScoreCalculatorClass) { - this.easyScoreCalculatorClass = easyScoreCalculatorClass; + this.easyScoreCalculatorClass = easyScoreCalculatorClass.getName(); return this; } @@ -163,7 +164,7 @@ public void setAssertionScoreDirectorFactory(@Nullable ScoreDirectorFactoryConfi public @NonNull ScoreDirectorFactoryConfig withConstraintProviderClass(@NonNull Class constraintProviderClass) { - this.constraintProviderClass = constraintProviderClass; + this.constraintProviderClass = constraintProviderClass.getName(); return this; } @@ -189,7 +190,7 @@ public void setAssertionScoreDirectorFactory(@Nullable ScoreDirectorFactoryConfi public @NonNull ScoreDirectorFactoryConfig withIncrementalScoreCalculatorClass( @NonNull Class incrementalScoreCalculatorClass) { - this.incrementalScoreCalculatorClass = incrementalScoreCalculatorClass; + this.incrementalScoreCalculatorClass = incrementalScoreCalculatorClass.getName(); return this; } @@ -214,11 +215,11 @@ public void setAssertionScoreDirectorFactory(@Nullable ScoreDirectorFactoryConfi @Override public @NonNull ScoreDirectorFactoryConfig inherit(@NonNull ScoreDirectorFactoryConfig inheritedConfig) { easyScoreCalculatorClass = ConfigUtils.inheritOverwritableProperty( - easyScoreCalculatorClass, inheritedConfig.getEasyScoreCalculatorClass()); + easyScoreCalculatorClass, inheritedConfig.easyScoreCalculatorClass); easyScoreCalculatorCustomProperties = ConfigUtils.inheritMergeableMapProperty( easyScoreCalculatorCustomProperties, inheritedConfig.getEasyScoreCalculatorCustomProperties()); constraintProviderClass = ConfigUtils.inheritOverwritableProperty( - constraintProviderClass, inheritedConfig.getConstraintProviderClass()); + constraintProviderClass, inheritedConfig.constraintProviderClass); constraintProviderCustomProperties = ConfigUtils.inheritMergeableMapProperty( constraintProviderCustomProperties, inheritedConfig.getConstraintProviderCustomProperties()); constraintStreamAutomaticNodeSharing = ConfigUtils.inheritOverwritableProperty(constraintStreamAutomaticNodeSharing, @@ -226,7 +227,7 @@ public void setAssertionScoreDirectorFactory(@Nullable ScoreDirectorFactoryConfi constraintStreamProfilingEnabled = ConfigUtils.inheritOverwritableProperty(constraintStreamProfilingEnabled, inheritedConfig.getConstraintStreamProfilingEnabled()); incrementalScoreCalculatorClass = ConfigUtils.inheritOverwritableProperty( - incrementalScoreCalculatorClass, inheritedConfig.getIncrementalScoreCalculatorClass()); + incrementalScoreCalculatorClass, inheritedConfig.incrementalScoreCalculatorClass); incrementalScoreCalculatorCustomProperties = ConfigUtils.inheritMergeableMapProperty( incrementalScoreCalculatorCustomProperties, inheritedConfig.getIncrementalScoreCalculatorCustomProperties()); initializingScoreTrend = ConfigUtils.inheritOverwritableProperty( @@ -243,9 +244,9 @@ public void setAssertionScoreDirectorFactory(@Nullable ScoreDirectorFactoryConfi @Override public void visitReferencedClasses(@NonNull Consumer> classVisitor) { - classVisitor.accept(easyScoreCalculatorClass); - classVisitor.accept(constraintProviderClass); - classVisitor.accept(incrementalScoreCalculatorClass); + classVisitor.accept(getEasyScoreCalculatorClass()); + classVisitor.accept(getConstraintProviderClass()); + classVisitor.accept(getIncrementalScoreCalculatorClass()); if (assertionScoreDirectorFactory != null) { assertionScoreDirectorFactory.visitReferencedClasses(classVisitor); } diff --git a/core/src/main/java/ai/timefold/solver/core/config/solver/SolverConfig.java b/core/src/main/java/ai/timefold/solver/core/config/solver/SolverConfig.java index cef89d74d48..ed43fb1bceb 100644 --- a/core/src/main/java/ai/timefold/solver/core/config/solver/SolverConfig.java +++ b/core/src/main/java/ai/timefold/solver/core/config/solver/SolverConfig.java @@ -19,6 +19,7 @@ import java.util.Set; import java.util.concurrent.ThreadFactory; import java.util.function.Consumer; +import java.util.stream.Collectors; import jakarta.xml.bind.annotation.XmlElement; import jakarta.xml.bind.annotation.XmlElements; @@ -215,12 +216,12 @@ public final class SolverConfig extends AbstractConfig { private Long randomSeed = null; private String moveThreadCount = null; private Integer moveThreadBufferSize = null; - private Class threadFactoryClass = null; + private String threadFactoryClass = null; - private Class solutionClass = null; + private String solutionClass = null; @XmlElement(name = "entityClass") - private List> entityClassList = null; + private List entityClassList = null; @XmlTransient private Map gizmoMemberAccessorMap = null; @XmlTransient @@ -232,7 +233,7 @@ public final class SolverConfig extends AbstractConfig { @XmlElement(name = "termination") private TerminationConfig terminationConfig; - private Class> nearbyDistanceMeterClass = null; + private String nearbyDistanceMeterClass = null; @XmlElements({ @XmlElement(name = ConstructionHeuristicPhaseConfig.XML_ELEMENT_NAME, @@ -364,27 +365,31 @@ public void setMoveThreadBufferSize(@Nullable Integer moveThreadBufferSize) { } public @Nullable Class getThreadFactoryClass() { - return threadFactoryClass; + return ConfigUtils.resolveClass(threadFactoryClass, "threadFactoryClass", this); } public void setThreadFactoryClass(@Nullable Class threadFactoryClass) { - this.threadFactoryClass = threadFactoryClass; + this.threadFactoryClass = threadFactoryClass == null ? null : threadFactoryClass.getName(); } public @Nullable Class getSolutionClass() { - return solutionClass; + return ConfigUtils.resolveClass(solutionClass, "solutionClass", this); } public void setSolutionClass(@Nullable Class solutionClass) { - this.solutionClass = solutionClass; + this.solutionClass = solutionClass == null ? null : solutionClass.getName(); } public @Nullable List> getEntityClassList() { - return entityClassList; + if (entityClassList == null) { + return null; + } + return ConfigUtils.resolveClasses(entityClassList, "entityClass", this); } public void setEntityClassList(@Nullable List> entityClassList) { - this.entityClassList = entityClassList; + this.entityClassList = entityClassList == null ? null + : entityClassList.stream().map(Class::getName).collect(Collectors.toList()); } public @Nullable Map<@NonNull String, @NonNull MemberAccessor> getGizmoMemberAccessorMap() { @@ -420,11 +425,11 @@ public void setTerminationConfig(@Nullable TerminationConfig terminationConfig) } public @Nullable Class> getNearbyDistanceMeterClass() { - return nearbyDistanceMeterClass; + return ConfigUtils.resolveClass(nearbyDistanceMeterClass, "nearbyDistanceMeterClass", this); } public void setNearbyDistanceMeterClass(@Nullable Class> nearbyDistanceMeterClass) { - this.nearbyDistanceMeterClass = nearbyDistanceMeterClass; + this.nearbyDistanceMeterClass = nearbyDistanceMeterClass == null ? null : nearbyDistanceMeterClass.getName(); } public @Nullable List<@NonNull PhaseConfig> getPhaseConfigList() { @@ -478,22 +483,22 @@ public void setMonitoringConfig(@Nullable MonitoringConfig monitoringConfig) { } public @NonNull SolverConfig withThreadFactoryClass(@NonNull Class threadFactoryClass) { - this.threadFactoryClass = threadFactoryClass; + this.threadFactoryClass = threadFactoryClass.getName(); return this; } public @NonNull SolverConfig withSolutionClass(@NonNull Class solutionClass) { - this.solutionClass = solutionClass; + this.solutionClass = solutionClass.getName(); return this; } public @NonNull SolverConfig withEntityClassList(@NonNull List> entityClassList) { - this.entityClassList = entityClassList; + this.entityClassList = entityClassList.stream().map(Class::getName).collect(Collectors.toList()); return this; } public @NonNull SolverConfig withEntityClasses(@NonNull Class... entityClasses) { - this.entityClassList = Arrays.asList(entityClasses); + this.entityClassList = Arrays.stream(entityClasses).map(Class::getName).collect(Collectors.toList()); return this; } @@ -576,7 +581,7 @@ public void setMonitoringConfig(@Nullable MonitoringConfig monitoringConfig) { public @NonNull SolverConfig withNearbyDistanceMeterClass(@NonNull Class> distanceMeterClass) { - this.nearbyDistanceMeterClass = distanceMeterClass; + this.nearbyDistanceMeterClass = distanceMeterClass.getName(); return this; } @@ -656,10 +661,10 @@ public void offerRandomSeedFromSubSingleIndex(long subSingleIndex) { moveThreadBufferSize = ConfigUtils.inheritOverwritableProperty(moveThreadBufferSize, inheritedConfig.getMoveThreadBufferSize()); threadFactoryClass = ConfigUtils.inheritOverwritableProperty(threadFactoryClass, - inheritedConfig.getThreadFactoryClass()); - solutionClass = ConfigUtils.inheritOverwritableProperty(solutionClass, inheritedConfig.getSolutionClass()); + inheritedConfig.threadFactoryClass); + solutionClass = ConfigUtils.inheritOverwritableProperty(solutionClass, inheritedConfig.solutionClass); entityClassList = ConfigUtils.inheritMergeableListProperty(entityClassList, - inheritedConfig.getEntityClassList()); + inheritedConfig.entityClassList); gizmoMemberAccessorMap = ConfigUtils.inheritMergeableMapProperty( gizmoMemberAccessorMap, inheritedConfig.getGizmoMemberAccessorMap()); gizmoSolutionClonerMap = ConfigUtils.inheritMergeableMapProperty( @@ -669,7 +674,7 @@ public void offerRandomSeedFromSubSingleIndex(long subSingleIndex) { inheritedConfig.getScoreDirectorFactoryConfig()); terminationConfig = ConfigUtils.inheritConfig(terminationConfig, inheritedConfig.getTerminationConfig()); nearbyDistanceMeterClass = ConfigUtils.inheritOverwritableProperty(nearbyDistanceMeterClass, - inheritedConfig.getNearbyDistanceMeterClass()); + inheritedConfig.nearbyDistanceMeterClass); phaseConfigList = ConfigUtils.inheritMergeableListConfig(phaseConfigList, inheritedConfig.getPhaseConfigList()); monitoringConfig = ConfigUtils.inheritConfig(monitoringConfig, inheritedConfig.getMonitoringConfig()); return this; @@ -682,16 +687,16 @@ public void offerRandomSeedFromSubSingleIndex(long subSingleIndex) { @Override public void visitReferencedClasses(@NonNull Consumer> classVisitor) { - classVisitor.accept(threadFactoryClass); - classVisitor.accept(solutionClass); + classVisitor.accept(getThreadFactoryClass()); + classVisitor.accept(getSolutionClass()); if (entityClassList != null) { - entityClassList.forEach(classVisitor); + getEntityClassList().forEach(classVisitor); } if (scoreDirectorFactoryConfig != null) { scoreDirectorFactoryConfig.visitReferencedClasses(classVisitor); } if (nearbyDistanceMeterClass != null) { - classVisitor.accept(nearbyDistanceMeterClass); + classVisitor.accept(getNearbyDistanceMeterClass()); } if (terminationConfig != null) { terminationConfig.visitReferencedClasses(classVisitor); diff --git a/core/src/main/java/ai/timefold/solver/core/config/solver/SolverManagerConfig.java b/core/src/main/java/ai/timefold/solver/core/config/solver/SolverManagerConfig.java index bb90c94ead3..56fbd61fa84 100644 --- a/core/src/main/java/ai/timefold/solver/core/config/solver/SolverManagerConfig.java +++ b/core/src/main/java/ai/timefold/solver/core/config/solver/SolverManagerConfig.java @@ -24,7 +24,7 @@ public final class SolverManagerConfig extends AbstractConfig threadFactoryClass = null; + private String threadFactoryClass = null; // Future features: // throttlingDelay @@ -46,11 +46,11 @@ public void setParallelSolverCount(@Nullable String parallelSolverCount) { } public @Nullable Class getThreadFactoryClass() { - return threadFactoryClass; + return ConfigUtils.resolveClass(threadFactoryClass, "threadFactoryClass", this); } public void setThreadFactoryClass(@Nullable Class threadFactoryClass) { - this.threadFactoryClass = threadFactoryClass; + this.threadFactoryClass = threadFactoryClass == null ? null : threadFactoryClass.getName(); } // ************************************************************************ @@ -63,7 +63,7 @@ public void setThreadFactoryClass(@Nullable Class threa } public @NonNull SolverManagerConfig withThreadFactoryClass(@NonNull Class threadFactoryClass) { - this.threadFactoryClass = threadFactoryClass; + this.threadFactoryClass = threadFactoryClass.getName(); return this; } @@ -109,7 +109,7 @@ private static int resolveParallelSolverCountAutomatically(int availableProcesso parallelSolverCount = ConfigUtils.inheritOverwritableProperty(parallelSolverCount, inheritedConfig.getParallelSolverCount()); threadFactoryClass = ConfigUtils.inheritOverwritableProperty(threadFactoryClass, - inheritedConfig.getThreadFactoryClass()); + inheritedConfig.threadFactoryClass); return this; } @@ -120,7 +120,7 @@ private static int resolveParallelSolverCountAutomatically(int availableProcesso @Override public void visitReferencedClasses(@NonNull Consumer> classVisitor) { - classVisitor.accept(threadFactoryClass); + classVisitor.accept(getThreadFactoryClass()); } } diff --git a/core/src/main/java/ai/timefold/solver/core/config/util/ConfigUtils.java b/core/src/main/java/ai/timefold/solver/core/config/util/ConfigUtils.java index 0b542e33ebf..f0773b0c32a 100644 --- a/core/src/main/java/ai/timefold/solver/core/config/util/ConfigUtils.java +++ b/core/src/main/java/ai/timefold/solver/core/config/util/ConfigUtils.java @@ -45,6 +45,39 @@ public class ConfigUtils { private static final AlphabeticMemberComparator alphabeticMemberComparator = new AlphabeticMemberComparator(); + @SuppressWarnings("unchecked") + public static @Nullable Class resolveClass(@Nullable String className, @NonNull String fieldName, + @NonNull Object context) { + if (className == null) { + return null; + } + var trimmedClassName = className.strip(); + if (trimmedClassName.isEmpty()) { + return null; + } + var classloader = Objects.requireNonNullElse(Thread.currentThread().getContextClassLoader(), + ConfigUtils.class.getClassLoader()); + try { + return (Class) Class.forName(trimmedClassName, false, classloader); + } catch (ClassNotFoundException e) { + throw new IllegalArgumentException( + "The %s (%s) of %s cannot be found.".formatted(fieldName, trimmedClassName, context), e); + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static List> resolveClasses(List<@Nullable String> classList, @NonNull String fieldName, + @NonNull Object context) { + return (List) classList.stream() + .map(cn -> ConfigUtils.resolveClass(cn, fieldName, context)) + .peek(clz -> { + if (clz == null) { + throw new IllegalArgumentException( + "The %s of %s cannot be null or empty.".formatted(fieldName, context)); + } + }).toList(); + } + /** * Create a new instance of clazz from a config's property. *

diff --git a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/BiRandomMoveIterator.java b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/BiRandomMoveIterator.java index 2144b5ef14d..85d00e2cabc 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/BiRandomMoveIterator.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/BiRandomMoveIterator.java @@ -1,7 +1,9 @@ package ai.timefold.solver.core.impl.neighborhood.stream; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; +import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.random.RandomGenerator; @@ -60,18 +62,23 @@ final class BiRandomMoveIterator implements Iterator context; private final RandomGenerator workingRandom; + /** + * We cannot cache the right iterator on the left tuple, + * because that cache would survive across steps and the right iterator would be invalid by then. + * The alternative would be worse than this map, + * likely requiring some loop over tuples at step end, clearing the cache. + */ + private final Map, Iterator>> leftTupleToRightIteratorMap = new HashMap<>(); // Fields required for iteration. private final Iterator> leftTupleIterator; - private final int rightIteratorStoreIndex; private @Nullable Move nextMove; public BiRandomMoveIterator(BiMoveStreamContext context, RandomGenerator workingRandom) { this.context = Objects.requireNonNull(context); this.workingRandom = Objects.requireNonNull(workingRandom); - var leftDatasetInstance = context.getLeftDatasetInstance(); - this.rightIteratorStoreIndex = leftDatasetInstance.getRightIteratorStoreIndex(); - this.leftTupleIterator = leftDatasetInstance.randomIterator(workingRandom); + this.leftTupleIterator = context.getLeftDatasetInstance() + .randomIterator(workingRandom); } @Override @@ -82,10 +89,9 @@ public boolean hasNext() { while (leftTupleIterator.hasNext()) { var leftTuple = leftTupleIterator.next(); - var rightEmpty = pickNextMove(leftTuple); - if (rightEmpty) { + if (!pickNextMove(leftTuple)) { leftTupleIterator.remove(); - leftTuple.setStore(rightIteratorStoreIndex, null); + leftTupleToRightIteratorMap.remove(leftTuple); } if (nextMove != null) { if (nextMove instanceof AbstractSelectorBasedMove legacyMove) { @@ -101,17 +107,20 @@ Please refactor your code (%s) to use the new Move API.""" } private boolean pickNextMove(UniTuple leftTuple) { - var rightTupleIterator = (Iterator>) leftTuple.getStore(rightIteratorStoreIndex); + var rightTupleIterator = leftTupleToRightIteratorMap.get(leftTuple); if (rightTupleIterator == null) { rightTupleIterator = createRightTupleIterator(leftTuple); - leftTuple.setStore(rightIteratorStoreIndex, rightTupleIterator); + if (!rightTupleIterator.hasNext()) { + return false; + } + leftTupleToRightIteratorMap.put(leftTuple, rightTupleIterator); } if (!rightTupleIterator.hasNext()) { - return true; + return false; } nextMove = context.buildMove(leftTuple.getA(), rightTupleIterator.next().getA()); rightTupleIterator.remove(); - return false; + return true; } private Iterator> createRightTupleIterator(UniTuple leftTuple) { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/AbstractLeftDataset.java b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/AbstractLeftDataset.java index c96bbebbb9e..c1d28919f4c 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/AbstractLeftDataset.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/AbstractLeftDataset.java @@ -12,7 +12,6 @@ protected AbstractLeftDataset(AbstractUniEnumeratingStream parent) super(parent); } - public abstract AbstractLeftDatasetInstance> instantiate(int rightSequenceStoreIndex, - int entryStoreIndex); + public abstract AbstractLeftDatasetInstance> instantiate(int entryStoreIndex); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/AbstractLeftDatasetInstance.java b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/AbstractLeftDatasetInstance.java index 0c32c5967b6..3005eb611fb 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/AbstractLeftDatasetInstance.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/AbstractLeftDatasetInstance.java @@ -15,15 +15,9 @@ public abstract class AbstractLeftDatasetInstance { private final ElementAwareArrayList tupleList = new ElementAwareArrayList<>(); - private final int rightIteratorStoreIndex; - protected AbstractLeftDatasetInstance(AbstractDataset parent, int rightIteratorStoreIndex, int entryStoreIndex) { + protected AbstractLeftDatasetInstance(AbstractDataset parent, int entryStoreIndex) { super(parent, entryStoreIndex); - this.rightIteratorStoreIndex = rightIteratorStoreIndex; - } - - public int getRightIteratorStoreIndex() { - return rightIteratorStoreIndex; } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/uni/LeftTerminalUniEnumeratingStream.java b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/uni/LeftTerminalUniEnumeratingStream.java index 042d46ab4d5..ba9a24935e4 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/uni/LeftTerminalUniEnumeratingStream.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/uni/LeftTerminalUniEnumeratingStream.java @@ -22,9 +22,7 @@ public LeftTerminalUniEnumeratingStream(EnumeratingStreamFactory enum @Override public void buildNode(DataNodeBuildHelper buildHelper) { assertEmptyChildStreamList(); - var datasetInstance = dataset.instantiate( - buildHelper.reserveTupleStoreIndex(parent.getTupleSource()), - buildHelper.reserveTupleStoreIndex(parent.getTupleSource())); + var datasetInstance = dataset.instantiate(buildHelper.reserveTupleStoreIndex(parent.getTupleSource())); buildHelper.putInsertUpdateRetract(this, datasetInstance); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/uni/UniLeftDataset.java b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/uni/UniLeftDataset.java index fc5fa00ad7c..dc86e802fb2 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/uni/UniLeftDataset.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/uni/UniLeftDataset.java @@ -14,8 +14,8 @@ public UniLeftDataset(AbstractUniEnumeratingStream parent) { } @Override - public UniLeftDatasetInstance instantiate(int rightIteratorStoreIndex, int entryStoreIndex) { - return new UniLeftDatasetInstance<>(this, rightIteratorStoreIndex, entryStoreIndex); + public UniLeftDatasetInstance instantiate(int entryStoreIndex) { + return new UniLeftDatasetInstance<>(this, entryStoreIndex); } @Override diff --git a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/uni/UniLeftDatasetInstance.java b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/uni/UniLeftDatasetInstance.java index 1d28040edbe..b11e75b5420 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/uni/UniLeftDatasetInstance.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/uni/UniLeftDatasetInstance.java @@ -10,8 +10,8 @@ public final class UniLeftDatasetInstance extends AbstractLeftDatasetInstance> { - public UniLeftDatasetInstance(AbstractDataset parent, int rightIteratorStoreIndex, int entryStoreIndex) { - super(parent, rightIteratorStoreIndex, entryStoreIndex); + public UniLeftDatasetInstance(AbstractDataset parent, int entryStoreIndex) { + super(parent, entryStoreIndex); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/test/AbstractMultiConstraintAssertion.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/test/AbstractMultiConstraintAssertion.java index e5a816a319f..ac674a6fba0 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/test/AbstractMultiConstraintAssertion.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/test/AbstractMultiConstraintAssertion.java @@ -59,7 +59,7 @@ public void scores(@NonNull Score score, String message) { @Override @SuppressWarnings("unchecked") - public > S score() { + public > S getScore() { ensureInitialized(); return (S) actualScore.raw(); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/test/AbstractSingleConstraintAssertion.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/test/AbstractSingleConstraintAssertion.java index 794a455d055..0f31c2a34ea 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/test/AbstractSingleConstraintAssertion.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/test/AbstractSingleConstraintAssertion.java @@ -254,13 +254,13 @@ public void rewardsWithLessThan(@Nullable String message, @NonNull BigDecimal ma @Override @SuppressWarnings("unchecked") - public > S score() { + public > S getScore() { ensureInitialized(); return (S) actualScore.raw(); } @Override - public Number impact() { + public Number getImpact() { ensureInitialized(); return deduceImpact().key(); } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/test/MultiConstraintAssertionTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/test/MultiConstraintAssertionTest.java index b1dbe2dfcea..0fa5e0fe112 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/test/MultiConstraintAssertionTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/test/MultiConstraintAssertionTest.java @@ -71,7 +71,7 @@ void checksScore() { } @Test - void scoreReturnsTypedScoreWithGivenFacts() { + void getScoreReturnsTypedScoreWithGivenFacts() { var constraintVerifier = ConstraintVerifier.build(new TestdataConstraintVerifierConstraintProvider(), TestdataConstraintVerifierExtendedSolution.class, TestdataConstraintVerifierFirstEntity.class, @@ -81,7 +81,7 @@ void scoreReturnsTypedScoreWithGivenFacts() { HardSoftScore score = constraintVerifier .verifyThat() .given(entity) - .score(); + .getScore(); assertThat(score).isNotNull(); assertThat(score).isInstanceOf(HardSoftScore.class); @@ -91,7 +91,7 @@ void scoreReturnsTypedScoreWithGivenFacts() { } @Test - void scoreEnablesRelativeComparisonWithGivenFacts() { + void getScoreEnablesRelativeComparisonWithGivenFacts() { var constraintVerifier = ConstraintVerifier.build(new TestdataConstraintVerifierConstraintProvider(), TestdataConstraintVerifierExtendedSolution.class, TestdataConstraintVerifierFirstEntity.class, @@ -106,11 +106,11 @@ void scoreEnablesRelativeComparisonWithGivenFacts() { HardSoftScore scoreA = constraintVerifier .verifyThat() .given(entityA) - .score(); + .getScore(); HardSoftScore scoreB = constraintVerifier .verifyThat() .given(entityB1, entityB2) - .score(); + .getScore(); assertThat(scoreA).isGreaterThan(scoreB); } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/test/SingleConstraintAssertionTest.java b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/test/SingleConstraintAssertionTest.java index 559b43601d2..888a9090f56 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/score/stream/test/SingleConstraintAssertionTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/score/stream/test/SingleConstraintAssertionTest.java @@ -587,35 +587,35 @@ void impactsByLessThan() { } @Test - void impactEnablesRelativeComparison() { + void getImpactEnablesRelativeComparison() { var entityA = new TestdataConstraintVerifierFirstEntity("A", new TestdataValue()); var solution = TestdataConstraintVerifierSolution.generateSolution(2, 3); - Number impactA = constraintVerifier + var impactA = constraintVerifier .verifyThat(TestdataConstraintVerifierConstraintProvider::penalizeEveryEntity) .given(entityA) - .impact(); - Number impactB = constraintVerifier + .getImpact(); + var impactB = constraintVerifier .verifyThat(TestdataConstraintVerifierConstraintProvider::penalizeEveryEntity) .given(solution.getEntityList().toArray()) - .impact(); + .getImpact(); assertThat(impactB.intValue()).isGreaterThan(impactA.intValue()); } @Test - void scoreEnablesRelativeComparisonForRewards() { + void getScoreEnablesRelativeComparisonForRewards() { var entityA = new TestdataConstraintVerifierFirstEntity("A", new TestdataValue()); var solution = TestdataConstraintVerifierSolution.generateSolution(2, 3); HardSoftScore scoreA = constraintVerifier .verifyThat(TestdataConstraintVerifierConstraintProvider::rewardEveryEntity) .given(entityA) - .score(); + .getScore(); HardSoftScore scoreB = constraintVerifier .verifyThat(TestdataConstraintVerifierConstraintProvider::rewardEveryEntity) .given(solution.getEntityList().toArray()) - .score(); + .getScore(); assertThat(scoreA).isNotNull(); assertThat(scoreA).isInstanceOf(HardSoftScore.class); @@ -631,18 +631,18 @@ void scoreEnablesRelativeComparisonForRewards() { } @Test - void scoreComparesGivenSolutions() { + void getScoreComparesGivenSolutions() { var smallSolution = TestdataConstraintVerifierExtendedSolution.generateSolution(2, 2); var largeSolution = TestdataConstraintVerifierExtendedSolution.generateSolution(2, 4); HardSoftScore smallScore = constraintVerifier .verifyThat(TestdataConstraintVerifierConstraintProvider::penalizeEveryEntity) .givenSolution(smallSolution) - .score(); + .getScore(); HardSoftScore largeScore = constraintVerifier .verifyThat(TestdataConstraintVerifierConstraintProvider::penalizeEveryEntity) .givenSolution(largeSolution) - .score(); + .getScore(); assertThat(smallScore).isGreaterThan(largeScore); } diff --git a/docs/src/modules/ROOT/pages/quickstart/quarkus-vehicle-routing/quarkus-vehicle-routing-quickstart.adoc b/docs/src/modules/ROOT/pages/quickstart/quarkus-vehicle-routing/quarkus-vehicle-routing-quickstart.adoc index 513b1d06505..54bc2c06002 100644 --- a/docs/src/modules/ROOT/pages/quickstart/quarkus-vehicle-routing/quarkus-vehicle-routing-quickstart.adoc +++ b/docs/src/modules/ROOT/pages/quickstart/quarkus-vehicle-routing/quarkus-vehicle-routing-quickstart.adoc @@ -535,7 +535,7 @@ Add some dependencies in your `pom.xml`: ---- io.quarkus - quarkus-junit5 + quarkus-junit test ---- diff --git a/docs/src/modules/ROOT/pages/quickstart/quarkus/quarkus-quickstart.adoc b/docs/src/modules/ROOT/pages/quickstart/quarkus/quarkus-quickstart.adoc index b28a5a31c1a..7f3f9df8dea 100644 --- a/docs/src/modules/ROOT/pages/quickstart/quarkus/quarkus-quickstart.adoc +++ b/docs/src/modules/ROOT/pages/quickstart/quarkus/quarkus-quickstart.adoc @@ -236,7 +236,7 @@ Add the subsequent dependency in your `pom.xml`: ---- io.quarkus - quarkus-junit5 + quarkus-junit test ---- @@ -247,7 +247,7 @@ Gradle:: Add the subsequent dependency to your `build.gradle`: [source,groovy,subs=attributes+] ---- - testImplementation "io.quarkus:quarkus-junit5" + testImplementation "io.quarkus:quarkus-junit" ---- -- ==== diff --git a/quarkus-integration/quarkus-benchmark/deployment/pom.xml b/quarkus-integration/quarkus-benchmark/deployment/pom.xml index c8bc7f9f60b..4917a5e572e 100644 --- a/quarkus-integration/quarkus-benchmark/deployment/pom.xml +++ b/quarkus-integration/quarkus-benchmark/deployment/pom.xml @@ -33,7 +33,7 @@ io.quarkus - quarkus-junit5-internal + quarkus-junit-internal test diff --git a/quarkus-integration/quarkus-benchmark/integration-test/pom.xml b/quarkus-integration/quarkus-benchmark/integration-test/pom.xml index cfb84e7d59d..e0d27325f1e 100644 --- a/quarkus-integration/quarkus-benchmark/integration-test/pom.xml +++ b/quarkus-integration/quarkus-benchmark/integration-test/pom.xml @@ -40,7 +40,7 @@ io.quarkus - quarkus-junit5 + quarkus-junit test diff --git a/quarkus-integration/quarkus-jackson/integration-test/pom.xml b/quarkus-integration/quarkus-jackson/integration-test/pom.xml index d8b4ebef73d..5f37102389b 100644 --- a/quarkus-integration/quarkus-jackson/integration-test/pom.xml +++ b/quarkus-integration/quarkus-jackson/integration-test/pom.xml @@ -44,7 +44,7 @@ io.quarkus - quarkus-junit5 + quarkus-junit test diff --git a/quarkus-integration/quarkus/deployment/pom.xml b/quarkus-integration/quarkus/deployment/pom.xml index d2d867802c4..02711fe73d9 100644 --- a/quarkus-integration/quarkus/deployment/pom.xml +++ b/quarkus-integration/quarkus/deployment/pom.xml @@ -30,7 +30,7 @@ io.quarkus - quarkus-junit5-internal + quarkus-junit-internal test diff --git a/quarkus-integration/quarkus/devui-integration-test/pom.xml b/quarkus-integration/quarkus/devui-integration-test/pom.xml index f732c75ed5b..913c423814e 100644 --- a/quarkus-integration/quarkus/devui-integration-test/pom.xml +++ b/quarkus-integration/quarkus/devui-integration-test/pom.xml @@ -40,7 +40,7 @@ io.quarkus - quarkus-junit5 + quarkus-junit test @@ -50,7 +50,7 @@ io.quarkus - quarkus-junit5-internal + quarkus-junit-internal test diff --git a/quarkus-integration/quarkus/reflection-integration-test/pom.xml b/quarkus-integration/quarkus/reflection-integration-test/pom.xml index 7444fd65692..92601b08297 100644 --- a/quarkus-integration/quarkus/reflection-integration-test/pom.xml +++ b/quarkus-integration/quarkus/reflection-integration-test/pom.xml @@ -36,7 +36,7 @@ io.quarkus - quarkus-junit5 + quarkus-junit test diff --git a/tools/benchmark/src/main/java/ai/timefold/solver/benchmark/config/PlannerBenchmarkConfig.java b/tools/benchmark/src/main/java/ai/timefold/solver/benchmark/config/PlannerBenchmarkConfig.java index 24be1ca01cd..0c1b46558d6 100644 --- a/tools/benchmark/src/main/java/ai/timefold/solver/benchmark/config/PlannerBenchmarkConfig.java +++ b/tools/benchmark/src/main/java/ai/timefold/solver/benchmark/config/PlannerBenchmarkConfig.java @@ -27,6 +27,7 @@ import ai.timefold.solver.benchmark.impl.io.jaxb.PlannerBenchmarkConfigIO; import ai.timefold.solver.benchmark.impl.report.BenchmarkReport; import ai.timefold.solver.core.config.solver.SolverConfig; +import ai.timefold.solver.core.config.util.ConfigUtils; import ai.timefold.solver.core.impl.io.jaxb.TimefoldXmlSerializationException; import org.jspecify.annotations.NonNull; @@ -418,7 +419,7 @@ A classpath resource should not start with a slash (/). A templateResource adher private String name = null; private File benchmarkDirectory = null; - private Class threadFactoryClass = null; + private String threadFactoryClass = null; private String parallelBenchmarkCount = null; private Long warmUpMillisecondsSpentLimit = null; private Long warmUpSecondsSpentLimit = null; @@ -477,11 +478,11 @@ public void setBenchmarkDirectory(@Nullable File benchmarkDirectory) { } public @Nullable Class getThreadFactoryClass() { - return threadFactoryClass; + return ConfigUtils.resolveClass(threadFactoryClass, "threadFactoryClass", this); } public void setThreadFactoryClass(@Nullable Class threadFactoryClass) { - this.threadFactoryClass = threadFactoryClass; + this.threadFactoryClass = threadFactoryClass == null ? null : threadFactoryClass.getName(); } /** @@ -592,7 +593,7 @@ public void setSolverBenchmarkConfigList(@Nullable List<@NonNull SolverBenchmark } public @NonNull PlannerBenchmarkConfig withThreadFactoryClass(@NonNull Class threadFactoryClass) { - this.setThreadFactoryClass(threadFactoryClass); + this.threadFactoryClass = threadFactoryClass.getName(); return this; } diff --git a/tools/benchmark/src/main/java/ai/timefold/solver/benchmark/config/ProblemBenchmarksConfig.java b/tools/benchmark/src/main/java/ai/timefold/solver/benchmark/config/ProblemBenchmarksConfig.java index 9490c236c6e..903a11ba2c0 100644 --- a/tools/benchmark/src/main/java/ai/timefold/solver/benchmark/config/ProblemBenchmarksConfig.java +++ b/tools/benchmark/src/main/java/ai/timefold/solver/benchmark/config/ProblemBenchmarksConfig.java @@ -28,7 +28,7 @@ }) public class ProblemBenchmarksConfig extends AbstractConfig { - private Class> solutionFileIOClass = null; + private String solutionFileIOClass = null; private Boolean writeOutputSolutionEnabled = null; @@ -48,11 +48,11 @@ public class ProblemBenchmarksConfig extends AbstractConfig> getSolutionFileIOClass() { - return solutionFileIOClass; + return ConfigUtils.resolveClass(solutionFileIOClass, "solutionFileIOClass", this); } public void setSolutionFileIOClass(@Nullable Class> solutionFileIOClass) { - this.solutionFileIOClass = solutionFileIOClass; + this.solutionFileIOClass = solutionFileIOClass == null ? null : solutionFileIOClass.getName(); } public @Nullable Boolean getWriteOutputSolutionEnabled() { @@ -101,7 +101,7 @@ public void setSingleStatisticTypeList(@Nullable List<@NonNull SingleStatisticTy public @NonNull ProblemBenchmarksConfig withSolutionFileIOClass(@NonNull Class> solutionFileIOClass) { - this.setSolutionFileIOClass(solutionFileIOClass); + this.solutionFileIOClass = solutionFileIOClass.getName(); return this; } @@ -179,7 +179,7 @@ public void setSingleStatisticTypeList(@Nullable List<@NonNull SingleStatisticTy @Override public @NonNull ProblemBenchmarksConfig inherit(@NonNull ProblemBenchmarksConfig inheritedConfig) { solutionFileIOClass = ConfigUtils.inheritOverwritableProperty(solutionFileIOClass, - inheritedConfig.getSolutionFileIOClass()); + inheritedConfig.solutionFileIOClass); writeOutputSolutionEnabled = ConfigUtils.inheritOverwritableProperty(writeOutputSolutionEnabled, inheritedConfig.getWriteOutputSolutionEnabled()); inputSolutionFileList = ConfigUtils.inheritMergeableListProperty(inputSolutionFileList, @@ -200,7 +200,7 @@ public void setSingleStatisticTypeList(@Nullable List<@NonNull SingleStatisticTy @Override public void visitReferencedClasses(@NonNull Consumer> classVisitor) { - classVisitor.accept(solutionFileIOClass); + classVisitor.accept(getSolutionFileIOClass()); } } diff --git a/tools/benchmark/src/main/java/ai/timefold/solver/benchmark/config/report/BenchmarkReportConfig.java b/tools/benchmark/src/main/java/ai/timefold/solver/benchmark/config/report/BenchmarkReportConfig.java index 6e46cdd5592..76cda618258 100644 --- a/tools/benchmark/src/main/java/ai/timefold/solver/benchmark/config/report/BenchmarkReportConfig.java +++ b/tools/benchmark/src/main/java/ai/timefold/solver/benchmark/config/report/BenchmarkReportConfig.java @@ -28,8 +28,8 @@ public class BenchmarkReportConfig extends AbstractConfig @XmlJavaTypeAdapter(JaxbLocaleAdapter.class) private Locale locale = null; private SolverRankingType solverRankingType = null; - private Class> solverRankingComparatorClass = null; - private Class solverRankingWeightFactoryClass = null; + private String solverRankingComparatorClass = null; + private String solverRankingWeightFactoryClass = null; public BenchmarkReportConfig() { } @@ -55,21 +55,23 @@ public void setSolverRankingType(@Nullable SolverRankingType solverRankingType) } public @Nullable Class> getSolverRankingComparatorClass() { - return solverRankingComparatorClass; + return ConfigUtils.resolveClass(solverRankingComparatorClass, "solverRankingComparatorClass", this); } public void setSolverRankingComparatorClass( @Nullable Class> solverRankingComparatorClass) { - this.solverRankingComparatorClass = solverRankingComparatorClass; + this.solverRankingComparatorClass = solverRankingComparatorClass == null ? null + : solverRankingComparatorClass.getName(); } public @Nullable Class getSolverRankingWeightFactoryClass() { - return solverRankingWeightFactoryClass; + return ConfigUtils.resolveClass(solverRankingWeightFactoryClass, "solverRankingWeightFactoryClass", this); } public void setSolverRankingWeightFactoryClass( @Nullable Class solverRankingWeightFactoryClass) { - this.solverRankingWeightFactoryClass = solverRankingWeightFactoryClass; + this.solverRankingWeightFactoryClass = solverRankingWeightFactoryClass == null ? null + : solverRankingWeightFactoryClass.getName(); } public @Nullable Locale determineLocale() { @@ -92,13 +94,13 @@ public void setSolverRankingWeightFactoryClass( public @NonNull BenchmarkReportConfig withSolverRankingComparatorClass( @NonNull Class> solverRankingComparatorClass) { - this.setSolverRankingComparatorClass(solverRankingComparatorClass); + this.solverRankingComparatorClass = solverRankingComparatorClass.getName(); return this; } public @NonNull BenchmarkReportConfig withSolverRankingWeightFactoryClass( @NonNull Class solverRankingWeightFactoryClass) { - this.setSolverRankingWeightFactoryClass(solverRankingWeightFactoryClass); + this.solverRankingWeightFactoryClass = solverRankingWeightFactoryClass.getName(); return this; } @@ -108,9 +110,9 @@ public void setSolverRankingWeightFactoryClass( solverRankingType = ConfigUtils.inheritOverwritableProperty(solverRankingType, inheritedConfig.getSolverRankingType()); solverRankingComparatorClass = ConfigUtils.inheritOverwritableProperty(solverRankingComparatorClass, - inheritedConfig.getSolverRankingComparatorClass()); + inheritedConfig.solverRankingComparatorClass); solverRankingWeightFactoryClass = ConfigUtils.inheritOverwritableProperty(solverRankingWeightFactoryClass, - inheritedConfig.getSolverRankingWeightFactoryClass()); + inheritedConfig.solverRankingWeightFactoryClass); return this; } @@ -121,8 +123,8 @@ public void setSolverRankingWeightFactoryClass( @Override public void visitReferencedClasses(@NonNull Consumer> classVisitor) { - classVisitor.accept(solverRankingComparatorClass); - classVisitor.accept(solverRankingWeightFactoryClass); + classVisitor.accept(getSolverRankingComparatorClass()); + classVisitor.accept(getSolverRankingWeightFactoryClass()); } }